regexp_parser 0.5.0 → 1.0.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +242 -0
  3. data/Gemfile +1 -0
  4. data/README.md +21 -17
  5. data/Rakefile +31 -0
  6. data/lib/regexp_parser/expression.rb +11 -9
  7. data/lib/regexp_parser/expression/classes/alternation.rb +5 -28
  8. data/lib/regexp_parser/expression/classes/backref.rb +21 -16
  9. data/lib/regexp_parser/expression/classes/escape.rb +81 -10
  10. data/lib/regexp_parser/expression/classes/group.rb +20 -20
  11. data/lib/regexp_parser/expression/classes/{character_class.rb → posix_class.rb} +2 -2
  12. data/lib/regexp_parser/expression/classes/property.rb +6 -0
  13. data/lib/regexp_parser/expression/classes/set.rb +10 -93
  14. data/lib/regexp_parser/expression/classes/set/intersection.rb +9 -0
  15. data/lib/regexp_parser/expression/classes/set/range.rb +23 -0
  16. data/lib/regexp_parser/expression/methods/strfregexp.rb +6 -4
  17. data/lib/regexp_parser/expression/methods/tests.rb +4 -14
  18. data/lib/regexp_parser/expression/methods/traverse.rb +1 -1
  19. data/lib/regexp_parser/expression/quantifier.rb +3 -4
  20. data/lib/regexp_parser/expression/sequence_operation.rb +34 -0
  21. data/lib/regexp_parser/expression/subexpression.rb +6 -10
  22. data/lib/regexp_parser/lexer.rb +13 -17
  23. data/lib/regexp_parser/parser.rb +170 -116
  24. data/lib/regexp_parser/scanner.rb +952 -2431
  25. data/lib/regexp_parser/scanner/char_type.rl +31 -0
  26. data/lib/regexp_parser/scanner/properties/long.yml +561 -0
  27. data/lib/regexp_parser/scanner/properties/short.yml +225 -0
  28. data/lib/regexp_parser/scanner/property.rl +7 -806
  29. data/lib/regexp_parser/scanner/scanner.rl +112 -154
  30. data/lib/regexp_parser/syntax/base.rb +4 -4
  31. data/lib/regexp_parser/syntax/tokens.rb +1 -0
  32. data/lib/regexp_parser/syntax/tokens/backref.rb +2 -2
  33. data/lib/regexp_parser/syntax/tokens/character_set.rb +3 -38
  34. data/lib/regexp_parser/syntax/tokens/escape.rb +2 -3
  35. data/lib/regexp_parser/syntax/tokens/group.rb +5 -4
  36. data/lib/regexp_parser/syntax/tokens/{character_class.rb → posix_class.rb} +5 -5
  37. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +519 -266
  38. data/lib/regexp_parser/syntax/versions/1.8.6.rb +2 -4
  39. data/lib/regexp_parser/syntax/versions/1.9.1.rb +4 -10
  40. data/lib/regexp_parser/syntax/versions/2.0.0.rb +0 -2
  41. data/lib/regexp_parser/syntax/versions/2.4.1.rb +1 -1
  42. data/lib/regexp_parser/version.rb +1 -1
  43. data/regexp_parser.gemspec +2 -1
  44. data/test/expression/test_base.rb +2 -1
  45. data/test/expression/test_clone.rb +0 -57
  46. data/test/expression/test_set.rb +31 -8
  47. data/test/expression/test_strfregexp.rb +13 -4
  48. data/test/expression/test_subexpression.rb +25 -0
  49. data/test/expression/test_traverse.rb +25 -25
  50. data/test/helpers.rb +1 -0
  51. data/test/lexer/test_all.rb +1 -1
  52. data/test/lexer/test_conditionals.rb +9 -7
  53. data/test/lexer/test_nesting.rb +39 -21
  54. data/test/lexer/test_refcalls.rb +4 -4
  55. data/test/parser/set/test_intersections.rb +127 -0
  56. data/test/parser/set/test_ranges.rb +111 -0
  57. data/test/parser/test_all.rb +4 -1
  58. data/test/parser/test_escapes.rb +41 -9
  59. data/test/parser/test_groups.rb +22 -3
  60. data/test/parser/test_posix_classes.rb +27 -0
  61. data/test/parser/test_properties.rb +17 -290
  62. data/test/parser/test_refcalls.rb +66 -26
  63. data/test/parser/test_sets.rb +132 -129
  64. data/test/scanner/test_all.rb +1 -7
  65. data/test/scanner/test_conditionals.rb +16 -16
  66. data/test/scanner/test_errors.rb +0 -30
  67. data/test/scanner/test_escapes.rb +1 -2
  68. data/test/scanner/test_free_space.rb +28 -28
  69. data/test/scanner/test_groups.rb +35 -35
  70. data/test/scanner/test_meta.rb +1 -1
  71. data/test/scanner/test_properties.rb +87 -114
  72. data/test/scanner/test_refcalls.rb +18 -18
  73. data/test/scanner/test_scripts.rb +19 -351
  74. data/test/scanner/test_sets.rb +87 -60
  75. data/test/scanner/test_unicode_blocks.rb +4 -105
  76. data/test/support/warning_extractor.rb +1 -1
  77. data/test/syntax/test_syntax.rb +7 -0
  78. data/test/syntax/versions/test_1.8.rb +2 -4
  79. metadata +17 -7
  80. data/ChangeLog +0 -325
  81. data/test/scanner/test_emojis.rb +0 -31
@@ -82,9 +82,8 @@ class TestParserGroups < Test::Unit::TestCase
82
82
  def test_parse_option_switch_group
83
83
  t = RP.parse(/a(?i-m)b/m, 'ruby/1.8')
84
84
 
85
- assert_equal Group::Options, t.expressions[1].class
86
- assert_equal :options, t.expressions[1].token
87
- # TODO: change this ^ to :options_switch in v1.0.0
85
+ assert_equal Group::Options, t.expressions[1].class
86
+ assert_equal :options_switch, t.expressions[1].token
88
87
 
89
88
  assert_equal false, t.expressions[1].m?
90
89
  assert_equal true, t.expressions[1].i?
@@ -245,4 +244,24 @@ class TestParserGroups < Test::Unit::TestCase
245
244
  end
246
245
  end
247
246
  end
247
+
248
+ def test_parse_group_number
249
+ t = RP.parse('(a)(?=b)((?:c)(d|(e)))')
250
+ assert_equal 1, t[0].number
251
+ assert_equal false, t[1].respond_to?(:number)
252
+ assert_equal 2, t[2].number
253
+ assert_equal false, t[2][0].respond_to?(:number)
254
+ assert_equal 3, t[2][1].number
255
+ assert_equal 4, t[2][1][0][1][0].number
256
+ end
257
+
258
+ def test_parse_group_number_at_level
259
+ t = RP.parse('(a)(?=b)((?:c)(d|(e)))')
260
+ assert_equal 1, t[0].number_at_level
261
+ assert_equal false, t[1].respond_to?(:number_at_level)
262
+ assert_equal 2, t[2].number_at_level
263
+ assert_equal false, t[2][0].respond_to?(:number_at_level)
264
+ assert_equal 1, t[2][1].number_at_level
265
+ assert_equal 1, t[2][1][0][1][0].number_at_level
266
+ end
248
267
  end
@@ -0,0 +1,27 @@
1
+ require File.expand_path("../../helpers", __FILE__)
2
+
3
+ class TestParserPosixClasses < Test::Unit::TestCase
4
+ def test_parse_posix_class
5
+ root = RP.parse('[[:word:]]')
6
+ exp = root[0][0]
7
+
8
+ assert_equal PosixClass, exp.class
9
+ assert_equal :posixclass, exp.type
10
+ assert_equal :word, exp.token
11
+ assert_equal 'word', exp.name
12
+ assert_equal '[:word:]', exp.text
13
+ refute exp.negative?
14
+ end
15
+
16
+ def test_parse_negative_posix_class
17
+ root = RP.parse('[[:^word:]]')
18
+ exp = root[0][0]
19
+
20
+ assert_equal PosixClass, exp.class
21
+ assert_equal :nonposixclass, exp.type
22
+ assert_equal :word, exp.token
23
+ assert_equal 'word', exp.name
24
+ assert_equal '[:^word:]', exp.text
25
+ assert exp.negative?
26
+ end
27
+ end
@@ -1,314 +1,28 @@
1
1
  require File.expand_path("../../helpers", __FILE__)
2
2
 
3
3
  class ParserProperties < Test::Unit::TestCase
4
-
5
4
  modes = ['p', 'P']
6
- props = [
5
+ example_props = [
7
6
  'Alnum',
8
- 'Alpha',
9
- 'Ascii',
10
- 'Blank',
11
- 'Cntrl',
12
- 'Digit',
13
- 'Graph',
14
- 'Lower',
15
- 'Print',
16
- 'Punct',
17
- 'Space',
18
- 'Upper',
19
- 'Word',
20
- 'Xdigit',
21
- 'XPosixPunct',
22
-
23
7
  'Any',
24
- 'Assigned',
25
-
26
- 'L',
27
- 'Letter',
28
-
29
- 'Lu',
30
- 'Uppercase_Letter',
31
-
32
- 'Ll',
33
- 'Lowercase_Letter',
34
-
35
- 'Lt',
36
- 'Titlecase_Letter',
37
-
38
- 'Lm',
39
- 'Modifier_Letter',
40
-
41
- 'Lo',
42
- 'Other_Letter',
43
-
44
- 'M',
45
- 'Mark',
46
-
47
- 'Mn',
48
- 'Nonspacing_Mark',
49
-
50
- 'Mc',
51
- 'Spacing_Mark',
52
-
53
- 'Me',
54
- 'Enclosing_Mark',
55
-
56
- 'N',
57
- 'Number',
58
-
59
- 'Nd',
60
- 'Decimal_Number',
61
-
62
- 'Nl',
63
- 'Letter_Number',
64
-
65
- 'No',
66
- 'Other_Number',
67
-
68
- 'P',
69
- 'Punctuation',
70
-
71
- 'Pc',
72
- 'Connector_Punctuation',
73
-
74
- 'Pd',
75
- 'Dash_Punctuation',
76
-
77
- 'Ps',
78
- 'Open_Punctuation',
79
-
80
- 'Pe',
81
- 'Close_Punctuation',
82
-
83
- 'Pi',
84
- 'Initial_Punctuation',
85
-
86
- 'Pf',
87
- 'Final_Punctuation',
88
-
89
- 'Po',
90
- 'Other_Punctuation',
91
-
92
- 'S',
93
- 'Symbol',
94
-
95
- 'Sm',
96
- 'Math_Symbol',
97
-
98
- 'Sc',
99
- 'Currency_Symbol',
100
-
101
- 'Sk',
102
- 'Modifier_Symbol',
103
-
104
- 'So',
105
- 'Other_Symbol',
106
-
107
- 'Z',
108
- 'Separator',
109
-
110
- 'Zs',
111
- 'Space_Separator',
112
-
113
- 'Zl',
114
- 'Line_Separator',
115
-
116
- 'Zp',
117
- 'Paragraph_Separator',
118
-
119
- 'C',
120
- 'Other',
121
-
122
- 'Cc',
123
- 'Control',
124
-
125
- 'Cf',
126
- 'Format',
127
-
128
- 'Cs',
129
- 'Surrogate',
130
-
131
- 'Co',
132
- 'Private_Use',
133
-
134
- 'Cn',
135
- 'Unassigned',
136
-
137
8
  'Age=1.1',
138
- 'Age=2.0',
139
- 'Age=2.1',
140
- 'Age=3.0',
141
- 'Age=3.1',
142
- 'Age=3.2',
143
- 'Age=4.0',
144
- 'Age=4.1',
145
- 'Age=5.0',
146
- 'Age=5.1',
147
- 'Age=5.2',
148
- 'Age=6.0',
149
- 'Age=7.0',
150
- 'Age=8.0',
151
- 'Age=9.0',
152
- 'Age=10.0',
153
-
154
- 'ahex',
155
- 'ASCII_Hex_Digit',
156
-
157
- 'Alphabetic',
158
-
159
- 'Cased',
160
-
161
- 'cwcf',
162
- 'Changes_When_Casefolded',
163
-
164
- 'cwcm',
165
- 'Changes_When_Casemapped',
166
-
167
- 'cwl',
168
- 'Changes_When_Lowercased',
169
-
170
- 'cwt',
171
- 'Changes_When_Titlecased',
172
-
173
- 'cwu',
174
- 'Changes_When_Uppercased',
175
-
176
- 'ci',
177
- 'Case_Ignorable',
178
-
179
- 'bidic',
180
- 'Bidi_Control',
181
-
182
9
  'Dash',
183
-
184
- 'dep',
185
- 'Deprecated',
186
-
187
10
  'di',
188
11
  'Default_Ignorable_Code_Point',
189
-
190
- 'dia',
191
- 'Diacritic',
192
-
193
- 'ext',
194
- 'Extender',
195
-
196
- 'grbase',
197
- 'Grapheme_Base',
198
-
199
- 'grext',
200
- 'Grapheme_Extend',
201
-
202
- 'grlink',
203
- 'Grapheme_Link',
204
-
205
- 'hex',
206
- 'Hex_Digit',
207
-
208
- 'Hyphen',
209
-
210
- 'idc',
211
- 'ID_Continue',
212
-
213
- 'ideo',
214
- 'Ideographic',
215
-
216
- 'ids',
217
- 'ID_Start',
218
-
219
- 'idsb',
220
- 'IDS_Binary_Operator',
221
-
222
- 'idst',
223
- 'IDS_Trinary_Operator',
224
-
225
- 'joinc',
226
- 'Join_Control',
227
-
228
- 'loe',
229
- 'Logical_Order_Exception',
230
-
231
- 'Lowercase',
232
-
233
12
  'Math',
234
-
235
- 'nchar',
236
- 'Noncharacter_Code_Point',
237
-
238
- 'oalpha',
239
- 'Other_Alphabetic',
240
-
241
- 'odi',
242
- 'Other_Default_Ignorable_Code_Point',
243
-
244
- 'ogrext',
245
- 'Other_Grapheme_Extend',
246
-
247
- 'oidc',
248
- 'Other_ID_Continue',
249
-
250
- 'oids',
251
- 'Other_ID_Start',
252
-
253
- 'olower',
254
- 'Other_Lowercase',
255
-
256
- 'omath',
257
- 'Other_Math',
258
-
259
- 'oupper',
260
- 'Other_Uppercase',
261
-
262
- 'patsyn',
263
- 'Pattern_Syntax',
264
-
265
- 'patws',
266
- 'Pattern_Whitespace',
267
-
268
- 'qmark',
269
- 'quotationmark',
270
-
271
- 'radical',
272
-
273
- 'ri',
274
- 'Regional_Indicator',
275
-
13
+ 'Noncharacter-Code_Point', # test dash
276
14
  'sd',
277
- 'Soft_Dotted',
278
-
15
+ 'Soft Dotted', # test whitespace
279
16
  'sterm',
280
-
281
- 'term',
282
- 'Terminal_Punctuation',
283
-
284
- 'uideo',
285
- 'Unified_Ideograph',
286
-
287
- 'Uppercase',
288
-
289
- 'vs',
290
- 'Variation_Selector',
291
-
292
- 'wspace',
293
- 'whitespace',
294
-
295
- 'xids',
296
- 'XID_Start',
297
-
298
17
  'xidc',
299
18
  'XID_Continue',
300
-
301
19
  'Emoji',
302
- 'Emoji_Component',
303
- 'Emoji_Modifier',
304
- 'Emoji_Modifier_Base',
305
- 'Emoji_Presentation',
306
20
  ]
307
21
 
308
22
  modes.each do |mode|
309
23
  token_type = mode == 'p' ? :property : :nonproperty
310
24
 
311
- props.each do |property|
25
+ example_props.each do |property|
312
26
  define_method "test_parse_#{token_type}_#{property}" do
313
27
  t = RP.parse "ab\\#{mode}{#{property}}", 'ruby/2.5'
314
28
 
@@ -321,6 +35,13 @@ class ParserProperties < Test::Unit::TestCase
321
35
  end
322
36
  end
323
37
 
38
+ def test_parse_all_properties_of_current_ruby
39
+ unsupported = RegexpPropertyValues.all_for_current_ruby.reject do |prop|
40
+ begin RP.parse("\\p{#{prop}}"); rescue SyntaxError, StandardError; nil end
41
+ end
42
+ assert_empty unsupported
43
+ end
44
+
324
45
  def test_parse_property_negative
325
46
  t = RP.parse 'ab\p{L}cd', 'ruby/1.9'
326
47
 
@@ -345,6 +66,12 @@ class ParserProperties < Test::Unit::TestCase
345
66
  assert_equal false, t.expressions[1].negative?
346
67
  end
347
68
 
69
+ def test_parse_property_shortcut
70
+ assert_equal 'm', RP.parse('\p{mark}').expressions[0].shortcut
71
+ assert_equal 'sc', RP.parse('\p{sc}').expressions[0].shortcut
72
+ assert_equal nil, RP.parse('\p{in_bengali}').expressions[0].shortcut
73
+ end
74
+
348
75
  def test_parse_property_age
349
76
  t = RP.parse 'ab\p{age=5.2}cd', 'ruby/1.9'
350
77
 
@@ -5,15 +5,15 @@ class TestParserRefcalls < Test::Unit::TestCase
5
5
  root = RP.parse('(abc)\1', 'ruby/1.9')
6
6
  exp = root.expressions.at(1)
7
7
 
8
- assert_equal true, exp.is_a?(Backreference::Number)
9
- assert_equal '1', exp.number
8
+ assert_instance_of Backreference::Number, exp
9
+ assert_equal 1, exp.number
10
10
  end
11
11
 
12
12
  def test_parse_backref_named_ab
13
13
  root = RP.parse('(?<X>abc)\k<X>', 'ruby/1.9')
14
14
  exp = root.expressions.at(1)
15
15
 
16
- assert_equal true, exp.is_a?(Backreference::Name)
16
+ assert_instance_of Backreference::Name, exp
17
17
  assert_equal 'X', exp.name
18
18
  end
19
19
 
@@ -21,7 +21,7 @@ class TestParserRefcalls < Test::Unit::TestCase
21
21
  root = RP.parse("(?<X>abc)\\k'X'", 'ruby/1.9')
22
22
  exp = root.expressions.at(1)
23
23
 
24
- assert_equal true, exp.is_a?(Backreference::Name)
24
+ assert_instance_of Backreference::Name, exp
25
25
  assert_equal 'X', exp.name
26
26
  end
27
27
 
@@ -29,102 +29,142 @@ class TestParserRefcalls < Test::Unit::TestCase
29
29
  root = RP.parse('(abc)\k<1>', 'ruby/1.9')
30
30
  exp = root.expressions.at(1)
31
31
 
32
- assert_equal true, exp.is_a?(Backreference::Number)
33
- assert_equal '1', exp.number
32
+ assert_instance_of Backreference::Number, exp
33
+ assert_equal 1, exp.number
34
34
  end
35
35
 
36
36
  def test_parse_backref_number_sq
37
37
  root = RP.parse("(abc)\\k'1'", 'ruby/1.9')
38
38
  exp = root.expressions.at(1)
39
39
 
40
- assert_equal true, exp.is_a?(Backreference::Number)
41
- assert_equal '1', exp.number
40
+ assert_instance_of Backreference::Number, exp
41
+ assert_equal 1, exp.number
42
42
  end
43
43
 
44
44
  def test_parse_backref_number_relative_ab
45
45
  root = RP.parse('(abc)\k<-1>', 'ruby/1.9')
46
46
  exp = root.expressions.at(1)
47
47
 
48
- assert_equal true, exp.is_a?(Backreference::NumberRelative)
49
- assert_equal '-1', exp.number
48
+ assert_instance_of Backreference::NumberRelative, exp
49
+ assert_equal(-1, exp.number)
50
50
  end
51
51
 
52
52
  def test_parse_backref_number_relative_sq
53
53
  root = RP.parse("(abc)\\k'-1'", 'ruby/1.9')
54
54
  exp = root.expressions.at(1)
55
55
 
56
- assert_equal true, exp.is_a?(Backreference::NumberRelative)
57
- assert_equal '-1', exp.number
56
+ assert_instance_of Backreference::NumberRelative, exp
57
+ assert_equal(-1, exp.number)
58
58
  end
59
59
 
60
60
  def test_parse_backref_name_call_ab
61
61
  root = RP.parse('(?<X>abc)\g<X>', 'ruby/1.9')
62
62
  exp = root.expressions.at(1)
63
63
 
64
- assert_equal true, exp.is_a?(Backreference::NameCall)
64
+ assert_instance_of Backreference::NameCall, exp
65
+ assert_equal 'X', exp.name
65
66
  end
66
67
 
67
68
  def test_parse_backref_name_call_sq
68
69
  root = RP.parse("(?<X>abc)\\g'X'", 'ruby/1.9')
69
70
  exp = root.expressions.at(1)
70
71
 
71
- assert_equal true, exp.is_a?(Backreference::NameCall)
72
+ assert_instance_of Backreference::NameCall, exp
73
+ assert_equal 'X', exp.name
72
74
  end
73
75
 
74
76
  def test_parse_backref_number_call_ab
75
77
  root = RP.parse('(abc)\g<1>', 'ruby/1.9')
76
78
  exp = root.expressions.at(1)
77
79
 
78
- assert_equal true, exp.is_a?(Backreference::NumberCall)
80
+ assert_instance_of Backreference::NumberCall, exp
81
+ assert_equal 1, exp.number
79
82
  end
80
83
 
81
84
  def test_parse_backref_number_call_sq
82
85
  root = RP.parse("(abc)\\g'1'", 'ruby/1.9')
83
86
  exp = root.expressions.at(1)
84
87
 
85
- assert_equal true, exp.is_a?(Backreference::NumberCall)
88
+ assert_instance_of Backreference::NumberCall, exp
89
+ assert_equal 1, exp.number
86
90
  end
87
91
 
88
92
  def test_parse_backref_number_relative_call_ab
89
93
  root = RP.parse('(abc)\g<-1>', 'ruby/1.9')
90
94
  exp = root.expressions.at(1)
91
95
 
92
- assert_equal true, exp.is_a?(Backreference::NumberCallRelative)
96
+ assert_instance_of Backreference::NumberCallRelative, exp
97
+ assert_equal(-1, exp.number)
93
98
  end
94
99
 
95
100
  def test_parse_backref_number_relative_call_sq
96
101
  root = RP.parse("(abc)\\g'-1'", 'ruby/1.9')
97
102
  exp = root.expressions.at(1)
98
103
 
99
- assert_equal true, exp.is_a?(Backreference::NumberCallRelative)
104
+ assert_instance_of Backreference::NumberCallRelative, exp
105
+ assert_equal(-1, exp.number)
100
106
  end
101
107
 
102
- def test_parse_backref_name_nest_level_ab
108
+ def test_parse_backref_name_recursion_level_ab
103
109
  root = RP.parse('(?<X>abc)\k<X-0>', 'ruby/1.9')
104
110
  exp = root.expressions.at(1)
105
111
 
106
- assert_equal true, exp.is_a?(Backreference::NameNestLevel)
112
+ assert_instance_of Backreference::NameRecursionLevel, exp
113
+ assert_equal 'X', exp.name
114
+ assert_equal 0, exp.recursion_level
107
115
  end
108
116
 
109
- def test_parse_backref_name_nest_level_sq
117
+ def test_parse_backref_name_recursion_level_sq
110
118
  root = RP.parse("(?<X>abc)\\k'X-0'", 'ruby/1.9')
111
119
  exp = root.expressions.at(1)
112
120
 
113
- assert_equal true, exp.is_a?(Backreference::NameNestLevel)
121
+ assert_instance_of Backreference::NameRecursionLevel, exp
122
+ assert_equal 'X', exp.name
123
+ assert_equal 0, exp.recursion_level
114
124
  end
115
125
 
116
- def test_parse_backref_number_nest_level_ab
126
+ def test_parse_backref_number_recursion_level_ab
117
127
  root = RP.parse('(abc)\k<1-0>', 'ruby/1.9')
118
128
  exp = root.expressions.at(1)
119
129
 
120
- assert_equal true, exp.is_a?(Backreference::NumberNestLevel)
130
+ assert_instance_of Backreference::NumberRecursionLevel, exp
131
+ assert_equal 1, exp.number
132
+ assert_equal 0, exp.recursion_level
121
133
  end
122
134
 
123
- def test_parse_backref_number_nest_level_sq
135
+ def test_parse_backref_number_recursion_level_sq
124
136
  root = RP.parse("(abc)\\k'1-0'", 'ruby/1.9')
125
137
  exp = root.expressions.at(1)
126
138
 
127
- assert_equal true, exp.is_a?(Backreference::NumberNestLevel)
139
+ assert_instance_of Backreference::NumberRecursionLevel, exp
140
+ assert_equal 1, exp.number
141
+ assert_equal 0, exp.recursion_level
142
+ end
143
+
144
+ def test_parse_backref_negative_number_recursion_level
145
+ root = RP.parse("(abc)\\k'-1+0'", 'ruby/1.9')
146
+ exp = root.expressions.at(1)
147
+
148
+ assert_instance_of Backreference::NumberRecursionLevel, exp
149
+ assert_equal(-1, exp.number)
150
+ assert_equal 0, exp.recursion_level
128
151
  end
129
152
 
153
+ def test_parse_backref_number_positive_recursion_level
154
+ root = RP.parse("(abc)\\k'1+1'", 'ruby/1.9')
155
+ exp = root.expressions.at(1)
156
+
157
+ assert_instance_of Backreference::NumberRecursionLevel, exp
158
+ assert_equal 1, exp.number
159
+ assert_equal 1, exp.recursion_level
160
+ end
161
+
162
+ def test_parse_backref_number_negative_recursion_level
163
+ root = RP.parse("(abc)\\k'1-1'", 'ruby/1.9')
164
+ exp = root.expressions.at(1)
165
+
166
+ assert_instance_of Backreference::NumberRecursionLevel, exp
167
+ assert_equal 1, exp.number
168
+ assert_equal(-1, exp.recursion_level)
169
+ end
130
170
  end