require "./parser.cr" require "./assert.cr" require "./many.cr" module Parcom # `Some` is a `Parser` that repeatedly tries to parse with another parser. # The `Some` object will collect all success values in an array, and # return them with the final state of the input stream. If the wrapped # parser ever fails or succeeds without parsing any input, the `Some` # object will stop attempting to parse and will return the array of # previous successes. # # `Some` will raise a `ParserFail` exception if the parser never succeeds # or consumes input. For cases where parsing should allow for 0 successes, # use `Many`. class Some(T, V) < Parser(T, Array(V)) @p : Assert(T, Array(V)) # Accepts the parser to use. def initialize(p : Parser(T, V)) @p = Many.new(p).assert { |arr| !arr.empty? } end # Continuously parses with the wrapped parser, returns all successes. # Fails if there are no successes. def parse(tokens : Tokens(T)) : Result(T, Array(V)) @p.parse(tokens) rescue ex : ParserFail raise ParserFail.new("Some: #{ex.message}") end end end