require "../parcom.cr" module Parcom # `Parser` is the base class of all parser objects and contains # a handful of helper methods that can allow for cleaner syntax. # # The generic type `T` represents the type of tokens a parser will # operate on (usually `Char`). # The generic type `V` represents the type of value that a parser # will return when parsing is successful. abstract class Parser(T, V) # Accepts a `Tokens(T)` and either retuns a `Result(T, V)`, or raises a # `ParserFail` exception with a message providing context of where # in the chain the parsing failed. # # The `V` in the returned `Result` is arbitrary, but the `Tokens(T)` in # the returned result MUST contain the parser's input, with some tokens # removed from the front proprtional to what was parsed. # # Example: # ``` # hello = ParsesHello.new # inherits from Parser(Char, String) # input = Tokens.from_string("Hello world!") # # result = hello.parse(input) # result.value # => "Hello" # result.tokens # => [' ', 'w', 'o', 'r', 'l', 'd', '!'] # # bad_input = Tokens.from_string("Good evening world!") # hello.parse(bad_input) # raises ParserFail # ``` abstract def parse(tokens : Tokens(T)) : Result(T, V) # Same as `#parse`, but returns `nil` instead of raising `ParserFail`. def parse?(tokens : Tokens(T)) : Result(T, V)? self.parse(tokens) rescue ParserFail return nil end # Constructs an `Alt` parser with `self` and `other`. def |(other : Parser(T, V)) : Alt(T, V) Alt.new(self, other) end # Constructs a `Plus` parser with `self` and `other`. def +(other : Parser(T, U)) : Plus(T, V, U) forall U Plus.new(self, other) end # Constructs a `Left` parser with `self` and `other`. def <<(other : Parser(T, U)) : Left(T, V, U) forall U Left.new(self, other) end # Constructs a `Right` parser with `self` and `other`. def >>(other : Parser(T, U)) : Right(T, V, U) forall U Right.new(self, other) end # Constructs an `Assert` parser with `self` and the given block. def assert(&block : V -> Bool) : Assert(T, V) Assert.new(self, &block) end # Constructs an `Assert` parser with `self` and the given proc. def assert(f : V -> Bool) : Assert(T, V) Assert.new(self, &f) end # Constructs a `Map` parser with `self` and the given block. def map(&block : V -> U) : Map(T, V, U) forall U Map.new(self, &block) end # Constructs a `Map` parser with `self` and the given proc. def map(f : V -> U) : Map(T, V, U) forall U Map.new(self, &f) end # Constructs a `Recover` parser with `self` and the given `V`. def recover(default : V) : Recover(T, V) Recover.new(self, default) end end end