diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-09 16:52:30 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-09 16:52:30 +1300 |
| commit | 1a9792afb92e227adcb564a051b678faa9fe2036 (patch) | |
| tree | 5fe774808eaef5943adef601c95b85712f684335 | |
| parent | 61f7421c2feb36b529a51589967efaa11e6a1814 (diff) | |
Implement Exactly + extra test for Sequence
| -rw-r--r-- | spec/parcom_spec.cr | 50 | ||||
| -rw-r--r-- | src/parcom.cr | 12 |
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 |
