1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
require "../spec_helper"
include Parcom
describe "Hash(Int32, Int32) parser", tags: "example" do
# setup
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 = parser_chain Char, Array({Int32, Int32}), "elements",
{pairs, pair.sep_by(delim)},
{_, delim.optional}, # trailing comma
pure: pairs
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
|