aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/parcom_spec.cr23
-rw-r--r--src/parcom.cr19
2 files changed, 39 insertions, 3 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index d9af3b9..2f3f6ba 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -348,7 +348,7 @@ describe Recover do
result.value.should eq('t')
end
- it "succeeds and returns the default value without modifying the input of the wrapped parser fails" do
+ it "succeeds and returns the default value without modifying the input if the wrapped parser fails" do
tokens = TokenStream.from_string("_____")
result = p.parse(tokens)
@@ -358,7 +358,26 @@ describe Recover do
end
end
-pending Optional do
+describe Optional do
+ p = Optional.new(Token.new('t'))
+
+ describe "#parse" do
+ it "succeeds and returns the wrapped parser's value if it succeeds" do
+ tokens = TokenStream.from_string("testing")
+ result = p.parse(tokens)
+
+ result.tokens.should eq(tokens[1..])
+ result.value.should eq('t')
+ end
+
+ it "succeeds and returns a value of `nil` without modifying the input if the wrapped parser fails" do
+ tokens = TokenStream.from_string("_____")
+ result = p.parse(tokens)
+
+ result.tokens.should eq(tokens)
+ result.value.should be_nil
+ end
+ end
end
pending Tokens do
diff --git a/src/parcom.cr b/src/parcom.cr
index f102728..87c73c5 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -201,7 +201,24 @@ module Parcom
end
end
- class Optional
+ # TODO: find a way to make this use Recover on the back end
+ class Optional(T, V) < Parser(T, V?)
+ def initialize(@p : Parser(T, V))
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, V?)
+ r = @p.parse?(tokens)
+
+ if r.nil?
+ Result.new(tokens, nil)
+ else
+ Result.new(r.tokens, r.value || nil)
+ end
+
+ new_tokens = r.nil? ? tokens : r.tokens
+ new_value = r.nil? ? nil : r.value
+ Result.new(new_tokens, new_value)
+ end
end
class Tokens