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