regexp_parser 1.5.0 → 1.5.1

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