srl_ruby 0.4.5 → 0.4.9

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 (58) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +298 -23
  3. data/CHANGELOG.md +41 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +1 -1
  7. data/Rakefile +3 -0
  8. data/appveyor.yml +14 -12
  9. data/bin/srl2ruby +13 -9
  10. data/bin/srl2ruby_cli_parser.rb +3 -3
  11. data/features/lib/step_definitions/srl_testing_steps.rb +2 -0
  12. data/features/lib/support/env..rb +2 -0
  13. data/lib/regex/abstract_method.rb +2 -0
  14. data/lib/regex/alternation.rb +3 -3
  15. data/lib/regex/anchor.rb +3 -0
  16. data/lib/regex/atomic_expression.rb +2 -0
  17. data/lib/regex/capturing_group.rb +8 -3
  18. data/lib/regex/char_class.rb +4 -2
  19. data/lib/regex/char_range.rb +3 -3
  20. data/lib/regex/char_shorthand.rb +3 -0
  21. data/lib/regex/character.rb +5 -2
  22. data/lib/regex/compound_expression.rb +2 -0
  23. data/lib/regex/concatenation.rb +3 -1
  24. data/lib/regex/expression.rb +6 -1
  25. data/lib/regex/lookaround.rb +3 -1
  26. data/lib/regex/match_option.rb +2 -0
  27. data/lib/regex/monadic_expression.rb +2 -0
  28. data/lib/regex/multiplicity.rb +8 -9
  29. data/lib/regex/non_capturing_group.rb +3 -1
  30. data/lib/regex/polyadic_expression.rb +2 -0
  31. data/lib/regex/quantifiable.rb +3 -1
  32. data/lib/regex/raw_expression.rb +2 -0
  33. data/lib/regex/repetition.rb +2 -0
  34. data/lib/regex/wildcard.rb +2 -5
  35. data/lib/srl_ruby/ast_builder.rb +81 -121
  36. data/lib/srl_ruby/grammar.rb +80 -92
  37. data/lib/srl_ruby/regex_repr.rb +2 -0
  38. data/lib/srl_ruby/tokenizer.rb +10 -4
  39. data/lib/srl_ruby/version.rb +3 -1
  40. data/lib/srl_ruby.rb +2 -0
  41. data/spec/acceptance/srl_test_suite_spec.rb +2 -0
  42. data/spec/acceptance/support/rule_file_ast_builder.rb +2 -0
  43. data/spec/acceptance/support/rule_file_grammar.rb +7 -5
  44. data/spec/acceptance/support/rule_file_nodes.rb +2 -0
  45. data/spec/acceptance/support/rule_file_parser.rb +2 -0
  46. data/spec/acceptance/support/rule_file_tokenizer.rb +10 -3
  47. data/spec/regex/atomic_expression_spec.rb +2 -0
  48. data/spec/regex/character_spec.rb +16 -6
  49. data/spec/regex/match_option_spec.rb +2 -0
  50. data/spec/regex/monadic_expression_spec.rb +2 -0
  51. data/spec/regex/multiplicity_spec.rb +4 -0
  52. data/spec/regex/repetition_spec.rb +2 -0
  53. data/spec/spec_helper.rb +2 -0
  54. data/spec/srl_ruby/srl_ruby_spec.rb +2 -0
  55. data/spec/srl_ruby/tokenizer_spec.rb +2 -0
  56. data/spec/srl_ruby_spec.rb +8 -6
  57. data/srl_ruby.gemspec +6 -4
  58. metadata +13 -14
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringio'
2
4
  require_relative 'regex_repr'
3
5
 
@@ -66,6 +68,8 @@ module SrlRuby
66
68
  return Regex::Multiplicity.new(lowerBound, upperBound, :greedy)
67
69
  end
68
70
 
71
+ # rubocop: disable Style/OptionalBooleanParameter
72
+
69
73
  def string_literal(aString, to_escape = true)
70
74
  if aString.size > 1
71
75
  chars = []
@@ -86,6 +90,7 @@ module SrlRuby
86
90
 
87
91
  return result
88
92
  end
93
+ # rubocop: enable Style/OptionalBooleanParameter
89
94
 
90
95
  def char_range(lowerBound, upperBound)
91
96
  lower = Regex::Character.new(lowerBound)
@@ -113,71 +118,52 @@ module SrlRuby
113
118
  Regex::Anchor.new('^')
114
119
  end
115
120
 
116
- # rule('expression' => %w[pattern flags]).as 'flagged_expr'
121
+ # rule('expression' => 'pattern (flags)?').tag 'flagged_expr'
117
122
  def reduce_flagged_expr(_production, aRange, theTokens, theChildren)
118
- @options = theChildren[1] if theChildren[1]
123
+ @options = theChildren[1].first if theChildren[1]
119
124
  return_first_child(aRange, theTokens, theChildren)
120
125
  end
121
126
 
122
- # rule('pattern' => %w[pattern separator sub_pattern]).as 'pattern_sequence'
127
+ # rule('pattern' => 'subpattern (separator sub_pattern)*').tag 'pattern_sequence'
123
128
  def reduce_pattern_sequence(_production, _range, _tokens, theChildren)
124
- third_member = theChildren[2]
125
- if third_member.kind_of?(Regex::Lookaround) && third_member.dir == :behind
126
- Regex::Concatenation.new(theChildren[2], theChildren[0])
129
+ return theChildren[0] if theChildren[1].empty?
130
+
131
+ successors = theChildren[1].map { |pair| pair[1] }
132
+ if successors[0].kind_of?(Regex::Lookaround) && successors[0].dir == :behind
133
+ Regex::Concatenation.new(successors.shift, theChildren[0], *successors)
127
134
  else
128
- Regex::Concatenation.new(theChildren[0], theChildren[2])
135
+ Regex::Concatenation.new(theChildren[0], *successors)
129
136
  end
130
-
131
- end
132
-
133
- # rule('pattern' => 'sub_pattern').as 'basic_pattern'
134
- def reduce_basic_pattern(_production, aRange, theTokens, theChildren)
135
- return_first_child(aRange, theTokens, theChildren)
136
137
  end
137
138
 
138
- # rule('sub_pattern' => 'assertion').as 'assertion_sub_pattern'
139
+ # rule('sub_pattern' => 'assertion').tag 'assertion_sub_pattern'
139
140
  def reduce_assertion_sub_pattern(_production, aRange, theTokens, theChildren)
140
141
  return_first_child(aRange, theTokens, theChildren)
141
142
  end
142
143
 
143
- # rule('flags' => %[flags separator single_flag]).as 'flag_sequence'
144
+ # rule('flags' => '(separator single_flag)+').tag 'flag_sequence'
144
145
  def reduce_flag_sequence(_production, _range, _tokens, theChildren)
145
- theChildren[0] << theChildren[2]
146
+ theChildren[0].map { |(_, flag)| flag }
146
147
  end
147
148
 
148
- # rule('flags' => %w[separator single_flag]).as 'flag_simple'
149
- def reduce_flag_simple(_production, _range, _tokens, theChildren)
150
- [theChildren.last]
151
- end
152
-
153
- # rule('single_flag' => %w[CASE INSENSITIVE]).as 'case_insensitive'
149
+ # rule('single_flag' => %w[CASE INSENSITIVE]).tag 'case_insensitive'
154
150
  def reduce_case_insensitive(_production, _range, _tokens, _children)
155
151
  Regexp::IGNORECASE
156
152
  end
157
153
 
158
- # rule('single_flag' => %w[MULTI LINE]).as 'multi_line'
154
+ # rule('single_flag' => %w[MULTI LINE]).tag 'multi_line'
159
155
  def reduce_multi_line(_production, _range, _tokens, _children)
160
156
  Regexp::MULTILINE
161
157
  end
162
158
 
163
- # rule('single_flag' => %w[ALL LAZY]).as 'all_lazy'
159
+ # rule('single_flag' => %w[ALL LAZY]).tag 'all_lazy'
164
160
  def reduce_all_lazy(_production, _range, _tokens, _children)
165
161
  :ALL_LAZY
166
162
  end
167
163
 
168
- # rule 'quantifiable' => %w[begin_anchor anchorable end_anchor]
169
- def reduce_pinned_quantifiable(_production, _range, _tokens, theChildren)
170
- Regex::Concatenation.new(*theChildren)
171
- end
172
-
173
- # rule 'quantifiable' => %w[begin_anchor anchorable]
174
- def reduce_begin_anchor_quantifiable(_production, _range, _tokens, theChildren)
175
- Regex::Concatenation.new(*theChildren)
176
- end
177
-
178
- # rule 'quantifiable' => %w[anchorable end_anchor]
179
- def reduce_end_anchor_quantifiable(_production, _range, _tokens, theChildren)
180
- return Regex::Concatenation.new(*theChildren)
164
+ # rule('quantifiable' => 'begin_anchor? anchorable end_anchor?')
165
+ def reduce_quantifiable(_production, _range, _tokens, theChildren)
166
+ Regex::Concatenation.new(*theChildren.flatten.compact)
181
167
  end
182
168
 
183
169
  # rule 'begin_anchor' => %w[STARTS WITH]
@@ -190,39 +176,30 @@ module SrlRuby
190
176
  begin_anchor
191
177
  end
192
178
 
193
- # rule('end_anchor' => %w[separator MUST END]).as 'end_anchor'
179
+ # rule('end_anchor' => %w[separator MUST END]).tag 'end_anchor'
194
180
  def reduce_end_anchor(_production, _range, _tokens, _children)
195
181
  Regex::Anchor.new('$')
196
182
  end
197
183
 
198
- # rule('assertion' => %w[IF FOLLOWED BY assertable]).as 'if_followed'
184
+ # rule('assertion' => 'IF NOT? FOLLOWED BY assertable')
199
185
  def reduce_if_followed(_production, _range, _tokens, theChildren)
200
- Regex::Lookaround.new(theChildren.last, :ahead, :positive)
201
- end
202
-
203
- # rule('assertion' => %w[IF NOT FOLLOWED BY assertable]).as 'if_not_followed'
204
- def reduce_if_not_followed(_production, _range, _tokens, theChildren)
205
- Regex::Lookaround.new(theChildren.last, :ahead, :negative)
186
+ polarity = theChildren[1] ? :negative : :positive
187
+ Regex::Lookaround.new(theChildren.last, :ahead, polarity)
206
188
  end
207
189
 
208
- # rule('assertion' => %w[IF ALREADY HAD assertable]).as 'if_had'
190
+ # rule('assertion' => 'IF NOT? ALREADY HAD assertable')
209
191
  def reduce_if_had(_production, _range, _tokens, theChildren)
210
- Regex::Lookaround.new(theChildren.last, :behind, :positive)
192
+ polarity = theChildren[1] ? :negative : :positive
193
+ Regex::Lookaround.new(theChildren.last, :behind, polarity)
211
194
  end
212
195
 
213
- # rule('assertion' => %w[IF NOT ALREADY HAD assertable]).as 'if_not_had'
214
- def reduce_if_not_had(_production, _range, _tokens, theChildren)
215
- Regex::Lookaround.new(theChildren.last, :behind, :negative)
196
+ # rule('assertable' => 'term quantifier?').tag 'assertable'
197
+ def reduce_assertable(_production, _range, _tokens, theChildren)
198
+ (term, quantifier) = theChildren.flatten
199
+ quantifier ? repetition(term, quantifier) : term
216
200
  end
217
201
 
218
- # rule('assertable' => %w[term quantifier]).as 'quantified_assertable'
219
- def reduce_quantified_assertable(_production, _range, _tokens, theChildren)
220
- quantifier = theChildren[1]
221
- term = theChildren[0]
222
- repetition(term, quantifier)
223
- end
224
-
225
- # rule('letter_range' => %w[LETTER FROM LETTER_LIT TO LETTER_LIT]).as 'lowercase_from_to'
202
+ # rule('letter_range' => %w[LETTER FROM LETTER_LIT TO LETTER_LIT]).tag 'lowercase_from_to'
226
203
  def reduce_lowercase_from_to(_production, _range, _tokens, theChildren)
227
204
  raw_range = [theChildren[2].token.lexeme, theChildren[4].token.lexeme]
228
205
  range_sorted = raw_range.sort
@@ -230,7 +207,7 @@ module SrlRuby
230
207
  char_class(false, ch_range)
231
208
  end
232
209
 
233
- # rule('letter_range' => %w[UPPERCASE LETTER FROM LETTER_LIT TO LETTER_LIT]).as 'uppercase_from_to'
210
+ # rule('letter_range' => %w[UPPERCASE LETTER FROM LETTER_LIT TO LETTER_LIT]).tag 'uppercase_from_to'
234
211
  def reduce_uppercase_from_to(_production, _range, _tokens, theChildren)
235
212
  raw_range = [theChildren[3].token.lexeme, theChildren[5].token.lexeme]
236
213
  range_sorted = raw_range.sort
@@ -238,19 +215,19 @@ module SrlRuby
238
215
  char_class(false, ch_range)
239
216
  end
240
217
 
241
- # rule('letter_range' => 'LETTER').as 'any_lowercase'
218
+ # rule('letter_range' => 'LETTER').tag 'any_lowercase'
242
219
  def reduce_any_lowercase(_production, _range, _tokens, _children)
243
220
  ch_range = char_range('a', 'z')
244
221
  char_class(false, ch_range)
245
222
  end
246
223
 
247
- # rule('letter_range' => %w[UPPERCASE LETTER]).as 'any_uppercase'
224
+ # rule('letter_range' => %w[UPPERCASE LETTER]).tag 'any_uppercase'
248
225
  def reduce_any_uppercase(_production, _range, _tokens, _children)
249
226
  ch_range = char_range('A', 'Z')
250
227
  char_class(false, ch_range)
251
228
  end
252
229
 
253
- # rule('digit_range' => %w[digit_or_number FROM DIGIT_LIT TO DIGIT_LIT]).as 'digits_from_to'
230
+ # rule('digit_range' => %w[digit_or_number FROM DIGIT_LIT TO DIGIT_LIT]).tag 'digits_from_to'
254
231
  def reduce_digits_from_to(_production, _range, _tokens, theChildren)
255
232
  raw_range = [theChildren[2].token.lexeme, theChildren[4].token.lexeme]
256
233
  range_sorted = raw_range.map(&:to_i).sort
@@ -258,42 +235,42 @@ module SrlRuby
258
235
  char_class(false, ch_range)
259
236
  end
260
237
 
261
- # rule('character_class' => %w[ANY CHARACTER]).as 'any_character'
238
+ # rule('character_class' => %w[ANY CHARACTER]).tag 'any_character'
262
239
  def reduce_any_character(_production, _range, _tokens, _children)
263
240
  char_shorthand('w')
264
241
  end
265
242
 
266
- # rule('character_class' => %w[NO CHARACTER]).as 'no_character'
243
+ # rule('character_class' => %w[NO CHARACTER]).tag 'no_character'
267
244
  def reduce_no_character(_production, _range, _tokens, _children)
268
245
  char_shorthand('W')
269
246
  end
270
247
 
271
- # rule('character_class' => 'digit_or_number').as 'digit'
248
+ # rule('character_class' => 'digit_or_number').tag 'digit'
272
249
  def reduce_digit(_production, _range, _tokens, _children)
273
250
  char_shorthand('d')
274
251
  end
275
252
 
276
- # rule('character_class' => %w[NO DIGIT]).as 'non_digit'
253
+ # rule('character_class' => %w[NO DIGIT]).tag 'non_digit'
277
254
  def reduce_non_digit(_production, _range, _tokens, _children)
278
255
  char_shorthand('D')
279
256
  end
280
257
 
281
- # rule('character_class' => 'WHITESPACE').as 'whitespace'
258
+ # rule('character_class' => 'WHITESPACE').tag 'whitespace'
282
259
  def reduce_whitespace(_production, _range, _tokens, _children)
283
260
  char_shorthand('s')
284
261
  end
285
262
 
286
- # rule('character_class' => %w[NO WHITESPACE]).as 'no_whitespace'
263
+ # rule('character_class' => %w[NO WHITESPACE]).tag 'no_whitespace'
287
264
  def reduce_no_whitespace(_production, _range, _tokens, _children)
288
265
  char_shorthand('S')
289
266
  end
290
267
 
291
- # rule('character_class' => 'ANYTHING').as 'anything'
268
+ # rule('character_class' => 'ANYTHING').tag 'anything'
292
269
  def reduce_anything(_production, _range, _tokens, _children)
293
270
  wildcard
294
271
  end
295
272
 
296
- # rule('character_class' => %w[ONE OF STRING_LIT]).as 'one_of'
273
+ # rule('character_class' => %w[ONE OF STRING_LIT]).tag 'one_of'
297
274
  def reduce_one_of(_production, _range, _tokens, theChildren)
298
275
  raw_literal = theChildren[-1].token.lexeme.dup
299
276
  alternatives = raw_literal.chars.map do |ch|
@@ -309,7 +286,7 @@ module SrlRuby
309
286
  return Regex::CharClass.new(false, *alternatives)
310
287
  end
311
288
 
312
- # rule('character_class' => %w[NONE OF STRING_LIT]).as 'none_of'
289
+ # rule('character_class' => %w[NONE OF STRING_LIT]).tag 'none_of'
313
290
  def reduce_none_of(_production, _range, _tokens, theChildren)
314
291
  raw_literal = theChildren[-1].token.lexeme.dup
315
292
  chars = raw_literal.chars.map do |ch|
@@ -318,44 +295,44 @@ module SrlRuby
318
295
  Regex::CharClass.new(true, *chars)
319
296
  end
320
297
 
321
- # rule('special_char' => 'TAB').as 'tab'
298
+ # rule('special_char' => 'TAB').tag 'tab'
322
299
  def reduce_tab(_production, _range, _tokens, _children)
323
300
  Regex::Character.new('\t')
324
301
  end
325
302
 
326
- # rule('special_char' => ' VERTICAL TAB').as 'vtab'
303
+ # rule('special_char' => ' VERTICAL TAB').tag 'vtab'
327
304
  def reduce_vtab(_production, _range, _tokens, _children)
328
305
  Regex::Character.new('\v')
329
306
  end
330
307
 
331
- # rule('special_char' => 'BACKSLASH').as 'backslash'
308
+ # rule('special_char' => 'BACKSLASH').tag 'backslash'
332
309
  def reduce_backslash(_production, _range, _tokens, _children)
333
310
  # Double the backslash (because of escaping)
334
311
  string_literal('\\', true)
335
312
  end
336
313
 
337
- # rule('special_char' => %w[NEW LINE]).as 'new_line'
314
+ # rule('special_char' => %w[NEW LINE]).tag 'new_line'
338
315
  def reduce_new_line(_production, _range, _tokens, _children)
339
316
  # TODO: control portability
340
317
  Regex::Character.new('\n')
341
318
  end
342
319
 
343
- # rule('special_char' => %w[CARRIAGE RETURN]).as 'carriage_return'
320
+ # rule('special_char' => %w[CARRIAGE RETURN]).tag 'carriage_return'
344
321
  def reduce_carriage_return(_production, _range, _tokens, _children)
345
322
  Regex::Character.new('\r')
346
323
  end
347
324
 
348
- # rule('special_char' => %w[WORD]).as 'word'
325
+ # rule('special_char' => %w[WORD]).tag 'word'
349
326
  def reduce_word(_production, _range, _tokens, _children)
350
327
  Regex::Anchor.new('\b')
351
328
  end
352
329
 
353
- # rule('special_char' => %w[NO WORD]).as 'no word'
330
+ # rule('special_char' => %w[NO WORD]).tag 'no word'
354
331
  def reduce_no_word(_production, _range, _tokens, _children)
355
332
  Regex::Anchor.new('\B')
356
333
  end
357
334
 
358
- # rule('literal' => %w[LITERALLY STRING_LIT]).as 'literally'
335
+ # rule('literal' => %w[LITERALLY STRING_LIT]).tag 'literally'
359
336
  def reduce_literally(_production, _range, _tokens, theChildren)
360
337
  # What if literal is empty?...
361
338
 
@@ -363,13 +340,13 @@ module SrlRuby
363
340
  return string_literal(raw_literal)
364
341
  end
365
342
 
366
- # rule('raw' => %w[RAW STRING_LIT]).as 'raw_literal'
343
+ # rule('raw' => %w[RAW STRING_LIT]).tag 'raw_literal'
367
344
  def reduce_raw_literal(_production, _range, _tokens, theChildren)
368
345
  raw_literal = theChildren[-1].token.lexeme.dup
369
346
  return Regex::RawExpression.new(raw_literal)
370
347
  end
371
348
 
372
- # rule('alternation' => %w[ANY OF LPAREN alternatives RPAREN]).as 'any_of'
349
+ # rule('alternation' => %w[ANY OF LPAREN alternatives RPAREN]).tag 'any_of'
373
350
  def reduce_any_of(_production, _range, _tokens, theChildren)
374
351
  first_alternative = theChildren[3].first
375
352
  result = nil
@@ -384,26 +361,21 @@ module SrlRuby
384
361
  return result
385
362
  end
386
363
 
387
- # rule('alternatives' => %w[alternatives separator quantifiable]).as 'alternative_list'
364
+ # rule('alternatives' => %w[alternatives separator quantifiable]).tag 'alternative_list'
388
365
  def reduce_alternative_list(_production, _range, _tokens, theChildren)
389
366
  return theChildren[0] << theChildren[-1]
390
367
  end
391
368
 
392
- # rule('alternatives' => 'quantifiable').as 'simple_alternative'
369
+ # rule('alternatives' => 'quantifiable').tag 'simple_alternative'
393
370
  def reduce_simple_alternative(_production, _range, _tokens, theChildren)
394
371
  [theChildren.last]
395
372
  end
396
373
 
397
- # rule('grouping' => %w[LPAREN pattern RPAREN]).as 'grouping_parenthenses'
374
+ # rule('grouping' => %w[LPAREN pattern RPAREN]).tag 'grouping_parenthenses'
398
375
  def reduce_grouping_parenthenses(_production, _range, _tokens, theChildren)
399
376
  Regex::NonCapturingGroup.new(theChildren[1])
400
377
  end
401
378
 
402
- # rule('capturing_group' => %w[CAPTURE assertable]).as 'capture'
403
- def reduce_capture(_production, _range, _tokens, theChildren)
404
- Regex::CapturingGroup.new(theChildren[1])
405
- end
406
-
407
379
  # If the rightmost (sub)expression is a repetition, then make it lazy
408
380
  def make_last_repetition_lazy(anExpr)
409
381
  sub_expr = anExpr
@@ -423,51 +395,49 @@ module SrlRuby
423
395
  end
424
396
  end
425
397
 
426
- # rule('capturing_group' => %w[CAPTURE assertable UNTIL assertable]).as
427
- # 'capture_until'
428
- def reduce_capture_until(_production, _range, _tokens, theChildren)
398
+ # rule('capturing_group' => 'CAPTURE assertable (UNTIL assertable)?').tag
399
+ # 'capture'
400
+ def reduce_capture(_production, _range, _tokens, theChildren)
401
+ return Regex::CapturingGroup.new(theChildren[1]) unless theChildren[2]
402
+
429
403
  # Until semantic requires that the last pattern in capture to be lazy
430
404
  make_last_repetition_lazy(theChildren[1])
431
405
 
432
406
  group = Regex::CapturingGroup.new(theChildren[1])
433
- return Regex::Concatenation.new(group, theChildren[3])
407
+ (_, until_expr) = theChildren[2]
408
+ Regex::Concatenation.new(group, until_expr)
434
409
  end
435
410
 
436
- # rule('capturing_group' => %w[CAPTURE assertable AS var_name]).as
437
- # 'named_capture'
411
+ # rule('capturing_group' => 'CAPTURE assertable AS var_name (UNTIL assertable)?').tag
412
+ # 'named_capture'
438
413
  def reduce_named_capture(_production, _range, _tokens, theChildren)
439
414
  name = theChildren[3].token.lexeme.dup
440
- return Regex::CapturingGroup.new(theChildren[1], name)
441
- end
415
+ return Regex::CapturingGroup.new(theChildren[1], name) unless theChildren[4]
442
416
 
443
- # rule('capturing_group' => %w[CAPTURE assertable AS var_name
444
- # UNTIL assertable]).as 'named_capture_until'
445
- def reduce_named_capture_until(_production, _range, _tokens, theChildren)
446
417
  # Until semantic requires that the last pattern in capture to be lazy
447
418
  make_last_repetition_lazy(theChildren[1])
448
-
449
- name = theChildren[3].token.lexeme.dup
450
419
  group = Regex::CapturingGroup.new(theChildren[1], name)
451
- return Regex::Concatenation.new(group, theChildren[5])
420
+ (_, until_expr) = theChildren[4]
421
+ return Regex::Concatenation.new(group, until_expr)
452
422
  end
453
423
 
454
- # rule('quantifier' => 'ONCE').as 'once'
424
+ # rule('quantifier' => 'ONCE').tag 'once'
455
425
  def reduce_once(_production, _range, _tokens, _children)
456
426
  multiplicity(1, 1)
457
427
  end
458
428
 
459
- # rule('quantifier' => 'TWICE').as 'twice'
429
+ # rule('quantifier' => 'TWICE').tag 'twice'
460
430
  def reduce_twice(_production, _range, _tokens, _children)
461
431
  multiplicity(2, 2)
462
432
  end
463
433
 
464
- # rule('quantifier' => %w[EXACTLY count TIMES]).as 'exactly'
434
+ # rule('quantifier' => %w[EXACTLY count TIMES]).tag 'exactly'
465
435
  def reduce_exactly(_production, _range, _tokens, theChildren)
466
436
  count = theChildren[1].token.lexeme.to_i
467
437
  multiplicity(count, count)
468
438
  end
469
439
 
470
- # rule('quantifier' => %w[BETWEEN count AND count times_suffix]).as
440
+ # rule('quantifier' => 'BETWEEN count AND count times_suffix').tag
471
441
  # 'between_and'
472
442
  def reduce_between_and(_production, _range, _tokens, theChildren)
473
443
  lower = theChildren[1].token.lexeme.to_i
@@ -475,36 +445,26 @@ module SrlRuby
475
445
  multiplicity(lower, upper)
476
446
  end
477
447
 
478
- # rule('quantifier' => 'OPTIONAL').as 'optional'
448
+ # rule('quantifier' => 'OPTIONAL').tag 'optional'
479
449
  def reduce_optional(_production, _range, _tokens, _children)
480
450
  multiplicity(0, 1)
481
451
  end
482
452
 
483
- # rule('quantifier' => %w[ONCE OR MORE]).as 'once_or_more'
453
+ # rule('quantifier' => %w[ONCE OR MORE]).tag 'once_or_more'
484
454
  def reduce_once_or_more(_production, _range, _tokens, _children)
485
455
  multiplicity(1, :more)
486
456
  end
487
457
 
488
- # rule('quantifier' => %w[NEVER OR MORE]).as 'never_or_more'
458
+ # rule('quantifier' => %w[NEVER OR MORE]).tag 'never_or_more'
489
459
  def reduce_never_or_more(_production, _range, _tokens, _children)
490
460
  multiplicity(0, :more)
491
461
  end
492
462
 
493
- # rule('quantifier' => %w[AT LEAST count TIMES]).as 'at_least'
463
+ # rule('quantifier' => %w[AT LEAST count TIMES]).tag 'at_least'
494
464
  def reduce_at_least(_production, _range, _tokens, theChildren)
495
465
  count = theChildren[2].token.lexeme.to_i
496
466
  multiplicity(count, :more)
497
467
  end
498
-
499
- # rule('times_suffix' => 'TIMES').as 'times_keyword'
500
- def reduce_times_keyword(_production, _range, _tokens, _children)
501
- nil
502
- end
503
-
504
- # rule('times_suffix' => []).as 'times_dropped'
505
- def reduce_times_dropped(_production, _range, _tokens, _children)
506
- nil
507
- end
508
468
  end # class
509
469
  end # module
510
470
  # End of file