srl_ruby 0.4.4 → 0.4.8

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