diff options
Diffstat (limited to 'spec')
| -rw-r--r-- | spec/parcom_spec.cr | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr index cee6ff4..2b7a447 100644 --- a/spec/parcom_spec.cr +++ b/spec/parcom_spec.cr @@ -2,6 +2,81 @@ require "./spec_helper" include Parcom +describe "parser_chain" do + it "works with zero intermediate steps" do + p = parser_chain "test", Char, Char, finally: Parser(Char, Char).pure('x') + tokens = Tokens.from_string("abcd") + result = p.parse(tokens) + + result.value.should eq('x') + result.tokens.should eq(tokens) + end + + it "works with one intermediate step" do + p = parser_chain "test", Char, Char, + {c, Parser(Char, Char).any_token}, + finally: Parser(Char, Char).pure(c) + tokens = Tokens.from_string("abcd") + result = p.parse(tokens) + + result.value.should eq('a') + result.tokens.should eq(tokens[1..]) + end + + it "works with many intermediate steps" do + digit = Parser(Char, Char).satisfy(&.number?) + p = parser_chain "float", Char, Float64, + {sign, Parser.token('-').map_const(-1).recover(1)}, + {front, digit.many}, + {point, Parser.token('.').optional}, + {back, digit.many}, + finally: case {front.empty?, point.nil?, back.empty?} + when {false, _, true} + Parser(Char, Float64).pure(front.join.to_f64 * sign) + when {true, false, false} + Parser(Char, Float64).pure("0.#{back.join}".to_f64 * sign) + when {false, false, false} + Parser(Char, Float64).pure("#{front.join}.#{back.join}".to_f64 * sign) + else + Parser(Char, Float64).flunk + end + { + {"1", 1_f64}, + {"-1", -1_f64}, + {"2.", 2_f64}, + {"-2.", -2_f64}, + {".3", 0.3_f64}, + {"-.3", -0.3_f64}, + {"0.4", 0.4_f64}, + {"-0.4", -0.4_f64}, + }.each do |s, v| + tokens = Tokens.from_string(s) + result = p.parse(tokens) + + result.value.should eq(v) + result.tokens.empty?.should be_true + end + end + + it "allows ignoring results with underscores" do + any_word = Parser(Char, String).satisfy(&.letter?).some.map(&.join) + ws = Parser(Char, Array(Char)).satisfy(&.whitespace?).many + two_words = parser_chain "two words", Char, {String, String}, + {word, any_word}, + {_, ws}, + finally: Parser.token_sequence(word.chars).map_const({word, word}) + + tokens = Tokens.from_string("foo \n foo") + result = two_words.parse(tokens) + result.value.should eq({"foo", "foo"}) + + tokens = Tokens.from_string("foo bar") + expect_raises(ParserFail) { two_words.parse(tokens) } + tokens = Tokens.from_string("foofoo") + expect_raises(ParserFail) { two_words.parse(tokens) } + end +end + describe Tokens do describe ".from_string" do it "constructs a Tokens(Char) from a String" do |
