require "./spec_helper" include Parcom describe "parser_chain" do it "works with zero intermediate steps" do p = parser_chain Char, Char, "test", 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 Char, Char, "test", {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 Char, Float64, "float", {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 Char, {String, String}, "two_words", {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