aboutsummaryrefslogtreecommitdiff
path: root/src/parcom.cr
diff options
context:
space:
mode:
Diffstat (limited to 'src/parcom.cr')
-rw-r--r--src/parcom.cr44
1 files changed, 29 insertions, 15 deletions
diff --git a/src/parcom.cr b/src/parcom.cr
index 0963184..60b8df0 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -12,9 +12,13 @@ module Parcom
# The first and second arguments are types used for the parser's type.
# The thirs argument is a string literal used for the name of the parser.
# This is 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)`.
+ # an expression resolving to a `Parser(t.class, _)`, whose success value will
+ # be stored in the aformentioned variable. The `make` named argument is an
+ # expression that resolves to a `Parser(t.class, u.class)`. This parser is
+ # the final step of the parser chain. The `pure` named argument is an
+ # expression that resolves to a `u.class`. This expression is passed to a
+ # call to `Parser(t.class, u.class).pure`, which will be the final step
+ # of the parser chain.
#
# Example:
# ```
@@ -23,7 +27,7 @@ module Parcom
# two_of_same_word = parser_chain Char, String, "two words",
# {word, any_word},
# {_, ws},
- # finally: Parser.token_sequence(word.chars).map(&.join)
+ # make: Parser.token_sequence(word.chars).map(&.join)
#
# tokens = Tokens.from_string("foo foo")
# result = two_of_same_word.parse(tokens)
@@ -39,17 +43,27 @@ module Parcom
# ```
#
# This macro is based on Haskell's do-notation.
- macro parser_chain(t, u, name, *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
+ macro parser_chain(t, u, name, *steps, make = nil, pure = nil )
+ {% if make.nil? && pure.nil? %}
+ raise ArgumentError.new("Expected exactly one of 'make' and 'pure', but got neither")
+ {% elsif !make.nil? && !pure.nil? %}
+ raise ArgumentError.new("Expected exactly one of 'make' and 'pure', but got both")
+ {% else %}
+ Parser({{t}}, {{u}}).new({{name}}) do |tokens|
+ {% for tup, index in steps %}
+ {{tup.last}}.and_then do |{{tup.first}}|
+ {% end %}
+ {% if !make.nil? %}
+ {{make}}
+ {% else %}
+ Parser({{t}}, {{u}}).pure({{pure}})
+ {% end %}
+ {% for _, _ in steps %}
+ end
+ {% end %}
+ .parse(tokens)
+ end
+ {% end %}
end
end