rattler 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. data/README.rdoc +57 -37
  2. data/features/command_line/dest_option.feature +8 -21
  3. data/features/command_line/lib_option.feature +37 -0
  4. data/features/command_line/parser_generator.feature +7 -4
  5. data/features/grammar/back_reference.feature +37 -0
  6. data/features/grammar/fail.feature +3 -3
  7. data/features/grammar/labels.feature +11 -3
  8. data/features/grammar/list_matching.feature +14 -5
  9. data/features/grammar/literal.feature +30 -4
  10. data/features/grammar/nonterminal.feature +1 -1
  11. data/features/grammar/ordered_choice.feature +2 -2
  12. data/features/grammar/skip_operator.feature +1 -1
  13. data/features/grammar/symantic_action.feature +7 -7
  14. data/features/grammar/whitespace.feature +2 -2
  15. data/features/step_definitions/grammar_steps.rb +2 -2
  16. data/lib/rattler/back_end.rb +1 -0
  17. data/lib/rattler/back_end/compiler.rb +19 -20
  18. data/lib/rattler/back_end/optimizer.rb +100 -0
  19. data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
  20. data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
  21. data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
  22. data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
  23. data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
  24. data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
  25. data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
  26. data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
  27. data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
  28. data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
  29. data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
  30. data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
  31. data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
  32. data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
  33. data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
  34. data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
  35. data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
  36. data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
  37. data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
  38. data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
  39. data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
  40. data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
  41. data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
  42. data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
  43. data/lib/rattler/back_end/parser_generator.rb +21 -14
  44. data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
  45. data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
  46. data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
  47. data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
  48. data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
  49. data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
  50. data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
  51. data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
  52. data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
  53. data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
  54. data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
  55. data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
  56. data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
  57. data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
  58. data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
  59. data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
  60. data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
  61. data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
  62. data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
  63. data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
  64. data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
  65. data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
  66. data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
  67. data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
  68. data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
  69. data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
  70. data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
  71. data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
  72. data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
  73. data/lib/rattler/grammar.rb +4 -3
  74. data/lib/rattler/grammar/analysis.rb +91 -0
  75. data/lib/rattler/grammar/grammar.rb +37 -25
  76. data/lib/rattler/grammar/grammar_parser.rb +19 -11
  77. data/lib/rattler/grammar/metagrammar.rb +569 -800
  78. data/lib/rattler/grammar/rattler.rtlr +162 -144
  79. data/lib/rattler/parsers.rb +5 -1
  80. data/lib/rattler/parsers/action_code.rb +29 -15
  81. data/lib/rattler/parsers/apply.rb +5 -5
  82. data/lib/rattler/parsers/assert.rb +4 -18
  83. data/lib/rattler/parsers/back_reference.rb +46 -0
  84. data/lib/rattler/parsers/choice.rb +6 -39
  85. data/lib/rattler/parsers/combinator_parser.rb +32 -0
  86. data/lib/rattler/parsers/combining.rb +3 -29
  87. data/lib/rattler/parsers/direct_action.rb +27 -30
  88. data/lib/rattler/parsers/disallow.rb +4 -18
  89. data/lib/rattler/parsers/dispatch_action.rb +30 -25
  90. data/lib/rattler/parsers/label.rb +9 -18
  91. data/lib/rattler/parsers/list.rb +3 -34
  92. data/lib/rattler/parsers/list1.rb +4 -36
  93. data/lib/rattler/parsers/list_parser.rb +64 -0
  94. data/lib/rattler/parsers/match.rb +7 -42
  95. data/lib/rattler/parsers/node_code.rb +44 -0
  96. data/lib/rattler/parsers/one_or_more.rb +7 -27
  97. data/lib/rattler/parsers/optional.rb +5 -25
  98. data/lib/rattler/parsers/parser.rb +16 -44
  99. data/lib/rattler/parsers/parser_dsl.rb +13 -3
  100. data/lib/rattler/parsers/predicate.rb +4 -12
  101. data/lib/rattler/parsers/rule.rb +18 -19
  102. data/lib/rattler/parsers/rule_set.rb +63 -0
  103. data/lib/rattler/parsers/sequence.rb +12 -46
  104. data/lib/rattler/parsers/skip.rb +12 -26
  105. data/lib/rattler/parsers/token.rb +6 -21
  106. data/lib/rattler/parsers/zero_or_more.rb +6 -26
  107. data/lib/rattler/runner.rb +66 -28
  108. data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
  109. data/lib/rattler/runtime/packrat_parser.rb +17 -21
  110. data/lib/rattler/runtime/parser.rb +12 -2
  111. data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
  112. data/lib/rattler/util.rb +2 -1
  113. data/lib/rattler/util/graphviz.rb +29 -0
  114. data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
  115. data/lib/rattler/util/graphviz/node_builder.rb +84 -0
  116. data/lib/rattler/util/node.rb +37 -19
  117. data/lib/rattler/util/parser_spec_helper.rb +61 -35
  118. data/spec/rattler/back_end/compiler_spec.rb +6 -860
  119. data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
  120. data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
  121. data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
  122. data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
  123. data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
  124. data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
  125. data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
  126. data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
  127. data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
  128. data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
  129. data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
  130. data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
  131. data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
  132. data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
  133. data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
  134. data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
  135. data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
  136. data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
  137. data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
  138. data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
  139. data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
  140. data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
  141. data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
  142. data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
  143. data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
  144. data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
  145. data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
  146. data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
  147. data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
  148. data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
  149. data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
  150. data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
  151. data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
  152. data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
  153. data/spec/rattler/grammar/analysis_spec.rb +167 -0
  154. data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
  155. data/spec/rattler/grammar/grammar_spec.rb +24 -21
  156. data/spec/rattler/parsers/action_code_spec.rb +64 -19
  157. data/spec/rattler/parsers/apply_spec.rb +9 -9
  158. data/spec/rattler/parsers/back_reference_spec.rb +38 -0
  159. data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
  160. data/spec/rattler/parsers/direct_action_spec.rb +16 -2
  161. data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
  162. data/spec/rattler/parsers/fail_spec.rb +6 -4
  163. data/spec/rattler/parsers/label_spec.rb +10 -28
  164. data/spec/rattler/parsers/node_code_spec.rb +48 -0
  165. data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
  166. data/spec/rattler/parsers/rule_set_spec.rb +35 -0
  167. data/spec/rattler/parsers/sequence_spec.rb +15 -24
  168. data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
  169. data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
  170. data/spec/rattler/runtime/parse_node_spec.rb +15 -19
  171. data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
  172. data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
  173. data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
  174. data/spec/rattler/util/node_spec.rb +92 -65
  175. data/spec/rattler_spec.rb +16 -16
  176. data/spec/support/combinator_parser_spec_helper.rb +19 -18
  177. data/spec/support/compiler_spec_helper.rb +56 -87
  178. data/spec/support/runtime_parser_spec_helper.rb +6 -14
  179. metadata +117 -22
  180. data/features/grammar/regex.feature +0 -24
  181. data/lib/rattler/parsers/match_joining.rb +0 -67
  182. 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
- subject { described_class }
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(:rules) { define_parser do
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, rules) }
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)