lib/dolos.rb in dolos-0.2.1 vs lib/dolos.rb in dolos-0.3.0
- old
+ new
@@ -13,43 +13,57 @@
attr_accessor :parser_proc
def initialize(&block)
@parser_proc = block
end
+ # Run the parser with the given input
+ # Returns a Result<Success|Failure>
+ # string("hello").run("hello") => Success.new("hello", 5)
def run(input)
run_with_state(ParserState.new(input))
end
+
def run_with_state(state)
result = @parser_proc.call(state)
state.last_success_position = state.input.offset if result.success?
result
end
+ # Capture the result of the parser
+ # p = string("hello").capture!
+ # p.run("hello").captures => ["hello"]
+ # Captures is a flat array of all captured values
def capture!(wrap_in = nil)
Parser.new do |state|
result = run_with_state(state)
result.success? ? result.capture!(wrap_in) : result
end
end
- # Will call `map` on captures
+ # Map the captures of the parser
+ # p = string("hello").map_captures { |captures| captures.map(&:upcase) }
+ # p.run("hello") => Success.new("hello", 5, ["HELLO"])
+ # This only maps over captures, not the value
def map_captures(&block)
Parser.new do |state|
result = run_with_state(state)
result.success? ? Success.new(result.value, result.length, block.call(result.captures)) : result
end
end
- # Will call block on tuple of value
+ # Map the result of the parser
+ # p = string("hello").map { |s| s.upcase }
+ # p.run("hello") => Success.new("HELLO", 5)
def map(&block)
Parser.new do |state|
result = run_with_state(state)
result.success? ? Success.new(block.call(result.value), result.length, result.captures) : result
end
end
+ # Combine the result of the parser with another parser
def combine(&block)
Parser.new do |state|
result = run_with_state(state)
if result.success?
@@ -60,16 +74,14 @@
result
end
end
end
- def flatten
- map_captures do |captures|
- captures.flatten
- end
- end
-
+ # Combine the result of the parser with another parser
+ # Has an alias of `&`
+ # p = string("hello") & string("world")
+ # p.run("helloworld") => Success.new(["hello", "world"], 10)
def product(other_parser)
combine do |value1, capture1|
other_parser.map do |value2|
[value1, value2]
end.map_captures do |capture2|
@@ -77,20 +89,27 @@
end
end
end
alias_method :&, :product
+
+ # Combine the result of the parser with another parser
+ # Discards the result of the second parser
+ # p = string("hello") << string("world")
def product_l(other_parser)
combine do |value1, capture1|
other_parser.map do |_|
value1
end.map_captures do |capture2|
[capture1, capture2].flatten
end
end
end
+ # Combine the result of the parser with another parser
+ # Discards the result of the first parser
+ # p = string("hello") >> string("world")
def product_r(other_parser)
combine do |_, capture1|
other_parser.map do |value2|
value2
end.map_captures do |capture2|
@@ -100,10 +119,14 @@
end
alias_method :<<, :product_l
alias_method :>>, :product_r
+ # Combine the result of the parser with another parser
+ # If the first parser fails, it will try the second parser
+ # p = string("hello") | string("world") | string("!")
+ # p.run("hello") => Success.new("hello", 5)
def choice(other_parser)
Parser.new do |state|
result = run_with_state(state)
if result.success?
result
@@ -112,10 +135,13 @@
end
end
end
alias_method :|, :choice
+
+ # Repeat the parser n times
+ # Separator is optional, its another parser that will be run between each repetition
# rep0 # 0 or more
# rep # 1 or more
# rep(n = 2) # exactly 2
# repeat(n_min: 2, n_max: 4) # 2 to 4
# repeat(n_min: 2) # 2 or more
@@ -154,23 +180,31 @@
else
Success.new(values, 0, captures)
end
end
end
+
+ # Repeat the parser zero or more times
+ # c(" ").rep0.run(" ") => Success.new([" ", " ", " "], 3)
def zero_or_more
repeat(n_min: 0, n_max: Float::INFINITY)
end
alias_method :rep0, :zero_or_more
+ # Repeat the parser one or more times
+ # Same as rep0, but must match at least once
+ # c(" ").rep.run("A") => Failure.new("...")
def one_or_more(exactly = nil)
if exactly.nil?
repeat(n_min: 1, n_max: Float::INFINITY)
else
repeat(n_min: exactly, n_max: exactly)
end
end
alias_method :rep, :one_or_more
+ # Make parser optional
+ # c(" ").opt.run("A") => Success.new([], 0)
def optional
Parser.new do |state|
result = run_with_state(state.dup)
if result.success?
result