rattler 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +57 -37
- data/features/command_line/dest_option.feature +8 -21
- data/features/command_line/lib_option.feature +37 -0
- data/features/command_line/parser_generator.feature +7 -4
- data/features/grammar/back_reference.feature +37 -0
- data/features/grammar/fail.feature +3 -3
- data/features/grammar/labels.feature +11 -3
- data/features/grammar/list_matching.feature +14 -5
- data/features/grammar/literal.feature +30 -4
- data/features/grammar/nonterminal.feature +1 -1
- data/features/grammar/ordered_choice.feature +2 -2
- data/features/grammar/skip_operator.feature +1 -1
- data/features/grammar/symantic_action.feature +7 -7
- data/features/grammar/whitespace.feature +2 -2
- data/features/step_definitions/grammar_steps.rb +2 -2
- data/lib/rattler/back_end.rb +1 -0
- data/lib/rattler/back_end/compiler.rb +19 -20
- data/lib/rattler/back_end/optimizer.rb +100 -0
- data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
- data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
- data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
- data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
- data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
- data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
- data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
- data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
- data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
- data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
- data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
- data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
- data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
- data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
- data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
- data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
- data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
- data/lib/rattler/back_end/parser_generator.rb +21 -14
- data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
- data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
- data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
- data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
- data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
- data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
- data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
- data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
- data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
- data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
- data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
- data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
- data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
- data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
- data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
- data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
- data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
- data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
- data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
- data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
- data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
- data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
- data/lib/rattler/grammar.rb +4 -3
- data/lib/rattler/grammar/analysis.rb +91 -0
- data/lib/rattler/grammar/grammar.rb +37 -25
- data/lib/rattler/grammar/grammar_parser.rb +19 -11
- data/lib/rattler/grammar/metagrammar.rb +569 -800
- data/lib/rattler/grammar/rattler.rtlr +162 -144
- data/lib/rattler/parsers.rb +5 -1
- data/lib/rattler/parsers/action_code.rb +29 -15
- data/lib/rattler/parsers/apply.rb +5 -5
- data/lib/rattler/parsers/assert.rb +4 -18
- data/lib/rattler/parsers/back_reference.rb +46 -0
- data/lib/rattler/parsers/choice.rb +6 -39
- data/lib/rattler/parsers/combinator_parser.rb +32 -0
- data/lib/rattler/parsers/combining.rb +3 -29
- data/lib/rattler/parsers/direct_action.rb +27 -30
- data/lib/rattler/parsers/disallow.rb +4 -18
- data/lib/rattler/parsers/dispatch_action.rb +30 -25
- data/lib/rattler/parsers/label.rb +9 -18
- data/lib/rattler/parsers/list.rb +3 -34
- data/lib/rattler/parsers/list1.rb +4 -36
- data/lib/rattler/parsers/list_parser.rb +64 -0
- data/lib/rattler/parsers/match.rb +7 -42
- data/lib/rattler/parsers/node_code.rb +44 -0
- data/lib/rattler/parsers/one_or_more.rb +7 -27
- data/lib/rattler/parsers/optional.rb +5 -25
- data/lib/rattler/parsers/parser.rb +16 -44
- data/lib/rattler/parsers/parser_dsl.rb +13 -3
- data/lib/rattler/parsers/predicate.rb +4 -12
- data/lib/rattler/parsers/rule.rb +18 -19
- data/lib/rattler/parsers/rule_set.rb +63 -0
- data/lib/rattler/parsers/sequence.rb +12 -46
- data/lib/rattler/parsers/skip.rb +12 -26
- data/lib/rattler/parsers/token.rb +6 -21
- data/lib/rattler/parsers/zero_or_more.rb +6 -26
- data/lib/rattler/runner.rb +66 -28
- data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
- data/lib/rattler/runtime/packrat_parser.rb +17 -21
- data/lib/rattler/runtime/parser.rb +12 -2
- data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
- data/lib/rattler/util.rb +2 -1
- data/lib/rattler/util/graphviz.rb +29 -0
- data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
- data/lib/rattler/util/graphviz/node_builder.rb +84 -0
- data/lib/rattler/util/node.rb +37 -19
- data/lib/rattler/util/parser_spec_helper.rb +61 -35
- data/spec/rattler/back_end/compiler_spec.rb +6 -860
- data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
- data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
- data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
- data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
- data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
- data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
- data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
- data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
- data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
- data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
- data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
- data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
- data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
- data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
- data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
- data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
- data/spec/rattler/grammar/analysis_spec.rb +167 -0
- data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
- data/spec/rattler/grammar/grammar_spec.rb +24 -21
- data/spec/rattler/parsers/action_code_spec.rb +64 -19
- data/spec/rattler/parsers/apply_spec.rb +9 -9
- data/spec/rattler/parsers/back_reference_spec.rb +38 -0
- data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
- data/spec/rattler/parsers/direct_action_spec.rb +16 -2
- data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
- data/spec/rattler/parsers/fail_spec.rb +6 -4
- data/spec/rattler/parsers/label_spec.rb +10 -28
- data/spec/rattler/parsers/node_code_spec.rb +48 -0
- data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
- data/spec/rattler/parsers/rule_set_spec.rb +35 -0
- data/spec/rattler/parsers/sequence_spec.rb +15 -24
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
- data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
- data/spec/rattler/runtime/parse_node_spec.rb +15 -19
- data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
- data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
- data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
- data/spec/rattler/util/node_spec.rb +92 -65
- data/spec/rattler_spec.rb +16 -16
- data/spec/support/combinator_parser_spec_helper.rb +19 -18
- data/spec/support/compiler_spec_helper.rb +56 -87
- data/spec/support/runtime_parser_spec_helper.rb +6 -14
- metadata +117 -22
- data/features/grammar/regex.feature +0 -24
- data/lib/rattler/parsers/match_joining.rb +0 -67
- data/lib/rattler/parsers/rules.rb +0 -43
@@ -1,22 +1,25 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/shared_compiler_examples')
|
2
3
|
|
3
4
|
describe Rattler::BackEnd::Compiler do
|
4
5
|
include CompilerSpecHelper
|
5
6
|
|
6
|
-
|
7
|
+
describe '.compile_parser result' do
|
8
|
+
it_behaves_like 'a compiled parser'
|
9
|
+
end
|
7
10
|
|
8
11
|
describe '.compile_parser' do
|
9
12
|
|
10
13
|
context 'given parse rules' do
|
11
14
|
|
12
|
-
let(:
|
15
|
+
let(:grammar) { define_grammar do
|
13
16
|
rule(:word) { match /\w+/ }
|
14
17
|
rule(:space) { match /\s*/ }
|
15
18
|
end }
|
16
19
|
|
17
20
|
let(:parser_base) { Rattler::Runtime::RecursiveDescentParser }
|
18
21
|
|
19
|
-
let(:result) { described_class.compile_parser(parser_base,
|
22
|
+
let(:result) { described_class.compile_parser(parser_base, grammar) }
|
20
23
|
|
21
24
|
it 'compiles a match_xxx method for each rule' do
|
22
25
|
result.should have_method(:match_word)
|
@@ -24,863 +27,6 @@ describe Rattler::BackEnd::Compiler do
|
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
27
|
-
########## match ##########
|
28
|
-
context 'given a match rule' do
|
29
|
-
let(:rules) { define_parser do
|
30
|
-
rule(:digit) { match /\d/ }
|
31
|
-
end }
|
32
|
-
it { should compile(rules).test_parsing('451').twice }
|
33
|
-
it { should compile(rules).test_parsing ' 4' }
|
34
|
-
it { should compile(rules).test_parsing 'foo' }
|
35
|
-
end
|
36
|
-
|
37
|
-
########## choice ##########
|
38
|
-
context 'given a choice rule' do
|
39
|
-
let(:rules) { define_parser do
|
40
|
-
rule :atom do
|
41
|
-
match(/[[:alpha:]]+/) & match(/[[:digit:]]+/)
|
42
|
-
end
|
43
|
-
end }
|
44
|
-
|
45
|
-
it { should compile(rules).test_parsing('abc123').twice }
|
46
|
-
it { should compile(rules).test_parsing '==' }
|
47
|
-
|
48
|
-
context 'with nested choices' do
|
49
|
-
let(:rules) { define_parser do
|
50
|
-
rule(:foo) do
|
51
|
-
(match('a') | match('b')) \
|
52
|
-
| (match('c') | match('d'))
|
53
|
-
end
|
54
|
-
end }
|
55
|
-
it { should compile(rules).test_parsing('abcd').repeating(4).times }
|
56
|
-
it { should compile(rules).test_parsing '123' }
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'with nested sequences' do
|
60
|
-
let(:rules) { define_parser do
|
61
|
-
rule(:foo) do
|
62
|
-
match('a') & match('b') \
|
63
|
-
| match('c') & match('d')
|
64
|
-
end
|
65
|
-
end }
|
66
|
-
it { should compile(rules).test_parsing('abcd').twice }
|
67
|
-
it { should compile(rules).test_parsing '123' }
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'with nested optional parsers' do
|
71
|
-
let(:rules) { define_parser do
|
72
|
-
rule(:foo) do
|
73
|
-
optional('a') | optional('b')
|
74
|
-
end
|
75
|
-
end }
|
76
|
-
it { should compile(rules).test_parsing('abcd').repeating(3).times }
|
77
|
-
it { should compile(rules).test_parsing '123' }
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
########## sequence ##########
|
82
|
-
context 'given a sequence rule' do
|
83
|
-
let(:rules) { define_parser do
|
84
|
-
rule :assignment do
|
85
|
-
match(/[[:alpha:]]+/) & match('=') & match(/[[:digit:]]+/)
|
86
|
-
end
|
87
|
-
end }
|
88
|
-
|
89
|
-
it { should compile(rules).test_parsing 'val=42 ' }
|
90
|
-
it { should compile(rules).test_parsing 'val=x' }
|
91
|
-
|
92
|
-
context 'with non-capturing parsers' do
|
93
|
-
it { should compile { rule :foo do
|
94
|
-
match(/[[:alpha:]]+/) & skip(/\s+/) & match(/[[:digit:]]+/)
|
95
|
-
end }.
|
96
|
-
test_parsing 'foo 42' }
|
97
|
-
end
|
98
|
-
|
99
|
-
context 'with only one capturing parser' do
|
100
|
-
it { should compile { rule :foo do
|
101
|
-
skip(/\s+/) & match(/\w+/)
|
102
|
-
end }.
|
103
|
-
test_parsing ' abc123' }
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'with no capturing parsers' do
|
107
|
-
it { should compile { rule :foo do
|
108
|
-
skip(/\s*/) & skip(/#[^\n]+/)
|
109
|
-
end }.
|
110
|
-
test_parsing ' # foo' }
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'with an apply referencing a non-capturing rule' do
|
114
|
-
it { should compile {
|
115
|
-
rule :ws do
|
116
|
-
skip(/\s+/)
|
117
|
-
end
|
118
|
-
rule :foo do
|
119
|
-
match(/[[:alpha:]]+/) & match(:ws) & match(/[[:digit:]]+/)
|
120
|
-
end }.
|
121
|
-
test_parsing('foo 42').as :foo }
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
########## optional ##########
|
126
|
-
context 'given an optional rule' do
|
127
|
-
let(:rules) { define_parser do
|
128
|
-
rule :foo do
|
129
|
-
optional(/\w+/)
|
130
|
-
end
|
131
|
-
end }
|
132
|
-
it { should compile(rules).test_parsing 'foo ' }
|
133
|
-
it { should compile(rules).test_parsing ' ' }
|
134
|
-
|
135
|
-
context 'with a non-capturing parser' do
|
136
|
-
let(:rules) { define_parser do
|
137
|
-
rule :foo do
|
138
|
-
optional(skip(/\w+/))
|
139
|
-
end
|
140
|
-
end }
|
141
|
-
it { should compile(rules).test_parsing 'foo ' }
|
142
|
-
it { should compile(rules).test_parsing ' ' }
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
########## zero-or-more ##########
|
147
|
-
context 'given a zero-or-more rule' do
|
148
|
-
let(:rules) { define_parser do
|
149
|
-
rule :foo do
|
150
|
-
zero_or_more(/\w+/)
|
151
|
-
end
|
152
|
-
end }
|
153
|
-
it { should compile(rules).test_parsing 'foo ' }
|
154
|
-
it { should compile(rules).test_parsing ' ' }
|
155
|
-
|
156
|
-
context 'with a non-capturing parser' do
|
157
|
-
let(:rules) { define_parser do
|
158
|
-
rule :foo do
|
159
|
-
zero_or_more(skip(/\w+/))
|
160
|
-
end
|
161
|
-
end }
|
162
|
-
it { should compile(rules).test_parsing 'foo ' }
|
163
|
-
it { should compile(rules).test_parsing ' ' }
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
########## one-or-more ##########
|
168
|
-
context 'given a one-or-more rule' do
|
169
|
-
let(:rules) { define_parser do
|
170
|
-
rule :foo do
|
171
|
-
one_or_more(/\w+/)
|
172
|
-
end
|
173
|
-
end }
|
174
|
-
it { should compile(rules).test_parsing 'foo ' }
|
175
|
-
it { should compile(rules).test_parsing ' ' }
|
176
|
-
|
177
|
-
context 'with a non-capturing parser' do
|
178
|
-
let(:rules) { define_parser do
|
179
|
-
rule :foo do
|
180
|
-
one_or_more(skip(/\w+/))
|
181
|
-
end
|
182
|
-
end }
|
183
|
-
it { should compile(rules).test_parsing 'foo ' }
|
184
|
-
it { should compile(rules).test_parsing ' ' }
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
########## list ##########
|
189
|
-
context 'given a list rule' do
|
190
|
-
let(:rules) { define_parser do
|
191
|
-
rule :foo do
|
192
|
-
list(/\w+/, /[,;]/)
|
193
|
-
end
|
194
|
-
end }
|
195
|
-
it { should compile(rules).test_parsing ' ' }
|
196
|
-
it { should compile(rules).test_parsing 'foo ' }
|
197
|
-
it { should compile(rules).test_parsing 'foo,bar;baz ' }
|
198
|
-
it { should compile(rules).test_parsing 'foo,bar, ' }
|
199
|
-
|
200
|
-
context 'with a non-capturing parser' do
|
201
|
-
let(:rules) { define_parser do
|
202
|
-
rule :foo do
|
203
|
-
list(skip(/\w+/), /[,;]/)
|
204
|
-
end
|
205
|
-
end }
|
206
|
-
it { should compile(rules).test_parsing ' ' }
|
207
|
-
it { should compile(rules).test_parsing 'foo ' }
|
208
|
-
it { should compile(rules).test_parsing 'foo,bar;baz ' }
|
209
|
-
it { should compile(rules).test_parsing 'foo,bar, ' }
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
########## list1 ##########
|
214
|
-
context 'given a list1 rule' do
|
215
|
-
let(:rules) { define_parser do
|
216
|
-
rule :foo do
|
217
|
-
list1(/\w+/, /[,;]/)
|
218
|
-
end
|
219
|
-
end }
|
220
|
-
it { should compile(rules).test_parsing ' ' }
|
221
|
-
it { should compile(rules).test_parsing 'foo ' }
|
222
|
-
it { should compile(rules).test_parsing 'foo,bar;baz ' }
|
223
|
-
it { should compile(rules).test_parsing 'foo,bar, ' }
|
224
|
-
|
225
|
-
context 'with a non-capturing parser' do
|
226
|
-
let(:rules) { define_parser do
|
227
|
-
rule :foo do
|
228
|
-
list(skip(/\w+/), /[,;]/)
|
229
|
-
end
|
230
|
-
end }
|
231
|
-
it { should compile(rules).test_parsing ' ' }
|
232
|
-
it { should compile(rules).test_parsing 'foo ' }
|
233
|
-
it { should compile(rules).test_parsing 'foo,bar;baz ' }
|
234
|
-
it { should compile(rules).test_parsing 'foo,bar, ' }
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
########## apply ##########
|
239
|
-
context 'given an apply rule' do
|
240
|
-
let(:rules) { define_parser do
|
241
|
-
rule(:digit) { match /\d/ }
|
242
|
-
rule(:foo) { match :digit }
|
243
|
-
end }
|
244
|
-
it { should compile(rules).test_parsing('451 ').twice.as :foo }
|
245
|
-
it { should compile(rules).test_parsing 'hi' }
|
246
|
-
end
|
247
|
-
|
248
|
-
########## assert ##########
|
249
|
-
context 'given an assert rule' do
|
250
|
-
|
251
|
-
context 'with a nested match rule' do
|
252
|
-
let(:rules) { define_parser do
|
253
|
-
rule(:word) { assert /\w+/ }
|
254
|
-
end }
|
255
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
256
|
-
it { should compile(rules).test_parsing ' ' }
|
257
|
-
end
|
258
|
-
|
259
|
-
context 'with a nested choice rule' do
|
260
|
-
let(:rules) { define_parser do
|
261
|
-
rule(:word) { assert(match(/[[:alpha:]]+/) | match(/[[:digit:]]+/)) }
|
262
|
-
end }
|
263
|
-
it { should compile(rules).test_parsing('abc123 ').twice }
|
264
|
-
it { should compile(rules).test_parsing ' ' }
|
265
|
-
end
|
266
|
-
|
267
|
-
context 'with a nested sequence rule' do
|
268
|
-
let(:rules) { define_parser do
|
269
|
-
rule(:word) { assert(match(/[[:alpha:]]+/) & match(/[[:digit:]]+/)) }
|
270
|
-
end }
|
271
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
272
|
-
it { should compile(rules).test_parsing ' ' }
|
273
|
-
end
|
274
|
-
|
275
|
-
context 'with a nested optional rule' do
|
276
|
-
let(:rules) { define_parser do
|
277
|
-
rule(:word) { assert(optional(/\w+/)) }
|
278
|
-
end }
|
279
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
280
|
-
it { should compile(rules).test_parsing ' ' }
|
281
|
-
end
|
282
|
-
|
283
|
-
context 'with a nested zero_or_more rule' do
|
284
|
-
let(:rules) { define_parser do
|
285
|
-
rule(:word) { assert(zero_or_more(/\w/)) }
|
286
|
-
end }
|
287
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
288
|
-
it { should compile(rules).test_parsing ' ' }
|
289
|
-
end
|
290
|
-
|
291
|
-
context 'with a nested one_or_more rule' do
|
292
|
-
let(:rules) { define_parser do
|
293
|
-
rule(:word) { assert(one_or_more(/\w/)) }
|
294
|
-
end }
|
295
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
296
|
-
it { should compile(rules).test_parsing ' ' }
|
297
|
-
end
|
298
|
-
|
299
|
-
context 'with a nested list rule' do
|
300
|
-
let(:rules) { define_parser do
|
301
|
-
rule(:word) { assert(list(/\w+/, /,/)) }
|
302
|
-
end }
|
303
|
-
it { should compile(rules).test_parsing 'abc,123 ' }
|
304
|
-
it { should compile(rules).test_parsing ' ' }
|
305
|
-
end
|
306
|
-
|
307
|
-
context 'with a nested list1 rule' do
|
308
|
-
let(:rules) { define_parser do
|
309
|
-
rule(:word) { assert(list(/\w+/, /,/)) }
|
310
|
-
end }
|
311
|
-
it { should compile(rules).test_parsing 'abc,123 ' }
|
312
|
-
it { should compile(rules).test_parsing ' ' }
|
313
|
-
end
|
314
|
-
|
315
|
-
context 'with a nested apply rule' do
|
316
|
-
let(:rules) { define_parser do
|
317
|
-
rule(:word) { assert /\w+/ }
|
318
|
-
rule(:foo) { match :word }
|
319
|
-
end }
|
320
|
-
it { should compile(rules).test_parsing('abc123 ').as :foo }
|
321
|
-
it { should compile(rules).test_parsing ' ' }
|
322
|
-
end
|
323
|
-
|
324
|
-
context 'with a nested dispatch-action rule' do
|
325
|
-
let(:rules) { define_parser do
|
326
|
-
rule(:word) { assert(dispatch_action(/\w+/)) }
|
327
|
-
end }
|
328
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
329
|
-
it { should compile(rules).test_parsing ' ' }
|
330
|
-
end
|
331
|
-
|
332
|
-
context 'with a nested token rule' do
|
333
|
-
let(:rules) { define_parser do
|
334
|
-
rule(:word) { assert(token(match(/\w+/))) }
|
335
|
-
end }
|
336
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
337
|
-
it { should compile(rules).test_parsing ' ' }
|
338
|
-
end
|
339
|
-
|
340
|
-
context 'with a nested skip rule' do
|
341
|
-
let(:rules) { define_parser do
|
342
|
-
rule(:word) { assert(skip(/\w+/)) }
|
343
|
-
end }
|
344
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
345
|
-
it { should compile(rules).test_parsing ' ' }
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
########## disallow ##########
|
350
|
-
context 'given a disallow rule' do
|
351
|
-
|
352
|
-
context 'with a nested match rule' do
|
353
|
-
let(:rules) { define_parser do
|
354
|
-
rule(:word) { disallow /\w+/ }
|
355
|
-
end }
|
356
|
-
it { should compile(rules).test_parsing ' ' }
|
357
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
358
|
-
end
|
359
|
-
|
360
|
-
context 'with a nested choice rule' do
|
361
|
-
let(:rules) { define_parser do
|
362
|
-
rule(:word) { disallow(match(/[[:alpha:]]/) | match(/[[:digit:]]/)) }
|
363
|
-
end }
|
364
|
-
it { should compile(rules).test_parsing('abc123 ').twice }
|
365
|
-
it { should compile(rules).test_parsing ' ' }
|
366
|
-
end
|
367
|
-
|
368
|
-
context 'with a nested sequence rule' do
|
369
|
-
let(:rules) { define_parser do
|
370
|
-
rule(:word) { disallow(match(/[[:alpha:]]/) & match(/[[:digit:]]/)) }
|
371
|
-
end }
|
372
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
373
|
-
it { should compile(rules).test_parsing ' ' }
|
374
|
-
end
|
375
|
-
|
376
|
-
context 'with a nested optional rule' do
|
377
|
-
let(:rules) { define_parser do
|
378
|
-
rule(:word) { disallow(optional(/\w+/)) }
|
379
|
-
end }
|
380
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
381
|
-
it { should compile(rules).test_parsing ' ' }
|
382
|
-
end
|
383
|
-
|
384
|
-
context 'with a nested zero_or_more rule' do
|
385
|
-
let(:rules) { define_parser do
|
386
|
-
rule(:word) { disallow(zero_or_more(/\w/)) }
|
387
|
-
end }
|
388
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
389
|
-
it { should compile(rules).test_parsing ' ' }
|
390
|
-
end
|
391
|
-
|
392
|
-
context 'with a nested one_or_more rule' do
|
393
|
-
let(:rules) { define_parser do
|
394
|
-
rule(:word) { disallow(one_or_more(/\w/)) }
|
395
|
-
end }
|
396
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
397
|
-
it { should compile(rules).test_parsing ' ' }
|
398
|
-
end
|
399
|
-
|
400
|
-
context 'with a nested apply rule' do
|
401
|
-
let(:rules) { define_parser do
|
402
|
-
rule(:word) { disallow /\w+/ }
|
403
|
-
rule(:foo) { match :word }
|
404
|
-
end }
|
405
|
-
it { should compile(rules).test_parsing ' ' }
|
406
|
-
it { should compile(rules).test_parsing('abc123 ').as :foo }
|
407
|
-
end
|
408
|
-
|
409
|
-
context 'with a nested token rule' do
|
410
|
-
let(:rules) { define_parser do
|
411
|
-
rule(:word) { disallow(token(match(/\w+/))) }
|
412
|
-
end }
|
413
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
414
|
-
it { should compile(rules).test_parsing ' ' }
|
415
|
-
end
|
416
|
-
|
417
|
-
context 'with a nested skip rule' do
|
418
|
-
let(:rules) { define_parser do
|
419
|
-
rule(:word) { disallow(skip(/\w+/)) }
|
420
|
-
end }
|
421
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
422
|
-
it { should compile(rules).test_parsing ' ' }
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
########## dispatch_action ##########
|
427
|
-
context 'given a dispatch-action rule' do
|
428
|
-
|
429
|
-
context 'with a nested match rule' do
|
430
|
-
let(:rules) { define_parser do
|
431
|
-
rule(:digits) { dispatch_action(/\d+/) }
|
432
|
-
end }
|
433
|
-
it { should compile(rules).test_parsing '451a' }
|
434
|
-
it { should compile(rules).test_parsing ' ' }
|
435
|
-
end
|
436
|
-
|
437
|
-
context 'with a nested choice rule' do
|
438
|
-
let(:rules) { define_parser do
|
439
|
-
rule :atom do
|
440
|
-
dispatch_action(match(/[[:alpha:]]+/) | match(/[[:digit:]]+/))
|
441
|
-
end
|
442
|
-
end }
|
443
|
-
|
444
|
-
it { should compile(rules).test_parsing '451a' }
|
445
|
-
it { should compile(rules).test_parsing ' ' }
|
446
|
-
|
447
|
-
context 'with labels' do
|
448
|
-
let(:rules) { define_parser do
|
449
|
-
rule :assignment do
|
450
|
-
dispatch_action(
|
451
|
-
label(:word, /[[:alpha:]]+/) |
|
452
|
-
label(:num, /[[:digit:]]+/)
|
453
|
-
)
|
454
|
-
end
|
455
|
-
end }
|
456
|
-
it { should compile(rules).test_parsing 'foo ' }
|
457
|
-
it { should compile(rules).test_parsing '42 ' }
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
context 'with a nested sequence rule' do
|
462
|
-
let(:rules) { define_parser do
|
463
|
-
rule :assignment do
|
464
|
-
dispatch_action(
|
465
|
-
match(/[[:alpha:]]+/) &
|
466
|
-
match('=') &
|
467
|
-
match(/[[:digit:]]+/)
|
468
|
-
)
|
469
|
-
end
|
470
|
-
end }
|
471
|
-
|
472
|
-
it { should compile(rules).test_parsing 'val=42 ' }
|
473
|
-
it { should compile(rules).test_parsing 'val=x' }
|
474
|
-
|
475
|
-
context 'with labels' do
|
476
|
-
let(:rules) { define_parser do
|
477
|
-
rule :assignment do
|
478
|
-
dispatch_action(
|
479
|
-
label(:name, /[[:alpha:]]+/) &
|
480
|
-
match('=') &
|
481
|
-
label(:value, /[[:digit:]]+/)
|
482
|
-
)
|
483
|
-
end
|
484
|
-
end }
|
485
|
-
it { should compile(rules).test_parsing 'val=42 ' }
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
|
-
context 'with a nested optional rule' do
|
490
|
-
let(:rules) { define_parser do
|
491
|
-
rule :foo do
|
492
|
-
dispatch_action(optional(/\w+/))
|
493
|
-
end
|
494
|
-
end }
|
495
|
-
it { should compile(rules).test_parsing 'foo ' }
|
496
|
-
it { should compile(rules).test_parsing ' ' }
|
497
|
-
end
|
498
|
-
|
499
|
-
context 'with a nested zero-or-more rule' do
|
500
|
-
let(:rules) { define_parser do
|
501
|
-
rule :foo do
|
502
|
-
dispatch_action(zero_or_more(/\w/))
|
503
|
-
end
|
504
|
-
end }
|
505
|
-
it { should compile(rules).test_parsing 'foo ' }
|
506
|
-
it { should compile(rules).test_parsing ' ' }
|
507
|
-
end
|
508
|
-
|
509
|
-
context 'with a nested one-or-more rule' do
|
510
|
-
let(:rules) { define_parser do
|
511
|
-
rule :foo do
|
512
|
-
dispatch_action(one_or_more(/\w/))
|
513
|
-
end
|
514
|
-
end }
|
515
|
-
it { should compile(rules).test_parsing 'foo ' }
|
516
|
-
it { should compile(rules).test_parsing ' ' }
|
517
|
-
end
|
518
|
-
|
519
|
-
context 'with a nested apply rule' do
|
520
|
-
let(:rules) { define_parser do
|
521
|
-
rule(:digit) { match /\d/ }
|
522
|
-
rule(:foo) { dispatch_action :digit }
|
523
|
-
end }
|
524
|
-
it { should compile(rules).test_parsing('451a').twice.as :foo }
|
525
|
-
it { should compile(rules).test_parsing(' ').as :foo }
|
526
|
-
end
|
527
|
-
|
528
|
-
context 'with a nested token rule' do
|
529
|
-
let(:rules) { define_parser do
|
530
|
-
rule :foo do
|
531
|
-
dispatch_action(token(match(/\w+/)))
|
532
|
-
end
|
533
|
-
end }
|
534
|
-
it { should compile(rules).test_parsing 'abc123' }
|
535
|
-
it { should compile(rules).test_parsing ' ' }
|
536
|
-
end
|
537
|
-
|
538
|
-
context 'with a nested skip rule' do
|
539
|
-
let(:rules) { define_parser do
|
540
|
-
rule :foo do
|
541
|
-
dispatch_action(skip(/\w+/))
|
542
|
-
end
|
543
|
-
end }
|
544
|
-
it { should compile(rules).test_parsing 'abc123' }
|
545
|
-
it { should compile(rules).test_parsing ' ' }
|
546
|
-
end
|
547
|
-
end
|
548
|
-
|
549
|
-
########## direct_action ##########
|
550
|
-
context 'given a direct-action rule' do
|
551
|
-
|
552
|
-
context 'with a nested match rule' do
|
553
|
-
let(:rules) { define_parser do
|
554
|
-
rule(:num) { direct_action(/\d+/, '|_| _.to_i') }
|
555
|
-
end }
|
556
|
-
it { should compile(rules).test_parsing '451a' }
|
557
|
-
it { should compile(rules).test_parsing ' ' }
|
558
|
-
end
|
559
|
-
|
560
|
-
context 'with a nested choice rule' do
|
561
|
-
let(:rules) { define_parser do
|
562
|
-
rule :foo do
|
563
|
-
direct_action(
|
564
|
-
match(/[[:alpha:]]+/) | match(/[[:digit:]]+/),
|
565
|
-
'|_| _.size'
|
566
|
-
)
|
567
|
-
end
|
568
|
-
end }
|
569
|
-
|
570
|
-
it { should compile(rules).test_parsing 'abc123' }
|
571
|
-
it { should compile(rules).test_parsing '451a' }
|
572
|
-
it { should compile(rules).test_parsing ' ' }
|
573
|
-
end
|
574
|
-
|
575
|
-
context 'with a nested sequence rule' do
|
576
|
-
let(:rules) { define_parser do
|
577
|
-
rule :assignment do
|
578
|
-
direct_action(
|
579
|
-
match(/[[:alpha:]]+/) & match('=') & match(/[[:digit:]]+/),
|
580
|
-
'|l,_,r| "#{r} -> #{l}"'
|
581
|
-
)
|
582
|
-
end
|
583
|
-
end }
|
584
|
-
|
585
|
-
it { should compile(rules).test_parsing 'val=42 ' }
|
586
|
-
it { should compile(rules).test_parsing 'val=x' }
|
587
|
-
|
588
|
-
context 'with labels' do
|
589
|
-
let(:rules) { define_parser do
|
590
|
-
rule :assignment do
|
591
|
-
direct_action(
|
592
|
-
label(:name, /[[:alpha:]]+/) & match('=') & label(:value, /[[:digit:]]+/),
|
593
|
-
'"#{value} -> #{name}"'
|
594
|
-
)
|
595
|
-
end
|
596
|
-
end }
|
597
|
-
it { should compile(rules).test_parsing 'val=42 ' }
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
context 'with a nested optional rule' do
|
602
|
-
let(:rules) { define_parser do
|
603
|
-
rule :foo do
|
604
|
-
direct_action(optional(/\w+/), '|_| _.size')
|
605
|
-
end
|
606
|
-
end }
|
607
|
-
it { should compile(rules).test_parsing 'foo ' }
|
608
|
-
it { should compile(rules).test_parsing ' ' }
|
609
|
-
end
|
610
|
-
|
611
|
-
context 'with a nested zero-or-more rule' do
|
612
|
-
let(:rules) { define_parser do
|
613
|
-
rule :foo do
|
614
|
-
direct_action(zero_or_more(/\w/), '|_| _.size')
|
615
|
-
end
|
616
|
-
end }
|
617
|
-
it { should compile(rules).test_parsing 'foo ' }
|
618
|
-
it { should compile(rules).test_parsing ' ' }
|
619
|
-
end
|
620
|
-
|
621
|
-
context 'with a nested one-or-more rule' do
|
622
|
-
let(:rules) { define_parser do
|
623
|
-
rule :foo do
|
624
|
-
direct_action(one_or_more(/\w/), '|_| _.size')
|
625
|
-
end
|
626
|
-
end }
|
627
|
-
it { should compile(rules).test_parsing 'foo ' }
|
628
|
-
it { should compile(rules).test_parsing ' ' }
|
629
|
-
end
|
630
|
-
|
631
|
-
context 'with a nested apply rule' do
|
632
|
-
let(:rules) { define_parser do
|
633
|
-
rule(:digit) { match /\d/ }
|
634
|
-
rule(:foo) { direct_action :digit, '|_| _.to_i' }
|
635
|
-
end }
|
636
|
-
it { should compile(rules).test_parsing('451a').twice.as :foo }
|
637
|
-
it { should compile(rules).test_parsing(' ').as :foo }
|
638
|
-
end
|
639
|
-
|
640
|
-
context 'with a nested token rule' do
|
641
|
-
let(:rules) { define_parser do
|
642
|
-
rule :foo do
|
643
|
-
direct_action(token(/\w+/), '|_| _.size')
|
644
|
-
end
|
645
|
-
end }
|
646
|
-
it { should compile(rules).test_parsing 'abc123' }
|
647
|
-
it { should compile(rules).test_parsing ' ' }
|
648
|
-
end
|
649
|
-
|
650
|
-
context 'with a nested skip rule' do
|
651
|
-
let(:rules) { define_parser do
|
652
|
-
rule :foo do
|
653
|
-
direct_action(skip(/\w+/), '42' )
|
654
|
-
end
|
655
|
-
end }
|
656
|
-
it { should compile(rules).test_parsing 'abc123' }
|
657
|
-
it { should compile(rules).test_parsing ' ' }
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
########## token ##########
|
662
|
-
context 'given a token rule' do
|
663
|
-
|
664
|
-
context 'with a nested match rule' do
|
665
|
-
let(:rules) { define_parser do
|
666
|
-
rule(:digits) { token(match(/\d+/)) }
|
667
|
-
end }
|
668
|
-
it { should compile(rules).test_parsing '451a' }
|
669
|
-
it { should compile(rules).test_parsing 'hi' }
|
670
|
-
end
|
671
|
-
|
672
|
-
context 'with a nested choice rule' do
|
673
|
-
let(:rules) { define_parser do
|
674
|
-
rule(:atom) do
|
675
|
-
token(match(/[[:alpha:]]+/) | match(/[[:digit:]]+/))
|
676
|
-
end
|
677
|
-
end }
|
678
|
-
|
679
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
680
|
-
it { should compile(rules).test_parsing '==' }
|
681
|
-
|
682
|
-
context 'with non-capturing choices' do
|
683
|
-
let(:rules) { define_parser do
|
684
|
-
rule(:atom) do
|
685
|
-
token(skip(/[[:alpha:]]+/) | match(/[[:digit:]]+/))
|
686
|
-
end
|
687
|
-
end }
|
688
|
-
it { should compile(rules).test_parsing 'abc123 ' }
|
689
|
-
it { should compile(rules).test_parsing '==' }
|
690
|
-
end
|
691
|
-
end
|
692
|
-
|
693
|
-
context 'with a nested sequence rule' do
|
694
|
-
let(:rules) { define_parser do
|
695
|
-
rule(:atom) do
|
696
|
-
token(match(/[[:alpha:]]+/) & match(/[[:digit:]]+/))
|
697
|
-
end
|
698
|
-
end }
|
699
|
-
|
700
|
-
it { should compile(rules).test_parsing 'foo42!' }
|
701
|
-
it { should compile(rules).test_parsing 'val=x' }
|
702
|
-
|
703
|
-
context 'with non-capturing parsers' do
|
704
|
-
let(:rules) { define_parser do
|
705
|
-
rule :foo do
|
706
|
-
token(match(/[[:alpha:]]+/) & skip(/\s+/) & match(/[[:digit:]]+/))
|
707
|
-
end
|
708
|
-
end }
|
709
|
-
it { should compile(rules).test_parsing 'foo 42' }
|
710
|
-
it { should compile(rules).test_parsing 'foo bar' }
|
711
|
-
end
|
712
|
-
end
|
713
|
-
|
714
|
-
context 'with a nested optional rule' do
|
715
|
-
let(:rules) { define_parser do
|
716
|
-
rule :foo do
|
717
|
-
token(optional(/\w+/))
|
718
|
-
end
|
719
|
-
end }
|
720
|
-
|
721
|
-
it { should compile(rules).test_parsing 'foo ' }
|
722
|
-
it { should compile(rules).test_parsing ' ' }
|
723
|
-
|
724
|
-
context 'with a non-capturing rule' do
|
725
|
-
let(:rules) { define_parser do
|
726
|
-
rule :foo do
|
727
|
-
token(optional(skip(/\w+/)))
|
728
|
-
end
|
729
|
-
end }
|
730
|
-
it { should compile(rules).test_parsing 'foo ' }
|
731
|
-
it { should compile(rules).test_parsing ' ' }
|
732
|
-
end
|
733
|
-
end
|
734
|
-
|
735
|
-
context 'with a nested zero-or-more rule' do
|
736
|
-
let(:rules) { define_parser do
|
737
|
-
rule :foo do
|
738
|
-
token(zero_or_more(/\w/))
|
739
|
-
end
|
740
|
-
end }
|
741
|
-
|
742
|
-
it { should compile(rules).test_parsing 'foo ' }
|
743
|
-
it { should compile(rules).test_parsing ' ' }
|
744
|
-
|
745
|
-
context 'with a non-capturing rule' do
|
746
|
-
let(:rules) { define_parser do
|
747
|
-
rule :foo do
|
748
|
-
token(zero_or_more(skip(/\w/)))
|
749
|
-
end
|
750
|
-
end }
|
751
|
-
it { should compile(rules).test_parsing 'foo ' }
|
752
|
-
it { should compile(rules).test_parsing ' ' }
|
753
|
-
end
|
754
|
-
end
|
755
|
-
|
756
|
-
context 'with a nested one-or-more rule' do
|
757
|
-
let(:rules) { define_parser do
|
758
|
-
rule :foo do
|
759
|
-
token(one_or_more(/\w/))
|
760
|
-
end
|
761
|
-
end }
|
762
|
-
|
763
|
-
it { should compile(rules).test_parsing 'foo ' }
|
764
|
-
it { should compile(rules).test_parsing ' ' }
|
765
|
-
|
766
|
-
context 'with a non-capturing rule' do
|
767
|
-
let(:rules) { define_parser do
|
768
|
-
rule :foo do
|
769
|
-
token(one_or_more(skip(/\w/)))
|
770
|
-
end
|
771
|
-
end }
|
772
|
-
it { should compile(rules).test_parsing 'foo ' }
|
773
|
-
it { should compile(rules).test_parsing ' ' }
|
774
|
-
end
|
775
|
-
end
|
776
|
-
|
777
|
-
context 'with a nested apply rule' do
|
778
|
-
let(:rules) { define_parser do
|
779
|
-
rule(:digits) { match(/\d+/) }
|
780
|
-
rule(:foo) { token(match(:digits)) }
|
781
|
-
end }
|
782
|
-
|
783
|
-
it { should compile(rules).test_parsing('451a').as :foo }
|
784
|
-
it { should compile(rules).test_parsing 'hi' }
|
785
|
-
|
786
|
-
context 'applying a non-capturing rule' do
|
787
|
-
let(:rules) { define_parser do
|
788
|
-
rule(:digits) { skip(/\d+/) }
|
789
|
-
rule(:foo) { token(match(:digits)) }
|
790
|
-
end }
|
791
|
-
it { should compile(rules).test_parsing('451a').as :foo }
|
792
|
-
it { should compile(rules).test_parsing 'hi' }
|
793
|
-
end
|
794
|
-
end
|
795
|
-
|
796
|
-
context 'with a nested dispatch-action rule' do
|
797
|
-
let(:rules) { define_parser do
|
798
|
-
rule(:foo) { token(dispatch_action(/\w+/)) }
|
799
|
-
end }
|
800
|
-
it { should compile(rules).test_parsing 'abc123' }
|
801
|
-
it { should compile(rules).test_parsing ' ' }
|
802
|
-
end
|
803
|
-
|
804
|
-
context 'with a nested skip rule' do
|
805
|
-
let(:rules) { define_parser do
|
806
|
-
rule(:foo) { token(skip(/\w+/)) }
|
807
|
-
end }
|
808
|
-
it { should compile(rules).test_parsing 'abc123' }
|
809
|
-
it { should compile(rules).test_parsing ' ' }
|
810
|
-
end
|
811
|
-
end
|
812
|
-
|
813
|
-
########## skip ##########
|
814
|
-
context 'given a skip rule' do
|
815
|
-
|
816
|
-
context 'with a nested match rule' do
|
817
|
-
let(:rules) { define_parser do
|
818
|
-
rule(:ws) { skip(/\s+/) }
|
819
|
-
end }
|
820
|
-
it { should compile(rules).test_parsing ' foo' }
|
821
|
-
it { should compile(rules).test_parsing 'hi' }
|
822
|
-
end
|
823
|
-
|
824
|
-
context 'with a nested choice rule' do
|
825
|
-
let(:rules) { define_parser do
|
826
|
-
rule(:ws) do
|
827
|
-
skip(match(/\s+/) | match(/\#[^\n]*/))
|
828
|
-
end
|
829
|
-
end }
|
830
|
-
it { should compile(rules).test_parsing(' # hi there ').twice }
|
831
|
-
it { should compile(rules).test_parsing 'hi' }
|
832
|
-
end
|
833
|
-
|
834
|
-
context 'with a nested sequence rule' do
|
835
|
-
let(:rules) { define_parser do
|
836
|
-
rule :foo do
|
837
|
-
skip(match(/[[:alpha:]]+/) & match(/[[:digit:]]+/))
|
838
|
-
end
|
839
|
-
end }
|
840
|
-
it { should compile(rules).test_parsing 'foo42!' }
|
841
|
-
it { should compile(rules).test_parsing 'val=x' }
|
842
|
-
end
|
843
|
-
|
844
|
-
context 'with a nested optional rule' do
|
845
|
-
let(:rules) { define_parser do
|
846
|
-
rule :foo do
|
847
|
-
skip(optional(/\w+/))
|
848
|
-
end
|
849
|
-
end }
|
850
|
-
it { should compile(rules).test_parsing 'foo ' }
|
851
|
-
it { should compile(rules).test_parsing ' ' }
|
852
|
-
end
|
853
|
-
|
854
|
-
context 'with a nested zero-or-more rule' do
|
855
|
-
let(:rules) { define_parser do
|
856
|
-
rule :foo do
|
857
|
-
skip(zero_or_more(/\w/))
|
858
|
-
end
|
859
|
-
end }
|
860
|
-
it { should compile(rules).test_parsing 'foo ' }
|
861
|
-
it { should compile(rules).test_parsing ' ' }
|
862
|
-
end
|
863
|
-
|
864
|
-
context 'with a nested one-or-more rule' do
|
865
|
-
let(:rules) { define_parser do
|
866
|
-
rule :foo do
|
867
|
-
skip(one_or_more(/\w/))
|
868
|
-
end
|
869
|
-
end }
|
870
|
-
it { should compile(rules).test_parsing 'foo ' }
|
871
|
-
it { should compile(rules).test_parsing ' ' }
|
872
|
-
end
|
873
|
-
|
874
|
-
context 'with a nested apply rule' do
|
875
|
-
let(:rules) { define_parser do
|
876
|
-
rule(:digits) { match(/\d+/) }
|
877
|
-
rule(:foo) { skip(:digits) }
|
878
|
-
end }
|
879
|
-
it { should compile(rules).test_parsing('451a').as :foo }
|
880
|
-
it { should compile(rules).test_parsing('hi').as :foo }
|
881
|
-
end
|
882
|
-
end
|
883
|
-
|
884
30
|
end
|
885
31
|
|
886
32
|
def have_method(rule_name)
|