diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-16 23:11:23 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-16 23:11:23 +1300 |
| commit | f023ca56dbf9372464afe0060270fcef85271db0 (patch) | |
| tree | b045bebfbb8ac7e6208e5703cb0f53808b14fe89 /spec/parcom_spec.cr | |
| parent | b274828831fec26cd8b3089ffef14cb96ce2de2f (diff) | |
I'm too tired for this
Diffstat (limited to 'spec/parcom_spec.cr')
| -rw-r--r-- | spec/parcom_spec.cr | 170 |
1 files changed, 169 insertions, 1 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr index d25c786..ceb7de8 100644 --- a/spec/parcom_spec.cr +++ b/spec/parcom_spec.cr @@ -4,6 +4,174 @@ require "../src/parcom.cr" include Parcom -pending State do +describe Tokens do + describe ".from_string" do + it "constructs a Tokens(Char) from a String" do + tokens = Tokens.from_string("abcd") + tokens.tokens.should eq("abcd".chars) + end + end + + describe "#initialize" do + it "wraps an array with the contents of the given iterable" do + set = Set{'a', 'b', 'c', 'd'} + tokens = Tokens.new(set) + tokens.tokens.should eq(set.to_a) + + arr = "abcd".chars + tokens = Tokens.new(arr) + tokens.tokens.should eq(arr) + end + end + + context do + tokens_empty = Tokens.new([] of Char) + tokens = Tokens.from_string("abcd") + + describe "#[]" do + it "returns the token at the given index" do + tokens[2].should eq('c') + expect_raises(IndexError) { tokens_empty[2] } + end + + it "returns a new Tokens similar to Array#[](Int, Int)" do + tokens[1, 5].should eq(Tokens.new(['b', 'c', 'd'])) + expect_raises(IndexError) { tokens_empty[1, 5] } + end + + it "returns a new Tokens similar to Array#[](Range)" do + tokens[1..3].should eq(Tokens.new(['b', 'c', 'd'])) + expect_raises(IndexError) { tokens_empty[1..3] } + end + end + + describe "#[]?" do + it "analogous to `Array#[]?`" do + # we should only need to check the nil-returning cases + tokens_empty[2]?.should be_nil + tokens_empty[1, 5]?.should be_nil + tokens_empty[1..3]?.should be_nil + end + end + + describe "#empty?" do + it "exposes the `#empty?` method of the wrapped array" do + tokens.empty?.should be_false + tokens_empty.empty?.should be_true + end + end + end +end + +describe Result do + describe "#map" do + r = Result.new(Tokens.from_string("abcd"), 'x') + r_expected = Result.new(Tokens.from_string("abcd"), 'x'.ord) + + it "accepts a proc" do + f = ->(c : Char) { c.ord } + r.map(f).should eq(r_expected) + end + + it "accepts a block" do + r.map { |c| c.ord }.should eq(r_expected) + end + end +end + +pending Parser do + describe "#assert" do + p = Basic(Char, Char).any_token.assert { |c| c == 'a' } + + it "succeeds if the parser succeeds and if the predicate passes" do + tokens = Tokens.from_string("abcd") + result = p.parse(tokens) + + result.value.should eq(tokens[0]) + result.tokens.should eq(tokens[1..]) + end + + it "fails if the predicate fails" do + tokens = Tokens.from_string("bbcd") + expect_raises(ParserFail) { p.parse(tokens) } + end + end +end + +describe Basic do + describe "Basic.pure" do + v = 'a' + p = Basic(Char, Char).pure(v) + tokens = Tokens.from_string("____") + result = p.parse(tokens) + + it "returns a value of whatever it was initialized with" do + result.value.should eq(v) + end + + it "does not modify the input" do + result.tokens.should eq(tokens) + end + end + + describe "Basic.flunk" do + p = Basic(Char, Char).flunk + it "always fails" do + expect_raises(ParserFail) { p.parse(Tokens.from_string("arbitrary")) } + end + end + + describe "Basic.any_token" do + p = Basic(Char, Nil).any_token + + it "parses the first token in the input stream" do + tokens = Tokens.from_string("abcd") + result = p.parse(tokens) + + result.value.should eq(tokens[0]) + result.tokens.should eq(tokens[1..]) + end + + it "fails if the input stream is empty" do + tokens = Tokens.from_string("") + expect_raises(ParserFail) { p.parse(tokens) } + end + end + + describe "Basic.eof" do + p = Basic(Char, Nil).eof + + it "succeeds with nil if the input stream is empty" do + tokens = Tokens.from_string("") + result = p.parse(tokens) + + result.value.should be_nil + result.tokens.empty?.should be_true + end + + it "fails if the input stream is not empty" do + tokens = Tokens.from_string("____") + expect_raises(ParserFail) { p.parse(tokens) } + end + end + + # TODO: the type checker hates me + describe "Basic.satisfy" do + #p = Basic.satisfy(Char) { |c| c == 'a' } + p = Basic(Char, Char).satisfy(->(c : Char) { c == 'a' }) + + it "succeeds if the token passes the predicate" do + tokens = Tokens.from_string("abcd") + result = p.parse(tokens).as_a(Result(Char, Char)) + + result.value.should eq(tokens[0]) + result.tokens.should eq(tokens[1..]) + end + + it "fails if the token fails the predicate" do + tokens = Tokens.from_string("bbcd") + expect_raises(ParserFail) { p.parse(tokens) } + end + end end |
