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