aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-09 16:52:30 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-09 16:52:30 +1300
commit1a9792afb92e227adcb564a051b678faa9fe2036 (patch)
tree5fe774808eaef5943adef601c95b85712f684335
parent61f7421c2feb36b529a51589967efaa11e6a1814 (diff)
Implement Exactly + extra test for Sequence
-rw-r--r--spec/parcom_spec.cr50
-rw-r--r--src/parcom.cr12
2 files changed, 60 insertions, 2 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index 9051cb7..713445f 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -401,6 +401,15 @@ describe Sequence do
expect_raises(ParserException) { p.parse(tokens) }
end
end
+
+ it "succeeds and returns empty array if parser iterable is empty" do
+ tokens = TokenStream.from_string("abcd")
+ empty_p = Sequence.new([] of Parser(Char, Char))
+ result = empty_p.parse(tokens)
+
+ result.value.empty?.should be_true
+ result.tokens.should eq(tokens)
+ end
end
end
@@ -480,7 +489,46 @@ describe Some do
end
end
-pending Exactly do
+describe Exactly do
+ letter_a = Token.new('a')
+ tokens = TokenStream.from_string("aaabcd")
+
+ describe "#parse" do
+ it "tries to parse exactly n of the wrapper parser" do
+ p = Exactly.new(3, letter_a)
+ result = p.parse(tokens)
+
+ result.value.should eq("aaa".chars)
+ result.tokens.should eq(tokens[3..])
+ end
+
+ it "always succeeds with an empty array if n < 1" do
+ p = Exactly.new(0, letter_a)
+ result = p.parse(tokens)
+
+ result.value.empty?.should be_true
+ result.tokens.should eq(tokens)
+
+ p = Exactly.new(-42, letter_a)
+ result = p.parse(tokens)
+
+ result.value.empty?.should be_true
+ result.tokens.should eq(tokens)
+ end
+
+ it "does not take extra matching tokens" do
+ p = Exactly.new(2, letter_a)
+ result = p.parse(tokens)
+
+ result.value.should eq("aa".chars)
+ result.tokens.should eq(tokens[2..])
+ end
+
+ it "fails if there are not enough matching tokens" do
+ p = Exactly.new(60, letter_a)
+ expect_raises(ParserException) { p.parse(tokens) }
+ end
+ end
end
pending AtLeast do
diff --git a/src/parcom.cr b/src/parcom.cr
index d7e6682..c7f4012 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -295,7 +295,17 @@ module Parcom
end
end
- class Exactly
+ class Exactly(T, V) < Parser(T, Array(V))
+ @p : Sequence(T, V)
+
+ def initialize(i : Int, p : Parser(T, V))
+ i = i.negative? ? 0 : i
+ @p = Sequence.new(([p] of Parser(T, V)) * i)
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, Array(V))
+ @p.parse(tokens)
+ end
end
class AtLeast