require "../spec_helper" include Parcom describe "Hash(Int32, Int32) parser", tags: "example" do d = Parser(Char, Char).satisfy(&.number?).named("digit") abs_num = d.some.map { |ds| ds.join.to_i32 }.named("abs_num") sign = Parser.token('-').map_const(-1_i32).recover(1_i32).named("sign") int32 = parser_chain Char, Int32, "int32", {s, sign}, {n, abs_num}, pure: n * s ws = Parser(Char, Char).satisfy(&.whitespace?) .many .named("whitespace") arrow = (ws >> Parser.token_sequence("=>".chars) >> ws).named("arrow") pair = parser_chain Char, {Int32, Int32}, "pair", {x, int32}, {_, arrow}, {y, int32}, pure: {x, y} delim = (ws >> Parser.token(',') >> ws).named("delim") elements = (pair.sep_by(delim) << delim.optional).named("elements") hash_start = (Parser.token('{') >> ws).named("start") hash_end = (ws >> Parser.token('}')).named("end") hash = parser_chain Char, Hash(Int32, Int32), "hash", {_, hash_start}, {es, elements.recover([] of {Int32, Int32})}, {_, hash_end}, pure: es.to_h it "can parse an empty hash" do empty = {} of Int32 => Int32 {"{}", "{ }", "{ \t\n\r}"}.each do |s| result = hash.parse(Tokens.from_string(s)) result.value.should eq(empty) result.tokens.empty?.should be_true end end it "does not accept trailing commas in empty hashes" do {"{,}", "{ ,}", "{, }", "{ , }"}.each do |s| expect_raises(ParserFail) { hash.parse(Tokens.from_string(s)) } end end it "can parse hashes with one entry" do expected = {2_i32 => -1_i32} { "{2=>-1}", "{2=>-1,}", "{2 =>-1 ,}", "{ 2 => -1 , }", }.each do |s| result = hash.parse(Tokens.from_string(s)) result.value.should eq(expected) result.tokens.empty?.should be_true end end it "can parse hashes with many entries" do expected = { -2_i32 => 1_i32, 3_i32 => -45_i32, -6_i32 => -7_i32, 8_i32 => 90_i32, } { "{-2=>1,3=>-45,-6=>-7,8=>90}", "{ -2=> 1,3 => -45,-6 =>-7,8 => 90,}", }.each do |s| result = hash.parse(Tokens.from_string(s)) result.value.should eq(expected) result.tokens.empty?.should be_true end end end