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
|
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
|