aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/parcom_spec.cr50
-rw-r--r--src/parcom.cr31
2 files changed, 77 insertions, 4 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index 937c43c..57c5024 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -402,10 +402,56 @@ describe Tokens do
end
end
-pending Many do
+describe Many do
+ p = Many.new(Token.new('a'))
+
+ describe "#parse" do
+ it "returns an empty array if the wrapped parser never succeeds" do
+ tokens = TokenStream.from_string("bb")
+ result = p.parse(tokens)
+
+ result.value.empty?.should be_true
+ result.tokens.should eq(tokens)
+ end
+
+ it "stops parsing when the wrapped parser fails, returns all successes" do
+ tokens = TokenStream.from_string("aaabcd")
+ result = p.parse(tokens)
+
+ result.value.should eq("aaa".chars)
+ result.tokens.should eq(tokens[3..])
+
+ tokens = TokenStream.from_string("aaa")
+ result = p.parse(tokens)
+
+ result.value.should eq("aaa".chars)
+ result.tokens.should eq(tokens[3..])
+ end
+ end
end
-pending Some do
+describe Some do
+ p = Some.new(Token.new('a'))
+ describe "#parse" do
+ it "fails if the wrapped parser never succeeds" do
+ tokens = TokenStream.from_string("")
+ expect_raises(ParserException) { p.parse(tokens) }
+ end
+
+ it "stops parsing when the wrapped parser fails, returns all successes" do
+ tokens = TokenStream.from_string("aaabcd")
+ result = p.parse(tokens)
+
+ result.value.should eq("aaa".chars)
+ result.tokens.should eq(tokens[3..])
+
+ tokens = TokenStream.from_string("aaa")
+ result = p.parse(tokens)
+
+ result.value.should eq("aaa".chars)
+ result.tokens.should eq(tokens[3..])
+ end
+ end
end
pending Exactly do
diff --git a/src/parcom.cr b/src/parcom.cr
index 760a450..8d7c754 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -246,10 +246,37 @@ module Parcom
end
end
- class Many
+ class Many(T, V) < Parser(T, Array(V))
+ def initialize(@p : Parser(T, V))
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, Array(V))
+ parsed = [] of V
+
+ loop do
+ result = @p.parse?(tokens)
+ if result.nil?
+ break
+ else
+ parsed << result.value
+ tokens = result.tokens
+ end
+ end
+
+ Result.new(tokens, parsed)
+ end
end
- class Some
+ class Some(T, V) < Parser(T, Array(V))
+ @p : Assert(T, Array(V))
+
+ def initialize(p : Parser(T, V))
+ @p = Many.new(p).assert { |arr| !arr.empty? }
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, Array(V))
+ @p.parse(tokens)
+ end
end
class Exactly