require "./parser.cr" require "./map.cr" require "./exactly.cr" require "./optional.cr" module Parcom # `AtMost` is a `Parser` that tries to parse with another parser a specific # number of times. The results of each successful parse are returned in an # array. If the specific number of parses succeed, the parsing stops, even # if it is possible to keep parsing. If the parser is never successful, it # succeeds with an empty array. class AtMost(T, V) < Parser(T, Array(V)) @p : Map(T, Array(V?), Array(V)) # Accepts the number of parsing attempts, and the parser to use. def initialize(i : Int, p : Parser(T, V)) @p = Exactly.new(i, Optional.new(p)).map(&.compact) end # Tries to parse up to the given number of times. # If the parser never succeeds, returns an empty array. def parse(tokens : Tokens(T)) : Result(T, Array(V)) @p.parse(tokens) rescue ex : ParserFail raise ParserFail.new("AtMost: #{ex.message}") end end end