regexp_parser 1.5.0 → 1.5.1

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/lib/regexp_parser/expression.rb +6 -43
  4. data/lib/regexp_parser/expression/classes/conditional.rb +3 -2
  5. data/lib/regexp_parser/expression/classes/escape.rb +0 -4
  6. data/lib/regexp_parser/expression/methods/match.rb +13 -0
  7. data/lib/regexp_parser/expression/methods/options.rb +35 -0
  8. data/lib/regexp_parser/expression/methods/strfregexp.rb +0 -1
  9. data/lib/regexp_parser/expression/methods/tests.rb +6 -15
  10. data/lib/regexp_parser/expression/sequence.rb +3 -2
  11. data/lib/regexp_parser/expression/sequence_operation.rb +2 -6
  12. data/lib/regexp_parser/lexer.rb +0 -21
  13. data/lib/regexp_parser/parser.rb +22 -21
  14. data/lib/regexp_parser/scanner.rb +1159 -1329
  15. data/lib/regexp_parser/scanner/char_type.rl +0 -3
  16. data/lib/regexp_parser/scanner/scanner.rl +82 -190
  17. data/lib/regexp_parser/version.rb +1 -1
  18. data/spec/expression/base_spec.rb +14 -0
  19. data/spec/expression/methods/match_length_spec.rb +13 -0
  20. data/spec/expression/methods/match_spec.rb +25 -0
  21. data/spec/expression/methods/tests_spec.rb +2 -0
  22. data/spec/expression/options_spec.rb +128 -0
  23. data/spec/expression/root_spec.rb +9 -0
  24. data/spec/expression/sequence_spec.rb +9 -0
  25. data/spec/lexer/conditionals_spec.rb +49 -119
  26. data/spec/lexer/escapes_spec.rb +8 -32
  27. data/spec/lexer/keep_spec.rb +5 -17
  28. data/spec/lexer/literals_spec.rb +73 -110
  29. data/spec/lexer/nesting_spec.rb +86 -117
  30. data/spec/lexer/refcalls_spec.rb +51 -50
  31. data/spec/parser/all_spec.rb +13 -1
  32. data/spec/parser/anchors_spec.rb +9 -23
  33. data/spec/parser/conditionals_spec.rb +9 -9
  34. data/spec/parser/errors_spec.rb +22 -43
  35. data/spec/parser/escapes_spec.rb +33 -44
  36. data/spec/parser/groups_spec.rb +98 -257
  37. data/spec/parser/keep_spec.rb +2 -15
  38. data/spec/parser/posix_classes_spec.rb +5 -24
  39. data/spec/parser/properties_spec.rb +42 -54
  40. data/spec/parser/quantifiers_spec.rb +41 -283
  41. data/spec/parser/refcalls_spec.rb +60 -185
  42. data/spec/parser/set/intersections_spec.rb +17 -17
  43. data/spec/parser/set/ranges_spec.rb +17 -17
  44. data/spec/parser/sets_spec.rb +5 -5
  45. data/spec/parser/types_spec.rb +11 -36
  46. data/spec/scanner/anchors_spec.rb +13 -28
  47. data/spec/scanner/conditionals_spec.rb +121 -173
  48. data/spec/scanner/errors_spec.rb +65 -87
  49. data/spec/scanner/escapes_spec.rb +49 -50
  50. data/spec/scanner/free_space_spec.rb +102 -165
  51. data/spec/scanner/groups_spec.rb +45 -64
  52. data/spec/scanner/keep_spec.rb +5 -28
  53. data/spec/scanner/literals_spec.rb +45 -81
  54. data/spec/scanner/meta_spec.rb +13 -33
  55. data/spec/scanner/properties_spec.rb +43 -286
  56. data/spec/scanner/quantifiers_spec.rb +13 -28
  57. data/spec/scanner/refcalls_spec.rb +32 -48
  58. data/spec/scanner/sets_spec.rb +88 -102
  59. data/spec/scanner/types_spec.rb +10 -25
  60. data/spec/spec_helper.rb +1 -0
  61. data/spec/support/shared_examples.rb +77 -0
  62. data/spec/syntax/syntax_spec.rb +4 -0
  63. data/spec/syntax/versions/1.8.6_spec.rb +12 -33
  64. data/spec/syntax/versions/1.9.1_spec.rb +5 -18
  65. data/spec/syntax/versions/1.9.3_spec.rb +4 -17
  66. data/spec/syntax/versions/2.0.0_spec.rb +8 -23
  67. data/spec/syntax/versions/2.2.0_spec.rb +4 -17
  68. data/spec/syntax/versions/aliases_spec.rb +25 -109
  69. metadata +14 -6
  70. data/spec/scanner/scripts_spec.rb +0 -49
  71. data/spec/scanner/unicode_blocks_spec.rb +0 -28
@@ -1,5 +1,5 @@
1
1
  class Regexp
2
2
  class Parser
3
- VERSION = '1.5.0'
3
+ VERSION = '1.5.1'
4
4
  end
5
5
  end
@@ -77,4 +77,18 @@ RSpec.describe(Regexp::Expression::Base) do
77
77
  expect([root[2][1].coded_offset, root[2][1].to_s]).to eq ['@6+4', '(c?)']
78
78
  expect([root[2][1][0].coded_offset, root[2][1][0].to_s]).to eq ['@7+2', 'c?']
79
79
  end
80
+
81
+ specify('#quantity') do
82
+ expect(RP.parse(/aa/)[0].quantity).to eq [nil, nil]
83
+ expect(RP.parse(/a?/)[0].quantity).to eq [0, 1]
84
+ expect(RP.parse(/a*/)[0].quantity).to eq [0, -1]
85
+ expect(RP.parse(/a+/)[0].quantity).to eq [1, -1]
86
+ end
87
+
88
+ specify('#repetitions') do
89
+ expect(RP.parse(/aa/)[0].repetitions).to eq 1..1
90
+ expect(RP.parse(/a?/)[0].repetitions).to eq 0..1
91
+ expect(RP.parse(/a*/)[0].repetitions).to eq 0..(Float::INFINITY)
92
+ expect(RP.parse(/a+/)[0].repetitions).to eq 1..(Float::INFINITY)
93
+ end
80
94
  end
@@ -30,6 +30,12 @@ RSpec.describe(Regexp::MatchLength) do
30
30
  specify('absence group') { expect(ML.of('(?~abc)').minmax).to eq [0, Float::INFINITY] }
31
31
  end
32
32
 
33
+ specify('raises for missing references') do
34
+ exp = RP.parse(/(a)\1/).last
35
+ exp.referenced_expression = nil
36
+ expect { exp.match_length }.to raise_error(ArgumentError)
37
+ end
38
+
33
39
  describe('::of') do
34
40
  it('works with Regexps') { expect(ML.of(/foo/).minmax).to eq [3, 3] }
35
41
  it('works with Strings') { expect(ML.of('foo').minmax).to eq [3, 3] }
@@ -138,4 +144,11 @@ RSpec.describe(Regexp::MatchLength) do
138
144
  expect(ML.of(/a*/).endless_each.first(3000).size).to eq 3000
139
145
  end
140
146
  end
147
+
148
+ describe('#inspect') do
149
+ it 'is nice' do
150
+ result = RP.parse(/a{2,4}/)[0].match_length
151
+ expect(result.inspect).to eq '#<Regexp::MatchLength<Literal> min=2 max=4>'
152
+ end
153
+ end
141
154
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Expression#match') do
4
+ it 'returns the #match result of the respective Regexp' do
5
+ expect(RP.parse(/a/).match('a')[0]).to eq 'a'
6
+ end
7
+
8
+ it 'can be given an offset, just like Regexp#match' do
9
+ expect(RP.parse(/./).match('ab', 1)[0]).to eq 'b'
10
+ end
11
+
12
+ it 'works with the #=~ alias' do
13
+ expect(RP.parse(/a/) =~ 'a').to be_a MatchData
14
+ end
15
+ end
16
+
17
+ RSpec.describe('Expression#match?') do
18
+ it 'returns true if the Respective Regexp matches' do
19
+ expect(RP.parse(/a/).match?('a')).to be true
20
+ end
21
+
22
+ it 'returns false if the Respective Regexp does not match' do
23
+ expect(RP.parse(/a/).match?('b')).to be false
24
+ end
25
+ end
@@ -93,5 +93,7 @@ RSpec.describe('ExpressionTests') do
93
93
  expect(seq_2.last.one_of?(meta: [:*], anchor: :eos)).to be true
94
94
  expect(seq_2.last.one_of?(meta: [:*], anchor: [:bos])).to be false
95
95
  expect(seq_2.last.one_of?(meta: [:*], anchor: %i[bos eos])).to be true
96
+
97
+ expect { root.one_of?(Object.new) }.to raise_error(ArgumentError)
96
98
  end
97
99
  end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Expression#options') do
4
+ it 'returns a hash of options/flags that affect the expression' do
5
+ exp = RP.parse(/a/ix)[0]
6
+ expect(exp).to be_a Literal
7
+ expect(exp.options).to eq(i: true, x: true)
8
+ end
9
+
10
+ it 'includes options that are locally enabled via special groups' do
11
+ exp = RP.parse(/(?x)(?m:a)/i)[1][0]
12
+ expect(exp).to be_a Literal
13
+ expect(exp.options).to eq(i: true, m: true, x: true)
14
+ end
15
+
16
+ it 'excludes locally disabled options' do
17
+ exp = RP.parse(/(?x)(?-im:a)/i)[1][0]
18
+ expect(exp).to be_a Literal
19
+ expect(exp.options).to eq(x: true)
20
+ end
21
+
22
+ it 'gives correct precedence to negative options' do
23
+ # Negative options have precedence. E.g. /(?i-i)a/ is case-sensitive.
24
+ regexp = /(?i-i:a)/
25
+ expect(regexp).to match 'a'
26
+ expect(regexp).not_to match 'A'
27
+
28
+ exp = RP.parse(regexp)[0][0]
29
+ expect(exp).to be_a Literal
30
+ expect(exp.options).to eq({})
31
+ end
32
+
33
+ it 'correctly handles multiple negative option parts' do
34
+ regexp = /(?--m--mx--) . /mx
35
+ expect(regexp).to match ' . '
36
+ expect(regexp).not_to match '.'
37
+ expect(regexp).not_to match "\n"
38
+
39
+ exp = RP.parse(regexp)[2]
40
+ expect(exp.options).to eq({})
41
+ end
42
+
43
+ it 'gives correct precedence when encountering multiple encoding flags' do
44
+ # Any encoding flag overrides all previous encoding flags. If there are
45
+ # multiple encoding flags in an options string, the last one wins.
46
+ # E.g. /(?dau)\w/ matches UTF8 chars but /(?dua)\w/ only ASCII chars.
47
+ regexp1 = /(?dau)\w/
48
+ regexp2 = /(?dua)\w/
49
+ expect(regexp1).to match 'ü'
50
+ expect(regexp2).not_to match 'ü'
51
+
52
+ exp1 = RP.parse(regexp1)[1]
53
+ exp2 = RP.parse(regexp2)[1]
54
+ expect(exp1.options).to eq(u: true)
55
+ expect(exp2.options).to eq(a: true)
56
+ end
57
+
58
+ it 'is accessible via shortcuts' do
59
+ exp = Root.build
60
+
61
+ expect { exp.options[:i] = true }
62
+ .to change { exp.i? }.from(false).to(true)
63
+ .and change { exp.ignore_case? }.from(false).to(true)
64
+ .and change { exp.case_insensitive? }.from(false).to(true)
65
+
66
+ expect { exp.options[:m] = true }
67
+ .to change { exp.m? }.from(false).to(true)
68
+ .and change { exp.multiline? }.from(false).to(true)
69
+
70
+ expect { exp.options[:x] = true }
71
+ .to change { exp.x? }.from(false).to(true)
72
+ .and change { exp.extended? }.from(false).to(true)
73
+ .and change { exp.free_spacing? }.from(false).to(true)
74
+
75
+ expect { exp.options[:a] = true }
76
+ .to change { exp.a? }.from(false).to(true)
77
+ .and change { exp.ascii_classes? }.from(false).to(true)
78
+
79
+ expect { exp.options[:d] = true }
80
+ .to change { exp.d? }.from(false).to(true)
81
+ .and change { exp.default_classes? }.from(false).to(true)
82
+
83
+ expect { exp.options[:u] = true }
84
+ .to change { exp.u? }.from(false).to(true)
85
+ .and change { exp.unicode_classes? }.from(false).to(true)
86
+ end
87
+
88
+ RSpec.shared_examples '#options' do |regexp, klass, at: []|
89
+ it "works for expression class #{klass}" do
90
+ exp = RP.parse(/#{regexp.source}/i).dig(*at)
91
+ expect(exp).to be_a(klass)
92
+ expect(exp).to be_i
93
+ expect(exp).not_to be_x
94
+ end
95
+ end
96
+
97
+ include_examples '#options', //, Root
98
+ include_examples '#options', /a/, Literal, at: [0]
99
+ include_examples '#options', /\A/, Anchor::Base, at: [0]
100
+ include_examples '#options', /\d/, CharacterType::Base, at: [0]
101
+ include_examples '#options', /\n/, EscapeSequence::Base, at: [0]
102
+ include_examples '#options', /\K/, Keep::Mark, at: [0]
103
+ include_examples '#options', /./, CharacterType::Any, at: [0]
104
+ include_examples '#options', /(a)/, Group::Base, at: [0]
105
+ include_examples '#options', /(a)/, Literal, at: [0, 0]
106
+ include_examples '#options', /(?=a)/, Assertion::Base, at: [0]
107
+ include_examples '#options', /(?=a)/, Literal, at: [0, 0]
108
+ include_examples '#options', /(a|b)/, Group::Base, at: [0]
109
+ include_examples '#options', /(a|b)/, Alternation, at: [0, 0]
110
+ include_examples '#options', /(a|b)/, Alternative, at: [0, 0, 0]
111
+ include_examples '#options', /(a|b)/, Literal, at: [0, 0, 0, 0]
112
+ include_examples '#options', /(a)\1/, Backreference::Base, at: [1]
113
+ include_examples '#options', /(a)\k<1>/, Backreference::Number, at: [1]
114
+ include_examples '#options', /(a)\g<1>/, Backreference::NumberCall, at: [1]
115
+ include_examples '#options', /[a]/, CharacterSet, at: [0]
116
+ include_examples '#options', /[a]/, Literal, at: [0, 0]
117
+ include_examples '#options', /[a-z]/, CharacterSet::Range, at: [0, 0]
118
+ include_examples '#options', /[a-z]/, Literal, at: [0, 0, 0]
119
+ include_examples '#options', /[a&&z]/, CharacterSet::Intersection, at: [0, 0]
120
+ include_examples '#options', /[a&&z]/, CharacterSet::IntersectedSequence, at: [0, 0, 0]
121
+ include_examples '#options', /[a&&z]/, Literal, at: [0, 0, 0, 0]
122
+ include_examples '#options', /[[:ascii:]]/, PosixClass, at: [0, 0]
123
+ include_examples '#options', /\p{word}/, UnicodeProperty::Base, at: [0]
124
+ include_examples '#options', /(a)(?(1)b|c)/, Conditional::Expression, at: [1]
125
+ include_examples '#options', /(a)(?(1)b|c)/, Conditional::Condition, at: [1, 0]
126
+ include_examples '#options', /(a)(?(1)b|c)/, Conditional::Branch, at: [1, 1]
127
+ include_examples '#options', /(a)(?(1)b|c)/, Literal, at: [1, 1, 0]
128
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe(Regexp::Expression::Root) do
4
+ describe('#initialize') do
5
+ it 'supports the old, nonstandard arity for backwards compatibility' do
6
+ expect { Root.new }.to output.to_stderr
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe(Regexp::Expression::Sequence) do
4
+ describe('#initialize') do
5
+ it 'supports the old, nonstandard arity for backwards compatibility' do
6
+ expect { Sequence.new(0, 0, 0) }.to output.to_stderr
7
+ end
8
+ end
9
+ end
@@ -1,123 +1,53 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Conditional lexing') do
4
- # Basic lexer output and nesting tests
5
- tests = {
6
- '(?<A>a)(?(<A>)b|c)' => [3, :conditional, :open, '(?', 7, 9, 0, 0, 0],
7
- '(?<B>a)(?(<B>)b|c)' => [4, :conditional, :condition, '(<B>)', 9, 14, 0, 0, 1],
8
- '(?<C>a)(?(<C>)b|c)' => [6, :conditional, :separator, '|', 15, 16, 0, 0, 1],
9
- '(?<D>a)(?(<D>)b|c)' => [8, :conditional, :close, ')', 17, 18, 0, 0, 0],
10
- }
11
-
12
- tests.each_with_index do |(pattern, (index, type, token, text, ts, te, level, set_level, conditional_level)), count|
13
- specify("lexer_#{type}_#{token}_#{count}") do
14
- tokens = RL.lex(pattern)
15
- struct = tokens.at(index)
16
-
17
- expect(struct.type).to eq type
18
- expect(struct.token).to eq token
19
- expect(struct.text).to eq text
20
- expect(struct.ts).to eq ts
21
- expect(struct.te).to eq te
22
- expect(struct.level).to eq level
23
- expect(struct.set_level).to eq set_level
24
- expect(struct.conditional_level).to eq conditional_level
25
- end
26
- end
27
-
28
- specify('lexer conditional mixed nesting') do
29
- regexp = '((?<A>a)(?<B>(?(<A>)b|((?(<B>)[e-g]|[h-j])))))'
30
- tokens = RL.lex(regexp)
31
-
32
- [
33
- [ 0, :group, :capture, '(', 0, 1, 0, 0, 0],
34
- [ 1, :group, :named, '(?<A>', 1, 6, 1, 0, 0],
35
-
36
- [ 5, :conditional, :open, '(?', 13, 15, 2, 0, 0],
37
- [ 6, :conditional, :condition, '(<A>)', 15, 20, 2, 0, 1],
38
- [ 8, :conditional, :separator, '|', 21, 22, 2, 0, 1],
39
-
40
- [10, :conditional, :open, '(?', 23, 25, 3, 0, 1],
41
- [11, :conditional, :condition, '(<B>)', 25, 30, 3, 0, 2],
42
-
43
- [12, :set, :open, '[', 30, 31, 3, 0, 2],
44
- [13, :literal, :literal, 'e', 31, 32, 3, 1, 2],
45
- [14, :set, :range, '-', 32, 33, 3, 1, 2],
46
- [15, :literal, :literal, 'g', 33, 34, 3, 1, 2],
47
- [16, :set, :close, ']', 34, 35, 3, 0, 2],
48
-
49
- [17, :conditional, :separator, '|', 35, 36, 3, 0, 2],
50
- [23, :conditional, :close, ')', 41, 42, 3, 0, 1],
51
- [25, :conditional, :close, ')', 43, 44, 2, 0, 0],
52
-
53
- [26, :group, :close, ')', 44, 45, 1, 0, 0],
54
- [27, :group, :close, ')', 45, 46, 0, 0, 0]
55
- ].each do |index, type, token, text, ts, te, level, set_level, conditional_level|
56
- struct = tokens.at(index)
57
-
58
- expect(struct.type).to eq type
59
- expect(struct.token).to eq token
60
- expect(struct.text).to eq text
61
- expect(struct.ts).to eq ts
62
- expect(struct.te).to eq te
63
- expect(struct.level).to eq level
64
- expect(struct.set_level).to eq set_level
65
- expect(struct.conditional_level).to eq conditional_level
66
- end
67
- end
68
-
69
- specify('lexer conditional deep nesting') do
70
- regexp = '(a(b(c)))(?(1)(?(2)(?(3)d|e))|(?(3)(?(2)f|g)|(?(1)f|g)))'
71
- tokens = RL.lex(regexp)
72
-
73
- [
74
- [ 9, :conditional, :open, '(?', 9, 11, 0, 0, 0],
75
- [10, :conditional, :condition, '(1)', 11, 14, 0, 0, 1],
76
-
77
- [11, :conditional, :open, '(?', 14, 16, 0, 0, 1],
78
- [12, :conditional, :condition, '(2)', 16, 19, 0, 0, 2],
79
-
80
- [13, :conditional, :open, '(?', 19, 21, 0, 0, 2],
81
- [14, :conditional, :condition, '(3)', 21, 24, 0, 0, 3],
82
-
83
- [16, :conditional, :separator, '|', 25, 26, 0, 0, 3],
84
-
85
- [18, :conditional, :close, ')', 27, 28, 0, 0, 2],
86
- [19, :conditional, :close, ')', 28, 29, 0, 0, 1],
87
-
88
- [20, :conditional, :separator, '|', 29, 30, 0, 0, 1],
89
-
90
- [21, :conditional, :open, '(?', 30, 32, 0, 0, 1],
91
- [22, :conditional, :condition, '(3)', 32, 35, 0, 0, 2],
92
-
93
- [23, :conditional, :open, '(?', 35, 37, 0, 0, 2],
94
- [24, :conditional, :condition, '(2)', 37, 40, 0, 0, 3],
95
-
96
- [26, :conditional, :separator, '|', 41, 42, 0, 0, 3],
97
-
98
- [28, :conditional, :close, ')', 43, 44, 0, 0, 2],
99
-
100
- [29, :conditional, :separator, '|', 44, 45, 0, 0, 2],
101
-
102
- [30, :conditional, :open, '(?', 45, 47, 0, 0, 2],
103
- [31, :conditional, :condition, '(1)', 47, 50, 0, 0, 3],
104
-
105
- [33, :conditional, :separator, '|', 51, 52, 0, 0, 3],
106
-
107
- [35, :conditional, :close, ')', 53, 54, 0, 0, 2],
108
- [36, :conditional, :close, ')', 54, 55, 0, 0, 1],
109
- [37, :conditional, :close, ')', 55, 56, 0, 0, 0]
110
- ].each do |index, type, token, text, ts, te, level, set_level, conditional_level|
111
- struct = tokens.at(index)
112
-
113
- expect(struct.type).to eq type
114
- expect(struct.token).to eq token
115
- expect(struct.text).to eq text
116
- expect(struct.ts).to eq ts
117
- expect(struct.te).to eq te
118
- expect(struct.level).to eq level
119
- expect(struct.set_level).to eq set_level
120
- expect(struct.conditional_level).to eq conditional_level
121
- end
122
- end
4
+ include_examples 'lex', /(?<A>a)(?(<A>)b|c)/,
5
+ 3 => [:conditional, :open, '(?', 7, 9, 0, 0, 0],
6
+ 4 => [:conditional, :condition, '(<A>)', 9, 14, 0, 0, 1],
7
+ 6 => [:conditional, :separator, '|', 15, 16, 0, 0, 1],
8
+ 8 => [:conditional, :close, ')', 17, 18, 0, 0, 0]
9
+
10
+ include_examples 'lex', /((?<A>a)(?<B>(?(<A>)b|((?(<B>)[e-g]|[h-j])))))/,
11
+ 0 => [:group, :capture, '(', 0, 1, 0, 0, 0],
12
+ 1 => [:group, :named, '(?<A>', 1, 6, 1, 0, 0],
13
+ 5 => [:conditional, :open, '(?', 13, 15, 2, 0, 0],
14
+ 6 => [:conditional, :condition, '(<A>)', 15, 20, 2, 0, 1],
15
+ 8 => [:conditional, :separator, '|', 21, 22, 2, 0, 1],
16
+ 10 => [:conditional, :open, '(?', 23, 25, 3, 0, 1],
17
+ 11 => [:conditional, :condition, '(<B>)', 25, 30, 3, 0, 2],
18
+ 12 => [:set, :open, '[', 30, 31, 3, 0, 2],
19
+ 13 => [:literal, :literal, 'e', 31, 32, 3, 1, 2],
20
+ 14 => [:set, :range, '-', 32, 33, 3, 1, 2],
21
+ 15 => [:literal, :literal, 'g', 33, 34, 3, 1, 2],
22
+ 16 => [:set, :close, ']', 34, 35, 3, 0, 2],
23
+ 17 => [:conditional, :separator, '|', 35, 36, 3, 0, 2],
24
+ 23 => [:conditional, :close, ')', 41, 42, 3, 0, 1],
25
+ 25 => [:conditional, :close, ')', 43, 44, 2, 0, 0],
26
+ 26 => [:group, :close, ')', 44, 45, 1, 0, 0],
27
+ 27 => [:group, :close, ')', 45, 46, 0, 0, 0]
28
+
29
+ include_examples 'lex', /(a(b(c)))(?(1)(?(2)(?(3)d|e))|(?(3)(?(2)f|g)|(?(1)f|g)))/,
30
+ 9 => [:conditional, :open, '(?', 9, 11, 0, 0, 0],
31
+ 10 => [:conditional, :condition, '(1)', 11, 14, 0, 0, 1],
32
+ 11 => [:conditional, :open, '(?', 14, 16, 0, 0, 1],
33
+ 12 => [:conditional, :condition, '(2)', 16, 19, 0, 0, 2],
34
+ 13 => [:conditional, :open, '(?', 19, 21, 0, 0, 2],
35
+ 14 => [:conditional, :condition, '(3)', 21, 24, 0, 0, 3],
36
+ 16 => [:conditional, :separator, '|', 25, 26, 0, 0, 3],
37
+ 18 => [:conditional, :close, ')', 27, 28, 0, 0, 2],
38
+ 19 => [:conditional, :close, ')', 28, 29, 0, 0, 1],
39
+ 20 => [:conditional, :separator, '|', 29, 30, 0, 0, 1],
40
+ 21 => [:conditional, :open, '(?', 30, 32, 0, 0, 1],
41
+ 22 => [:conditional, :condition, '(3)', 32, 35, 0, 0, 2],
42
+ 23 => [:conditional, :open, '(?', 35, 37, 0, 0, 2],
43
+ 24 => [:conditional, :condition, '(2)', 37, 40, 0, 0, 3],
44
+ 26 => [:conditional, :separator, '|', 41, 42, 0, 0, 3],
45
+ 28 => [:conditional, :close, ')', 43, 44, 0, 0, 2],
46
+ 29 => [:conditional, :separator, '|', 44, 45, 0, 0, 2],
47
+ 30 => [:conditional, :open, '(?', 45, 47, 0, 0, 2],
48
+ 31 => [:conditional, :condition, '(1)', 47, 50, 0, 0, 3],
49
+ 33 => [:conditional, :separator, '|', 51, 52, 0, 0, 3],
50
+ 35 => [:conditional, :close, ')', 53, 54, 0, 0, 2],
51
+ 36 => [:conditional, :close, ')', 54, 55, 0, 0, 1],
52
+ 37 => [:conditional, :close, ')', 55, 56, 0, 0, 0]
123
53
  end
@@ -1,38 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Escape lexing') do
4
- tests = {
5
- '\u{62}' => {
6
- 0 => [:escape, :codepoint_list, '\u{62}', 0, 6, 0, 0, 0],
7
- },
4
+ include_examples 'lex', '\u{62}',
5
+ 0 => [:escape, :codepoint_list, '\u{62}', 0, 6, 0, 0, 0]
8
6
 
9
- '\u{62 63 64}' => {
10
- 0 => [:escape, :codepoint_list, '\u{62 63 64}', 0, 12, 0, 0, 0],
11
- },
7
+ include_examples 'lex', '\u{62 63 64}',
8
+ 0 => [:escape, :codepoint_list, '\u{62 63 64}', 0, 12, 0, 0, 0]
12
9
 
13
- '\u{62 63 64}+' => {
14
- 0 => [:escape, :codepoint_list, '\u{62 63}', 0, 9, 0, 0, 0],
15
- 1 => [:escape, :codepoint_list, '\u{64}', 9, 15, 0, 0, 0],
16
- 2 => [:quantifier, :one_or_more, '+', 15, 16, 0, 0, 0],
17
- },
18
- }
19
-
20
- tests.each_with_index do |(pattern, checks), count|
21
- specify("lex_escape_runs_#{count}") do
22
- tokens = RL.lex(pattern)
23
-
24
- checks.each do |index, (type, token, text, ts, te, level, set_level, conditional_level)|
25
- struct = tokens.at(index)
26
-
27
- expect(struct.type).to eq type
28
- expect(struct.token).to eq token
29
- expect(struct.text).to eq text
30
- expect(struct.ts).to eq ts
31
- expect(struct.te).to eq te
32
- expect(struct.level).to eq level
33
- expect(struct.set_level).to eq set_level
34
- expect(struct.conditional_level).to eq conditional_level
35
- end
36
- end
37
- end
10
+ include_examples 'lex', '\u{62 63 64}+',
11
+ 0 => [:escape, :codepoint_list, '\u{62 63}', 0, 9, 0, 0, 0],
12
+ 1 => [:escape, :codepoint_list, '\u{64}', 9, 15, 0, 0, 0],
13
+ 2 => [:quantifier, :one_or_more, '+', 15, 16, 0, 0, 0]
38
14
  end