aboutsummaryrefslogtreecommitdiff
path: root/spec/parcom_spec.cr
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-18 21:44:26 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-18 21:44:26 +1300
commit467660e024bad8e2e084aa703686d0856a7e88b9 (patch)
tree768d3ae6cf4598058553ba2aee0659c2bf233a2c /spec/parcom_spec.cr
parent658876fa4db1bb8363a03135fd22ad61b25050b7 (diff)
Sequence, +, and variants
Diffstat (limited to 'spec/parcom_spec.cr')
-rw-r--r--spec/parcom_spec.cr94
1 files changed, 94 insertions, 0 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index 6acd1b2..86ad93a 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -170,6 +170,52 @@ describe Parser do
end
end
+ describe "self.sequence" do
+ it "always succeeds with 0 parsers" do
+ p = Parser(Char, Char).sequence([] of Parser(Char, Char))
+ tokens = Tokens.from_string("")
+ result = p.parse(tokens)
+
+ result.value.empty?.should be_true
+ result.tokens.should eq(tokens)
+ end
+
+ p = Parser(Char, Char).sequence([
+ Parser(Char, Char).token('a'),
+ Parser(Char, Char).token('b'),
+ Parser(Char, Char).token('c'),
+ ])
+
+ it "runs each parser in sequence" do
+ tokens = Tokens.from_string("abcd")
+ result = p.parse(tokens)
+
+ result.value.should eq("abc".chars)
+ result.tokens.should eq(tokens[3..])
+ end
+
+ it "fails if any of the parsers fail" do
+ "xbc axc abx".split.each do |s|
+ tokens = Tokens.from_string(s)
+ expect_raises(ParserFail) { p.parse(tokens) }
+ end
+ end
+ end
+
+ # most testing should be able to be skipped, since it is already
+ # done for `Parser.sequence`
+ describe "self.token_sequence" do
+ p = Parser(Char, Char).token_sequence("abc".chars)
+
+ it "parses the specified tokens in sequence" do
+ tokens = Tokens.from_string("abcd")
+ result = p.parse(tokens)
+
+ result.value.should eq("abc".chars)
+ result.tokens.should eq(tokens[3..])
+ end
+ end
+
describe "#assert" do
p = Parser(Char, Char).any_token.assert { |c| c == 'a' }
@@ -284,7 +330,55 @@ describe Parser do
it "does not modify the input when recovering" do
result2.tokens.should eq(tokens2)
end
+ end
+
+ describe "#+" do
+ a = Parser(Char, Char).token('a')
+ b = Parser(Char, Char).token('b')
+ p = a + b
+
+ it "combines both success results if both parsers succeed" do
+ tokens = Tokens.from_string("abcd")
+ result = p.parse(tokens)
+
+ result.value.should eq({'a', 'b'})
+ result.tokens.should eq(tokens[2..])
+ end
+
+ it "fails if either parser fails" do
+ "aacd bbcd cccd".split.each do |s|
+ tokens = Tokens.from_string(s)
+ expect_raises(ParserFail) { p.parse(tokens) }
+ end
+ end
+ end
+
+ # Should be able to skip some tests because they are already
+ # written for #+, which this is based on.
+ describe "#<<" do
+ a = Parser(Char, Char).token('a')
+ b = Parser(Char, Char).token('b')
+ p = a << b
+ tokens = Tokens.from_string("abcd")
+ result = p.parse(tokens)
+
+ it "discards the second parser's value" do
+ result.value.should eq('a')
+ end
+ end
+ # Should be able to skip some tests because they are already
+ # written for #+, which this is based on.
+ describe "#>>" do
+ a = Parser(Char, Char).token('a')
+ b = Parser(Char, Char).token('b')
+ p = a >> b
+ tokens = Tokens.from_string("abcd")
+ result = p.parse(tokens)
+
+ it "discards the second parser's value" do
+ result.value.should eq('b')
+ end
end
end