lib/dolos.rb in dolos-0.2.0 vs lib/dolos.rb in dolos-0.2.1

- old
+ new

@@ -8,72 +8,56 @@ module Dolos include Parsers class Parser - attr_accessor :parser_proc - def initialize(&block) @parser_proc = block end def run(input) run_with_state(ParserState.new(input)) end def run_with_state(state) - result = parser_proc.call(state) - if result.success? - state.last_success_position = state.input.offset - end + result = @parser_proc.call(state) + state.last_success_position = state.input.offset if result.success? result end def capture!(wrap_in = nil) Parser.new do |state| result = run_with_state(state) - if result.success? - result.capture!(wrap_in) - else - result - end + result.success? ? result.capture!(wrap_in) : result end end - # Will call block on captures + # Will call `map` on captures def map_captures(&block) Parser.new do |state| result = run_with_state(state) - if result.success? - Success.new(result.value, result.length, block.call(result.captures)) - else - result - end + result.success? ? Success.new(result.value, result.length, block.call(result.captures)) : result end end # Will call block on tuple of value def map(&block) Parser.new do |state| result = run_with_state(state) - if result.success? - Success.new(block.call(result.value), result.length, result.captures) - else - result - end + result.success? ? Success.new(block.call(result.value), result.length, result.captures) : result end end def combine(&block) Parser.new do |state| result = run_with_state(state) + if result.success? + state.input.advance(result.length) new_parser = block.call(result.value, result.captures) - new_state = state.dup - new_state.input.advance(result.length) - new_parser.run_with_state(new_state) + new_parser.run_with_state(state) else result end end end @@ -138,14 +122,13 @@ def repeat(n_min:, n_max: Float::INFINITY, separator: nil) Parser.new do |state| values = [] captures = [] count = 0 - state.input.mark_offset loop do - result = run_with_state(state.dup) + result = run_with_state(state) # Removing .dup for performance. Be cautious of side effects. if result.failure? || count >= n_max break end @@ -153,30 +136,28 @@ captures.concat(result.captures) state.input.advance(result.length) count += 1 if separator && count < n_max - sep_result = separator.run_with_state(state.dup) + sep_result = separator.run_with_state(state) # Removing .dup for performance. Be cautious of side effects. break if sep_result.failure? state.input.advance(sep_result.length) end end if count < n_min - error_pos = state.input.offset Failure.new( - "Expected parser to match at least #{n_min} times but matched only #{count} times", - error_pos, + -> { "Expected parser to match at least #{n_min} times but matched only #{count} times" }, + state.input.offset, state ) else Success.new(values, 0, captures) end end end - def zero_or_more repeat(n_min: 0, n_max: Float::INFINITY) end alias_method :rep0, :zero_or_more @@ -199,24 +180,17 @@ end end end alias_method :opt, :optional - # Unstable API # Used to declare lazy parser to avoid infinite loops in recursive parsers def lazy parser_memo = nil Parser.new do |state| parser_memo ||= self parser_memo.run_with_state(state) end - end - - private - - def combine_and_discard_empty(*arrays) - arrays.compact.reject { |arr| arr.is_a?(Array) && arr.empty? } end end end