diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-19 21:48:31 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-19 21:48:31 +1300 |
| commit | acd14e4b4f722f7fe502bbf3aabab16d7d7df396 (patch) | |
| tree | c7930e01b8c9bc743feecca09821235b47d69208 /spec/parcom_spec.cr | |
| parent | 0c7a2fe2c675ec742a953a4614d993e4f2694fff (diff) | |
exactly, at_least, at_most, between
Diffstat (limited to 'spec/parcom_spec.cr')
| -rw-r--r-- | spec/parcom_spec.cr | 210 |
1 files changed, 206 insertions, 4 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr index 749f7e0..aae1d1b 100644 --- a/spec/parcom_spec.cr +++ b/spec/parcom_spec.cr @@ -415,10 +415,212 @@ describe Parser do end end end - # TODO: exactly - # TODO: at_least - # TODO: at_most - # TODO: between + + describe "#exactly" do + a = Parser.token('a') + tokens = Tokens.from_string("aaabbb") + + it "fails to instantiate if `n` is negative" do + expect_raises(ArgumentError) { a * -3 } + end + + it "accepts parsing 0 times" do + p = a * 0 + result = p.parse(tokens) + + result.value.empty?.should be_true + result.tokens.should eq(tokens) + end + + it "tries to parse exactly n times" do + p = a * 3 + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "does not parse more than n times, even if it could" do + p = a * 1 + result = p.parse(tokens) + + result.value.should eq(['a']) + result.tokens.should eq(tokens[1..]) + end + + it "fails if unable to parse enough times" do + p = a * 5 + expect_raises(ParserFail) { p.parse(tokens) } + end + end + + describe "#at_least" do + a = Parser.token('a') + tokens = Tokens.from_string("aaabbb") + + it "fails to instantiate if `n` is negative" do + expect_raises(ArgumentError) { a.at_least(-3) } + end + + it "accepts parsing 0 times" do + p = a.at_least(0) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "tries to parse at least n times" do + p = a.at_least(3) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "parses as many times as possible (>=n)" do + p = a.at_least(1) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "fails if unable to parse enough times" do + p = a.at_least(5) + expect_raises(ParserFail) { p.parse(tokens) } + end + end + + describe "#at_most" do + a = Parser.token('a') + tokens = Tokens.from_string("aaabbb") + + it "fails to instantiate if `n` is negative" do + expect_raises(ArgumentError) { a.at_most(-3) } + end + + it "accepts parsing 0 times" do + p = a.at_most(0) + result = p.parse(tokens) + + result.value.should eq([] of Char) + result.tokens.should eq(tokens) + end + + it "tries to parse at most n times" do + p = a.at_most(3) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "stops if it succeeds `n` times" do + p = a.at_most(1) + result = p.parse(tokens) + + result.value.should eq(['a']) + result.tokens.should eq(tokens[1..]) + end + + it "stops if unable to parse `n` times" do + p = a.at_most(5) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + end + + describe "#between" do + a = Parser.token('a') + tokens = Tokens.from_string("aaabbb") + + it "fails to instantiate if `n` or `m` are negative" do + expect_raises(ArgumentError) { a.between(-1, 1) } + expect_raises(ArgumentError) { a.between(1, -1) } + expect_raises(ArgumentError) { a.between(-1, -1) } + end + + it "fails to instantiate if any range values are negative" do + {(-1..3), (-3..-1), (..-3), (-3..)}.each do |r| + expect_raises(ArgumentError) { a.between(r) } + end + end + + it "accepts either order for `n` and `m`" do + p1 = a.between(1,2) + r1 = p1.parse(tokens) + + p2 = a.between(2,1) + r2 = p1.parse(tokens) + + r1.should eq(r2) + end + + it "accepts `0` for `n` and `m`" do + p = a.between(0, 2) + result = p.parse(tokens) + + result.value.should eq(['a', 'a']) + result.tokens.should eq(tokens[2..]) + end + + it "accepts Range objects" do + p = a.between(1..2) + result = p.parse(tokens) + + result.value.should eq(['a', 'a']) + result.tokens.should eq(tokens[2..]) + end + + it "accepts beginless ranges" do + p = a.between(..2) + result = p.parse(tokens) + + result.value.should eq(['a', 'a']) + result.tokens.should eq(tokens[2..]) + end + + it "accepts endless ranges" do + p = a.between(2..) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "tries to parse between `n` and `m` times" do + p = a.between(1, 2) + result = p.parse(tokens) + + result.value.should eq(['a', 'a']) + result.tokens.should eq(tokens[2..]) + end + + it "fails if it does not succeed the minimum number of times" do + p = a.between(5, 6) + expect_raises(ParserFail) { p.parse(tokens) } + end + + it "stops parsing if it fails after succeeding the minimum number of times" do + p = a.between(2, 4) + result = p.parse(tokens) + + result.value.should eq(['a', 'a', 'a']) + result.tokens.should eq(tokens[3..]) + end + + it "stops parsing if it succeeds the maximum number of times" do + p = a.between(1, 2) + result = p.parse(tokens) + + result.value.should eq(['a', 'a']) + result.tokens.should eq(tokens[2..]) + end + end + # TODO: first_of # TODO: sep_by # TODO: phrase |
