diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/parcom.cr | 13 | ||||
| -rw-r--r-- | src/parcom/optional.cr | 40 |
2 files changed, 40 insertions, 13 deletions
diff --git a/src/parcom.cr b/src/parcom.cr index e421e5e..fdf7e31 100644 --- a/src/parcom.cr +++ b/src/parcom.cr @@ -93,19 +93,6 @@ module Parcom end end - class Optional(T, V) < Parser(T, V?) - def initialize(@p : Parser(T, V)) - end - - def parse(tokens : Tokens(T)) : Result(T, V?) - r = @p.parse?(tokens) - - new_tokens = r.nil? ? tokens : r.tokens - new_value = r.nil? ? nil : r.value - Result.new(new_tokens, new_value) - end - end - class Sequence(T, V) < Parser(T, Array(V)) def initialize(@ps : Iterable(Parser(T, V))) end diff --git a/src/parcom/optional.cr b/src/parcom/optional.cr new file mode 100644 index 0000000..b368d4e --- /dev/null +++ b/src/parcom/optional.cr @@ -0,0 +1,40 @@ +require "./parser.cr" + +module Parcom + # `Optional` is a `Parser` that tries to parse with another parser, + # but does not fail the parser chain if the wrapped parser fails. + # If the wrapped parser fails, an `Optional` will not modify the input + # stream, and return `nil` instead. + # + # Example: + # ``` + # digit = Satisfy(Char).new { |c| c.digit? } + # digits = Many.new(digit) + # plus_sign = Optional.new(Token.new('+')) + # positive_int = plus_sign >> digits + # + # input1 = Tokens.from_string("+12345") + # input2 = Tokens.from_string("12345") + # + # # Both of these has the same result + # positive_int.parse(input1) + # positive_int.parse(input2) + # ``` + class Optional(T, V) < Parser(T, V?) + # Accepts the parser to use. + def initialize(@p : Parser(T, V)) + end + + # Tries to parse with the given parser, succeeds with `nil` + # instead of failing. This parser does not consume input if + # the wrapped parser fails. + def parse(tokens : Tokens(T)) : Result(T, V?) + r = @p.parse?(tokens) + + new_tokens = r.nil? ? tokens : r.tokens + new_value = r.nil? ? nil : r.value + Result.new(new_tokens, new_value) + end + end +end + |
