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
93
94
|
require "./spec_helper"
include Parcom
describe "parser_chain" do
it "works with zero intermediate steps" do
p = parser_chain Char, Char, "test", 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},
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},
make: 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},
make: 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
it "fails without being given either `make` or `pure`" do
expect_raises(ArgumentError) do
_ = parser_chain Char, Char, "fails", {c, Parser.token('t')}
end
end
it "fails when given both `make` and `pure` at the same time" do
expect_raises(ArgumentError) do
_ = parser_chain Char, Char, "fails",
{c, Parser.token('t')},
pure: c,
make: Parser(Char, Char).pure('s')
end
end
end
|