regexp_parser 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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