aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parcom.cr44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/parcom.cr b/src/parcom.cr
index cdbebdb..7f0e475 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -8,6 +8,50 @@ module Parcom
class ParserFail < Exception
end
+ # Provides a more convenient syntax for combining parsers via `Parser#and_then`.
+ # The first argument is a string literal used for the name of the parser.
+ # The second and third arguments are types used for the parser's type.
+ # These are followed by any number of 2-tuples containing a variable name and
+ # an expression resolving to a `Parser(t.Class, _)`, whose success value will
+ # be stored in the aformentioned variable. The `finally` named argument is an
+ # expression that resolves to a `Parser(t.class, u.class)`.
+ #
+ # Example:
+ # ```
+ # any_word = Parser(Char, Char).satisfy(&.letter?).some.map(&.join)
+ # ws = Parser(Char, Array(Char)).satisfy(&.whitespace?).many
+ # two_of_same_word = parser_chain "two words", Char, String,
+ # {word, any_word},
+ # {_, ws},
+ # finally: Parser.token_sequence(word.chars).map(&.join)
+ #
+ # tokens = Tokens.from_string("foo foo")
+ # result = two_of_same_word.parse(tokens)
+ # result.value # => "foo"
+ #
+ # # The above definition of `two_of_same word`
+ # # is an alternative way of doing this:
+ # two_of_same_word = any_word.and_then do |word|
+ # ws.and_then do |_|
+ # Parser.token_sequence(word.chars).map(&.join)
+ # end
+ # end.named("two words")
+ # ```
+ #
+ # This macro is based on Haskell's do-notation.
+ macro parser_chain(name, t, u, *steps, finally)
+ Parser({{t}}, {{u}}).new({{name}}) do |tokens|
+ {% for tup, index in steps %}
+ {{tup.last}}.and_then do |{{tup.first}}|
+ {% end %}
+ {{finally}}
+ {% for _, _ in steps %}
+ end
+ {% end %}
+ .parse(tokens)
+ end
+ end
+
# `Tokens` is an `Array` wrapper struct to store the input
# stream of one or more `Parser` objects.
# A `Tokens` can be created from any `Iterable`, along with