aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parcom.cr44
-rw-r--r--src/parcom/parser.cr4
2 files changed, 31 insertions, 17 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
diff --git a/src/parcom/parser.cr b/src/parcom/parser.cr
index efa9780..398c95d 100644
--- a/src/parcom/parser.cr
+++ b/src/parcom/parser.cr
@@ -255,7 +255,7 @@ module Parcom
parser_chain T, {U, V}, "#{@name} + #{other.name}",
{x, self},
{y, other},
- finally: Parser(T, {U, V}).pure({x, y})
+ make: Parser(T, {U, V}).pure({x, y})
end
# Same as `#+`, but discards the second parser's result.
@@ -440,7 +440,7 @@ module Parcom
parser_chain T, Array(U), "<#{@name}> sep by <#{sep.name}>",
{head, self},
{tail, (sep >> self).many},
- finally: Parser(T, Array(U)).pure(tail.unshift(head))
+ make: Parser(T, Array(U)).pure(tail.unshift(head))
end
end
end