def attempt_match
    matches_before = matches.length
    match_length_before = match_length
    (yield && match_length > match_length_before).tap do |success|  # match_length test returns failure if no progress is made (our source position isn't advanced)
      unless success
        @matches = matches[0..matches_before-1]
        update_match_length
      end
    end
  end
def attempt_match
    matches_before = matches.length
    match_length_before = match_length
    (yield && match_length > match_length_before).tap do |success|  # match_length test returns failure if no progress is made (our source position isn't advanced)
      unless success
        @matches = matches[0..matches_before-1]
        update_match_length
      end
    end
  end
a simple "transaction" - logs the curent number of matches,
 if the block's result is false, it discards all new matches