regexp_parser 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -30
- data/README.md +10 -10
- data/lib/regexp_parser/expression.rb +3 -3
- data/lib/regexp_parser/expression/classes/conditional.rb +19 -17
- data/lib/regexp_parser/expression/classes/group.rb +3 -1
- data/lib/regexp_parser/expression/classes/root.rb +17 -5
- data/lib/regexp_parser/expression/methods/traverse.rb +0 -1
- data/lib/regexp_parser/expression/quantifier.rb +11 -2
- data/lib/regexp_parser/expression/sequence.rb +37 -13
- data/lib/regexp_parser/expression/sequence_operation.rb +1 -6
- data/lib/regexp_parser/expression/subexpression.rb +12 -2
- data/lib/regexp_parser/parser.rb +19 -10
- data/lib/regexp_parser/scanner.rb +8 -8
- data/lib/regexp_parser/scanner/scanner.rl +8 -8
- data/lib/regexp_parser/version.rb +1 -1
- data/test/expression/test_subexpression.rb +9 -0
- data/test/lexer/test_refcalls.rb +3 -0
- data/test/parser/test_all.rb +3 -3
- data/test/parser/test_conditionals.rb +46 -10
- data/test/parser/test_groups.rb +22 -0
- data/test/parser/test_quantifiers.rb +43 -1
- data/test/parser/test_refcalls.rb +36 -20
- data/test/scanner/test_all.rb +4 -4
- data/test/scanner/test_refcalls.rb +3 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 467bef34ff29198ccbde0063f1b2f62f03cf8237c46fe59be8f06e974c00c367
|
4
|
+
data.tar.gz: b876e662f889449954f0beeddedded8e462b4daec5fbb4692b65f9f7a012fec8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2064de034cf83f157da79225fc587374f744884f37934fd1828e4f3127bc45f899d62986495d9344fd4a5f2e96f7b2cf90c7961c0895fd0ee52ab8e24428d67
|
7
|
+
data.tar.gz: 146440a8fc9e2c48bb1bdedad539f6883ecbc5874276eb3e56876df7b74e42630ec789f6cc6b4ca7e79d5e6b2e986b5a2f5b2fc0be4d273c02d8ff62fa2cd35c
|
data/CHANGELOG.md
CHANGED
@@ -1,54 +1,71 @@
|
|
1
|
-
## [
|
1
|
+
## [1.1.0] - 2018-09-17 - [Janosch Müller](mailto:janosch84@gmail.com)
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
- Added `Quantifier` methods `#greedy?`, `#possessive?`, `#reluctant?`/`#lazy?`
|
6
|
+
- Added `Group::Options#option_changes`
|
7
|
+
- shows the options enabled or disabled by the given options group
|
8
|
+
- as with all other expressions, `#options` shows the overall active options
|
9
|
+
- Added `Conditional#reference` and `Condition#reference`, indicating the determinative group
|
10
|
+
- Added `Subexpression#dig`, acts like [`Array#dig`](http://ruby-doc.org/core-2.5.0/Array.html#method-i-dig)
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
|
14
|
+
- Fixed parsing of quantified conditional expressions (quantifiers were assigned to the wrong expression)
|
15
|
+
- Fixed scanning and parsing of forward-referring subexpression calls (e.g. `\g<+1>`)
|
16
|
+
- `Root` and `Sequence` expressions now support the same constructor signature as all other expressions
|
17
|
+
|
18
|
+
## [1.0.0] - 2018-09-01 - [Janosch Müller](mailto:janosch84@gmail.com)
|
2
19
|
|
3
20
|
This release includes several breaking changes, mostly to character sets, #map and properties.
|
4
21
|
|
5
22
|
### Changed
|
6
23
|
|
7
24
|
- Changed handling of sets (a.k.a. character classes or "bracket expressions")
|
8
|
-
* see PR #55 / issue #47 for details
|
25
|
+
* see PR [#55](https://github.com/ammar/regexp_parser/pull/55) / issue [#47](https://github.com/ammar/regexp_parser/issues/47) for details
|
9
26
|
* sets are now parsed to expression trees like other nestable expressions
|
10
|
-
*
|
11
|
-
* CharacterSet#members has been removed
|
12
|
-
* new Range and Intersection classes represent corresponding syntax features
|
13
|
-
* a new PosixClass expression class represents e.g. [[:ascii:]]
|
14
|
-
* PosixClass instances behave like Property ones, e.g. support
|
15
|
-
*
|
16
|
-
- Changed Subexpression#map to act like regular Enumerable#map
|
17
|
-
* the old behavior is available as Subexpression#flat_map
|
18
|
-
* e.g. parse(/[a]/).map(&:to_s) == ["[a]"]
|
19
|
-
- Changed
|
20
|
-
* EscapeSequence::Codepoint
|
21
|
-
* they already existed, but were all parsed as EscapeSequence::Literal
|
22
|
-
* e.g.
|
23
|
-
- Changed naming of many property tokens (emitted for
|
24
|
-
* if you work with these tokens, see PR #56 for details
|
25
|
-
* e.g.
|
26
|
-
- Changed (?m) and the likes to emit as
|
27
|
-
* allows differentiating from group-local
|
28
|
-
- Changed name of Backreference::..NestLevel to
|
29
|
-
- Changed
|
27
|
+
* `#scan` now emits the same tokens as outside sets (no longer `:set, :member`)
|
28
|
+
* `CharacterSet#members` has been removed
|
29
|
+
* new `Range` and `Intersection` classes represent corresponding syntax features
|
30
|
+
* a new `PosixClass` expression class represents e.g. `[[:ascii:]]`
|
31
|
+
* `PosixClass` instances behave like `Property` ones, e.g. support `#negative?`
|
32
|
+
* `#scan` emits `:(non)posixclass, :<type>` instead of `:set, :char_(non)<type>`
|
33
|
+
- Changed `Subexpression#map` to act like regular `Enumerable#map`
|
34
|
+
* the old behavior is available as `Subexpression#flat_map`
|
35
|
+
* e.g. `parse(/[a]/).map(&:to_s) == ["[a]"]`; used to be `["[a]", "a"]`
|
36
|
+
- Changed expression emissions for some escape sequences
|
37
|
+
* `EscapeSequence::Codepoint`, `CodepointList`, `Hex` and `Octal` are now all used
|
38
|
+
* they already existed, but were all parsed as `EscapeSequence::Literal`
|
39
|
+
* e.g. `\x97` is now `EscapeSequence::Hex` instead of `EscapeSequence::Literal`
|
40
|
+
- Changed naming of many property tokens (emitted for `\p{...}`)
|
41
|
+
* if you work with these tokens, see PR [#56](https://github.com/ammar/regexp_parser/pull/56) for details
|
42
|
+
* e.g. `:punct_dash` is now `:dash_punctuation`
|
43
|
+
- Changed `(?m)` and the likes to emit as `:options_switch` token (@4ade4d1)
|
44
|
+
* allows differentiating from group-local `:options`, e.g. `(?m:.)`
|
45
|
+
- Changed name of `Backreference::..NestLevel` to `..RecursionLevel` (@4184339)
|
46
|
+
- Changed B`ackreference::Number#number` from `String` to `Integer` (@40a2231)
|
30
47
|
|
31
48
|
### Added
|
32
49
|
|
33
50
|
- Added support for all previously missing properties (about 250)
|
34
|
-
- Added Expression::UnicodeProperty#shortcut (e.g. returns "m" for
|
35
|
-
- Added
|
36
|
-
- Added
|
37
|
-
- Added
|
51
|
+
- Added `Expression::UnicodeProperty#shortcut` (e.g. returns "m" for `\p{mark}`)
|
52
|
+
- Added `#char(s)` and `#codepoint(s)` methods to all `EscapeSequence` expressions
|
53
|
+
- Added `#number`/`#name`/`#recursion_level` to all backref/call expressions (@174bf21)
|
54
|
+
- Added `#number` and `#number_at_level` to capturing group expressions (@40a2231)
|
38
55
|
|
39
56
|
### Fixed
|
40
57
|
|
41
|
-
- Fixed
|
58
|
+
- Fixed Ruby version mapping of some properties
|
42
59
|
- Fixed scanning of some property spellings, e.g. with dashes
|
43
60
|
- Fixed some incorrect property alias normalizations
|
44
|
-
- Fixed scanning of codepoint escapes with 6 digits (e.g.
|
45
|
-
- Fixed scanning of
|
61
|
+
- Fixed scanning of codepoint escapes with 6 digits (e.g. `\u{10FFFF}`)
|
62
|
+
- Fixed scanning of `\R` and `\X` within sets; they act as literals there
|
46
63
|
|
47
64
|
## [0.5.0] - 2018-04-29 - [Janosch Müller](mailto:janosch84@gmail.com)
|
48
65
|
|
49
66
|
### Changed
|
50
67
|
|
51
|
-
- Changed handling of Ruby versions (PR #53)
|
68
|
+
- Changed handling of Ruby versions (PR [#53](https://github.com/ammar/regexp_parser/pull/53))
|
52
69
|
* New Ruby versions are now supported by default
|
53
70
|
* Some deep-lying APIs have changed, which should not affect most users:
|
54
71
|
* `Regexp::Syntax::VERSIONS` is gone
|
data/README.md
CHANGED
@@ -317,7 +317,7 @@ _Note that not all of these are available in all versions of Ruby_
|
|
317
317
|
| Syntax Feature | Examples | ⋯ |
|
318
318
|
| ------------------------------------- | ------------------------------------------------------- |:--------:|
|
319
319
|
| **Alternation** | `a\|b\|c` | ✓ |
|
320
|
-
| **Anchors** | `^`,
|
320
|
+
| **Anchors** | `\A`, `^`, `\b` | ✓ |
|
321
321
|
| **Character Classes** | `[abc]`, `[^\\]`, `[a-d&&g-h]`, `[a=e=b]` | ✓ |
|
322
322
|
| **Character Types** | `\d`, `\H`, `\s` | ✓ |
|
323
323
|
| **Cluster Types** | `\R`, `\X` | ✓ |
|
@@ -341,7 +341,7 @@ _Note that not all of these are available in all versions of Ruby_
|
|
341
341
|
|   _**Capturing**_ | `(abc)` | ✓ |
|
342
342
|
|   _**Comments**_ | `(?# comment text)` | ✓ |
|
343
343
|
|   _**Named**_ | `(?<name>abc)`, `(?'name'abc)` | ✓ |
|
344
|
-
|   _**Options**_ | `(?mi-x:abc)`, `(?a:\s\w+)`
|
344
|
+
|   _**Options**_ | `(?mi-x:abc)`, `(?a:\s\w+)`, `(?i)` | ✓ |
|
345
345
|
|   _**Passive**_ | `(?:abc)` | ✓ |
|
346
346
|
|   _**Subexp. Calls**_ | `\g<name>`, `\g<1>` | ✓ |
|
347
347
|
| **Keep** | `\K`, `(ab\Kc\|d\Ke)f` | ✓ |
|
@@ -357,14 +357,14 @@ _Note that not all of these are available in all versions of Ruby_
|
|
357
357
|
|   _**Meta**_ | `\M-c`, `\M-\C-C`, `\M-\cC`, `\C-\M-C`, `\c\M-C` | ✓ |
|
358
358
|
|   _**Octal**_ | `\0`, `\01`, `\012` | ✓ |
|
359
359
|
|   _**Unicode**_ | `\uHHHH`, `\u{H+ H+}` | ✓ |
|
360
|
-
| **Unicode Properties** | _<sub>([Unicode
|
361
|
-
|   _**Age**_ | `\p{Age=5.2}`, `\P{age=7.0}`
|
362
|
-
|   _**Blocks**_ | `\p{InArmenian}`, `\P{InKhmer}`
|
363
|
-
|   _**Classes**_ | `\p{Alpha}`, `\P{Space}`
|
364
|
-
|   _**Derived**_ | `\p{Math}`, `\P{Lowercase}`
|
365
|
-
|   _**General Categories**_ | `\p{Lu}`, `\P{Cs}
|
366
|
-
|   _**Scripts**_ | `\p{Arabic}`, `\P{Hiragana}
|
367
|
-
|   _**Simple**_ | `\p{Dash}`, `\p{Extender}
|
360
|
+
| **Unicode Properties** | _<sub>([Unicode 10.0.0](http://www.unicode.org/versions/Unicode10.0.0/))</sub>_ | ⋱ |
|
361
|
+
|   _**Age**_ | `\p{Age=5.2}`, `\P{age=7.0}`, `\p{^age=8.0}` | ✓ |
|
362
|
+
|   _**Blocks**_ | `\p{InArmenian}`, `\P{InKhmer}`, `\p{^InThai}` | ✓ |
|
363
|
+
|   _**Classes**_ | `\p{Alpha}`, `\P{Space}`, `\p{^Alnum}` | ✓ |
|
364
|
+
|   _**Derived**_ | `\p{Math}`, `\P{Lowercase}`, `\p{^Cased}` | ✓ |
|
365
|
+
|   _**General Categories**_ | `\p{Lu}`, `\P{Cs}`, \p{^sc} | ✓ |
|
366
|
+
|   _**Scripts**_ | `\p{Arabic}`, `\P{Hiragana}`, \p{^Greek} | ✓ |
|
367
|
+
|   _**Simple**_ | `\p{Dash}`, `\p{Extender}`, \p{^Hyphen} | ✓ |
|
368
368
|
|
369
369
|
##### Inapplicable Features
|
370
370
|
|
@@ -72,16 +72,16 @@ module Regexp::Expression
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def greedy?
|
75
|
-
quantified? and quantifier.
|
75
|
+
quantified? and quantifier.greedy?
|
76
76
|
end
|
77
77
|
|
78
78
|
def reluctant?
|
79
|
-
quantified? and quantifier.
|
79
|
+
quantified? and quantifier.reluctant?
|
80
80
|
end
|
81
81
|
alias :lazy? :reluctant?
|
82
82
|
|
83
83
|
def possessive?
|
84
|
-
quantified? and quantifier.
|
84
|
+
quantified? and quantifier.possessive?
|
85
85
|
end
|
86
86
|
|
87
87
|
def multiline?
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Regexp::Expression
|
2
|
-
|
3
2
|
module Conditional
|
4
3
|
class TooManyBranches < StandardError
|
5
4
|
def initialize
|
@@ -7,16 +6,19 @@ module Regexp::Expression
|
|
7
6
|
end
|
8
7
|
end
|
9
8
|
|
10
|
-
class Condition < Regexp::Expression::Base
|
11
|
-
|
9
|
+
class Condition < Regexp::Expression::Base
|
10
|
+
# Name or number of the referenced capturing group that determines state.
|
11
|
+
# Returns a String if reference is by name, Integer if by number.
|
12
|
+
def reference
|
13
|
+
ref = text.tr("'<>()", "")
|
14
|
+
ref =~ /\D/ ? ref : Integer(ref)
|
15
|
+
end
|
16
|
+
end
|
12
17
|
|
13
|
-
class
|
14
|
-
attr_reader :branches, :condition
|
18
|
+
class Branch < Regexp::Expression::Sequence; end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
@branches = []
|
19
|
-
end
|
20
|
+
class Expression < Regexp::Expression::Subexpression
|
21
|
+
attr_reader :condition
|
20
22
|
|
21
23
|
def condition=(exp)
|
22
24
|
@condition = exp
|
@@ -27,17 +29,18 @@ module Regexp::Expression
|
|
27
29
|
expressions.last << exp
|
28
30
|
end
|
29
31
|
|
30
|
-
def
|
32
|
+
def add_sequence
|
31
33
|
raise TooManyBranches.new if branches.length == 2
|
34
|
+
Branch.add_to(self, { conditional_level: conditional_level + 1 })
|
35
|
+
end
|
36
|
+
alias :branch :add_sequence
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
expressions << sequence
|
36
|
-
branches << expressions.last
|
38
|
+
def branches
|
39
|
+
expressions - [condition]
|
37
40
|
end
|
38
41
|
|
39
|
-
def
|
40
|
-
|
42
|
+
def reference
|
43
|
+
condition.reference
|
41
44
|
end
|
42
45
|
|
43
46
|
def to_s(_format = :full)
|
@@ -45,5 +48,4 @@ module Regexp::Expression
|
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
48
|
-
|
49
51
|
end
|
@@ -12,8 +12,10 @@ module Regexp::Expression
|
|
12
12
|
|
13
13
|
class Atomic < Group::Base; end
|
14
14
|
class Passive < Group::Base; end
|
15
|
-
class Options < Group::Base; end
|
16
15
|
class Absence < Group::Base; end
|
16
|
+
class Options < Group::Base
|
17
|
+
attr_accessor :option_changes
|
18
|
+
end
|
17
19
|
|
18
20
|
class Capture < Group::Base
|
19
21
|
attr_accessor :number, :number_at_level
|
@@ -1,12 +1,24 @@
|
|
1
1
|
module Regexp::Expression
|
2
2
|
|
3
3
|
class Root < Regexp::Expression::Subexpression
|
4
|
-
|
5
|
-
|
4
|
+
# TODO: this override is here for backwards compatibility, remove in 2.0.0
|
5
|
+
def initialize(*args)
|
6
|
+
unless args.first.is_a?(Regexp::Token)
|
7
|
+
warn('WARNING: Root.new without a Token argument is deprecated and '\
|
8
|
+
'will be removed in 2.0.0. Use Root.build for the old behavior.')
|
9
|
+
return super(self.class.build_token, *args)
|
10
|
+
end
|
11
|
+
super
|
6
12
|
end
|
7
13
|
|
8
|
-
|
9
|
-
|
10
|
-
|
14
|
+
class << self
|
15
|
+
def build(options = {})
|
16
|
+
new(build_token, options)
|
17
|
+
end
|
11
18
|
|
19
|
+
def build_token
|
20
|
+
Regexp::Token.new(:expression, :root, '', 0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
12
24
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Regexp::Expression
|
2
|
-
|
3
2
|
class Quantifier
|
3
|
+
MODES = [:greedy, :possessive, :reluctant]
|
4
|
+
|
4
5
|
attr_reader :token, :text, :min, :max, :mode
|
5
6
|
|
6
7
|
def initialize(token, text, min, max, mode)
|
@@ -30,6 +31,14 @@ module Regexp::Expression
|
|
30
31
|
max: max,
|
31
32
|
}
|
32
33
|
end
|
33
|
-
end
|
34
34
|
|
35
|
+
MODES.each do |mode|
|
36
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
37
|
+
def #{mode}?
|
38
|
+
mode.equal?(:#{mode})
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
end
|
42
|
+
alias :lazy? :reluctant?
|
43
|
+
end
|
35
44
|
end
|
@@ -4,20 +4,44 @@ module Regexp::Expression
|
|
4
4
|
# quantifiers, as it applies them to its last element instead of itself as
|
5
5
|
# a whole subexpression.
|
6
6
|
#
|
7
|
-
# Used as the base class for the Alternation alternatives
|
8
|
-
# branches.
|
7
|
+
# Used as the base class for the Alternation alternatives, Conditional
|
8
|
+
# branches, and CharacterSet::Intersection intersected sequences.
|
9
9
|
class Sequence < Regexp::Expression::Subexpression
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
# TODO: this override is here for backwards compatibility, remove in 2.0.0
|
11
|
+
def initialize(*args)
|
12
|
+
if args.count == 3
|
13
|
+
warn('WARNING: Sequence.new without a Regexp::Token argument is '\
|
14
|
+
'deprecated and will be removed in 2.0.0.')
|
15
|
+
return self.class.at_levels(*args)
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def add_to(subexpression, options = {})
|
22
|
+
sequence = at_levels(
|
23
|
+
subexpression.level,
|
24
|
+
subexpression.set_level,
|
25
|
+
options[:conditional_level] || subexpression.conditional_level
|
26
|
+
)
|
27
|
+
sequence.nesting_level = subexpression.nesting_level + 1
|
28
|
+
subexpression.expressions << sequence
|
29
|
+
sequence
|
30
|
+
end
|
31
|
+
|
32
|
+
def at_levels(level, set_level, conditional_level)
|
33
|
+
token = Regexp::Token.new(
|
34
|
+
:expression,
|
35
|
+
:sequence,
|
36
|
+
'',
|
37
|
+
nil, # ts
|
38
|
+
nil, # te
|
39
|
+
level,
|
40
|
+
set_level,
|
41
|
+
conditional_level
|
42
|
+
)
|
43
|
+
new(token)
|
44
|
+
end
|
21
45
|
end
|
22
46
|
|
23
47
|
def text
|
@@ -15,20 +15,15 @@ module Regexp::Expression
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def add_sequence
|
18
|
-
|
19
|
-
exp.nesting_level = nesting_level + 1
|
20
|
-
expressions << exp
|
21
|
-
exp
|
18
|
+
self.class::OPERAND.add_to(self)
|
22
19
|
end
|
23
20
|
|
24
21
|
def quantify(token, text, min = nil, max = nil, mode = :greedy)
|
25
22
|
sequences.last.last.quantify(token, text, min, max, mode)
|
26
|
-
sequences.last.last.quantify(token, text, min, max, mode)
|
27
23
|
end
|
28
24
|
|
29
25
|
def to_s(format = :full)
|
30
26
|
sequences.map { |e| e.to_s(format) }.join(text)
|
31
|
-
sequences.map { |e| e.to_s(format) }.join(text)
|
32
27
|
end
|
33
28
|
end
|
34
29
|
end
|
@@ -25,8 +25,18 @@ module Regexp::Expression
|
|
25
25
|
end
|
26
26
|
|
27
27
|
%w[[] all? any? at collect count each each_with_index empty?
|
28
|
-
fetch find first index join last length map values_at].each do |
|
29
|
-
|
28
|
+
fetch find first index join last length map values_at].each do |method|
|
29
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
def #{method}(*args, &block)
|
31
|
+
expressions.#{method}(*args, &block)
|
32
|
+
end
|
33
|
+
RUBY
|
34
|
+
end
|
35
|
+
|
36
|
+
def dig(*indices)
|
37
|
+
exp = self
|
38
|
+
indices.each { |idx| exp = exp.nil? || exp.terminal? ? nil : exp[idx] }
|
39
|
+
exp
|
30
40
|
end
|
31
41
|
|
32
42
|
def te
|
data/lib/regexp_parser/parser.rb
CHANGED
@@ -23,7 +23,7 @@ class Regexp::Parser
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def parse(input, syntax = "ruby/#{RUBY_VERSION}", &block)
|
26
|
-
root = Root.
|
26
|
+
root = Root.build(options_from_input(input))
|
27
27
|
|
28
28
|
self.root = root
|
29
29
|
self.node = root
|
@@ -89,8 +89,7 @@ class Regexp::Parser
|
|
89
89
|
|
90
90
|
def nest_conditional(exp)
|
91
91
|
conditional_nesting.push(exp)
|
92
|
-
|
93
|
-
self.node = exp
|
92
|
+
nest(exp)
|
94
93
|
end
|
95
94
|
|
96
95
|
def parse_token(token)
|
@@ -216,6 +215,7 @@ class Regexp::Parser
|
|
216
215
|
self.node = conditional_nesting.last.branches.last
|
217
216
|
when :close
|
218
217
|
conditional_nesting.pop
|
218
|
+
decrease_nesting
|
219
219
|
|
220
220
|
self.node =
|
221
221
|
if conditional_nesting.empty?
|
@@ -496,25 +496,34 @@ class Regexp::Parser
|
|
496
496
|
negative ||= ''
|
497
497
|
self.switching_options = token.token.equal?(:options_switch)
|
498
498
|
|
499
|
-
|
499
|
+
opt_changes = {}
|
500
|
+
new_active_opts = active_opts.dup
|
500
501
|
|
501
502
|
# Negative options have precedence. E.g. /(?i-i)a/ is case-sensitive.
|
502
503
|
%w[i m x].each do |flag|
|
503
|
-
|
504
|
-
|
504
|
+
if positive.include?(flag)
|
505
|
+
opt_changes[flag.to_sym] = new_active_opts[flag.to_sym] = true
|
506
|
+
end
|
507
|
+
if negative.include?(flag)
|
508
|
+
opt_changes[flag.to_sym] = false
|
509
|
+
new_active_opts.delete(flag.to_sym)
|
510
|
+
end
|
505
511
|
end
|
506
512
|
|
507
513
|
# Any encoding flag overrides all previous encoding flags. If there are
|
508
514
|
# multiple encoding flags in an options string, the last one wins.
|
509
515
|
# E.g. /(?dau)\w/ matches UTF8 chars but /(?dua)\w/ only ASCII chars.
|
510
516
|
if (flag = positive.reverse[/[adu]/])
|
511
|
-
%w[a d u].each { |key|
|
512
|
-
|
517
|
+
%w[a d u].each { |key| new_active_opts.delete(key.to_sym) }
|
518
|
+
opt_changes[flag.to_sym] = new_active_opts[flag.to_sym] = true
|
513
519
|
end
|
514
520
|
|
515
|
-
options_stack <<
|
521
|
+
options_stack << new_active_opts
|
522
|
+
|
523
|
+
options_group = Group::Options.new(token, active_opts)
|
524
|
+
options_group.option_changes = opt_changes
|
516
525
|
|
517
|
-
nest(
|
526
|
+
nest(options_group)
|
518
527
|
end
|
519
528
|
|
520
529
|
def open_group(token)
|
@@ -2131,14 +2131,14 @@ te = p+1
|
|
2131
2131
|
when /^\\([gk])''/ # single quotes
|
2132
2132
|
empty_backref_error("ref/call (sq)")
|
2133
2133
|
|
2134
|
-
when /^\\([gk])<[^\d
|
2134
|
+
when /^\\([gk])<[^\d+-]\w*>/ # angle-brackets
|
2135
2135
|
if $1 == 'k'
|
2136
2136
|
emit(:backref, :name_ref_ab, text, ts, te)
|
2137
2137
|
else
|
2138
2138
|
emit(:backref, :name_call_ab, text, ts, te)
|
2139
2139
|
end
|
2140
2140
|
|
2141
|
-
when /^\\([gk])'[^\d
|
2141
|
+
when /^\\([gk])'[^\d+-]\w*'/ #single quotes
|
2142
2142
|
if $1 == 'k'
|
2143
2143
|
emit(:backref, :name_ref_sq, text, ts, te)
|
2144
2144
|
else
|
@@ -2159,30 +2159,30 @@ te = p+1
|
|
2159
2159
|
emit(:backref, :number_call_sq, text, ts, te)
|
2160
2160
|
end
|
2161
2161
|
|
2162
|
-
when /^\\(
|
2162
|
+
when /^\\(?:g<\+|g<-|(k)<-)\d+>/ # angle-brackets
|
2163
2163
|
if $1 == 'k'
|
2164
2164
|
emit(:backref, :number_rel_ref_ab, text, ts, te)
|
2165
2165
|
else
|
2166
2166
|
emit(:backref, :number_rel_call_ab, text, ts, te)
|
2167
2167
|
end
|
2168
2168
|
|
2169
|
-
when /^\\(
|
2169
|
+
when /^\\(?:g'\+|g'-|(k)'-)\d+'/ # single quotes
|
2170
2170
|
if $1 == 'k'
|
2171
2171
|
emit(:backref, :number_rel_ref_sq, text, ts, te)
|
2172
2172
|
else
|
2173
2173
|
emit(:backref, :number_rel_call_sq, text, ts, te)
|
2174
2174
|
end
|
2175
2175
|
|
2176
|
-
when /^\\k<[^\d
|
2176
|
+
when /^\\k<[^\d+\-]\w*[+\-]\d+>/ # angle-brackets
|
2177
2177
|
emit(:backref, :name_recursion_ref_ab, text, ts, te)
|
2178
2178
|
|
2179
|
-
when /^\\k'[^\d
|
2179
|
+
when /^\\k'[^\d+\-]\w*[+\-]\d+'/ # single-quotes
|
2180
2180
|
emit(:backref, :name_recursion_ref_sq, text, ts, te)
|
2181
2181
|
|
2182
|
-
when /^\\([gk])
|
2182
|
+
when /^\\([gk])<[+\-]?\d+[+\-]\d+>/ # angle-brackets
|
2183
2183
|
emit(:backref, :number_recursion_ref_ab, text, ts, te)
|
2184
2184
|
|
2185
|
-
when /^\\([gk])'
|
2185
|
+
when /^\\([gk])'[+\-]?\d+[+\-]\d+'/ # single-quotes
|
2186
2186
|
emit(:backref, :number_recursion_ref_sq, text, ts, te)
|
2187
2187
|
|
2188
2188
|
else
|
@@ -582,14 +582,14 @@
|
|
582
582
|
when /^\\([gk])''/ # single quotes
|
583
583
|
empty_backref_error("ref/call (sq)")
|
584
584
|
|
585
|
-
when /^\\([gk])<[^\d
|
585
|
+
when /^\\([gk])<[^\d+-]\w*>/ # angle-brackets
|
586
586
|
if $1 == 'k'
|
587
587
|
emit(:backref, :name_ref_ab, text, ts, te)
|
588
588
|
else
|
589
589
|
emit(:backref, :name_call_ab, text, ts, te)
|
590
590
|
end
|
591
591
|
|
592
|
-
when /^\\([gk])'[^\d
|
592
|
+
when /^\\([gk])'[^\d+-]\w*'/ #single quotes
|
593
593
|
if $1 == 'k'
|
594
594
|
emit(:backref, :name_ref_sq, text, ts, te)
|
595
595
|
else
|
@@ -610,30 +610,30 @@
|
|
610
610
|
emit(:backref, :number_call_sq, text, ts, te)
|
611
611
|
end
|
612
612
|
|
613
|
-
when /^\\(
|
613
|
+
when /^\\(?:g<\+|g<-|(k)<-)\d+>/ # angle-brackets
|
614
614
|
if $1 == 'k'
|
615
615
|
emit(:backref, :number_rel_ref_ab, text, ts, te)
|
616
616
|
else
|
617
617
|
emit(:backref, :number_rel_call_ab, text, ts, te)
|
618
618
|
end
|
619
619
|
|
620
|
-
when /^\\(
|
620
|
+
when /^\\(?:g'\+|g'-|(k)'-)\d+'/ # single quotes
|
621
621
|
if $1 == 'k'
|
622
622
|
emit(:backref, :number_rel_ref_sq, text, ts, te)
|
623
623
|
else
|
624
624
|
emit(:backref, :number_rel_call_sq, text, ts, te)
|
625
625
|
end
|
626
626
|
|
627
|
-
when /^\\k<[^\d
|
627
|
+
when /^\\k<[^\d+\-]\w*[+\-]\d+>/ # angle-brackets
|
628
628
|
emit(:backref, :name_recursion_ref_ab, text, ts, te)
|
629
629
|
|
630
|
-
when /^\\k'[^\d
|
630
|
+
when /^\\k'[^\d+\-]\w*[+\-]\d+'/ # single-quotes
|
631
631
|
emit(:backref, :name_recursion_ref_sq, text, ts, te)
|
632
632
|
|
633
|
-
when /^\\([gk])
|
633
|
+
when /^\\([gk])<[+\-]?\d+[+\-]\d+>/ # angle-brackets
|
634
634
|
emit(:backref, :number_recursion_ref_ab, text, ts, te)
|
635
635
|
|
636
|
-
when /^\\([gk])'
|
636
|
+
when /^\\([gk])'[+\-]?\d+[+\-]\d+'/ # single-quotes
|
637
637
|
emit(:backref, :number_recursion_ref_sq, text, ts, te)
|
638
638
|
|
639
639
|
else
|
@@ -46,4 +46,13 @@ class ExpressionSubexpression < Test::Unit::TestCase
|
|
46
46
|
|
47
47
|
assert tests.empty?
|
48
48
|
end
|
49
|
+
|
50
|
+
def test_subexpression_dig
|
51
|
+
root = RP.parse(/(((a)))/)
|
52
|
+
|
53
|
+
assert_equal '(((a)))', root.dig(0).to_s
|
54
|
+
assert_equal 'a', root.dig(0, 0, 0, 0).to_s
|
55
|
+
assert_nil root.dig(0, 0, 0, 0, 0)
|
56
|
+
assert_nil root.dig(3, 7)
|
57
|
+
end
|
49
58
|
end
|
data/test/lexer/test_refcalls.rb
CHANGED
@@ -26,6 +26,9 @@ class LexerRefCalls < Test::Unit::TestCase
|
|
26
26
|
'(abc)\g<-1>' => [3, :backref, :number_rel_call, '\g<-1>', 5, 11, 0, 0, 0],
|
27
27
|
"(abc)\\g'-1'" => [3, :backref, :number_rel_call, "\\g'-1'", 5, 11, 0, 0, 0],
|
28
28
|
|
29
|
+
'(abc)\g<+1>' => [3, :backref, :number_rel_call, '\g<+1>', 5, 11, 0, 0, 0],
|
30
|
+
"(abc)\\g'+1'" => [3, :backref, :number_rel_call, "\\g'+1'", 5, 11, 0, 0, 0],
|
31
|
+
|
29
32
|
# Group back-references, with nesting level
|
30
33
|
'(?<X>abc)\k<X-0>' => [3, :backref, :name_recursion_ref, '\k<X-0>', 9, 16, 0, 0, 0],
|
31
34
|
"(?<X>abc)\\k'X-0'" => [3, :backref, :name_recursion_ref, "\\k'X-0'", 9, 16, 0, 0, 0],
|
data/test/parser/test_all.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require File.expand_path("../../helpers", __FILE__)
|
2
2
|
|
3
|
-
%w
|
3
|
+
%w[
|
4
4
|
alternation anchors errors escapes free_space groups
|
5
5
|
posix_classes properties quantifiers refcalls sets types
|
6
|
-
|
6
|
+
].each do |tc|
|
7
7
|
require File.expand_path("../test_#{tc}", __FILE__)
|
8
8
|
end
|
9
9
|
|
@@ -11,7 +11,7 @@ require File.expand_path('../set/test_ranges.rb', __FILE__)
|
|
11
11
|
require File.expand_path('../set/test_intersections.rb', __FILE__)
|
12
12
|
|
13
13
|
if RUBY_VERSION >= '2.0.0'
|
14
|
-
%w
|
14
|
+
%w[conditionals keep].each do |tc|
|
15
15
|
require File.expand_path("../test_#{tc}", __FILE__)
|
16
16
|
end
|
17
17
|
end
|
@@ -11,12 +11,12 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
11
11
|
assert exp.is_a?(Conditional::Expression),
|
12
12
|
"Expected Condition, but got #{exp.class.name}"
|
13
13
|
|
14
|
-
assert_equal exp.type,
|
15
|
-
assert_equal exp.token,
|
16
|
-
assert_equal exp.text,
|
14
|
+
assert_equal exp.type, :conditional
|
15
|
+
assert_equal exp.token, :open
|
16
|
+
assert_equal exp.text, '(?'
|
17
|
+
assert_equal exp.reference, 'A'
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
20
|
def test_parse_conditional_condition
|
21
21
|
regexp = /(?<A>a)(?(<A>)T|F)/
|
22
22
|
|
@@ -26,11 +26,26 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
26
26
|
assert exp.is_a?(Conditional::Condition),
|
27
27
|
"Expected Condition, but got #{exp.class.name}"
|
28
28
|
|
29
|
-
assert_equal exp.type,
|
30
|
-
assert_equal exp.token,
|
31
|
-
assert_equal exp.text,
|
29
|
+
assert_equal exp.type, :conditional
|
30
|
+
assert_equal exp.token, :condition
|
31
|
+
assert_equal exp.text, '(<A>)'
|
32
|
+
assert_equal exp.reference, 'A'
|
32
33
|
end
|
33
34
|
|
35
|
+
def test_parse_conditional_condition_with_number_ref
|
36
|
+
regexp = /(a)(?(1)T|F)/
|
37
|
+
|
38
|
+
root = RP.parse(regexp, 'ruby/2.0')
|
39
|
+
exp = root[1].condition
|
40
|
+
|
41
|
+
assert exp.is_a?(Conditional::Condition),
|
42
|
+
"Expected Condition, but got #{exp.class.name}"
|
43
|
+
|
44
|
+
assert_equal exp.type, :conditional
|
45
|
+
assert_equal exp.token, :condition
|
46
|
+
assert_equal exp.text, '(1)'
|
47
|
+
assert_equal exp.reference, 1
|
48
|
+
end
|
34
49
|
|
35
50
|
def test_parse_conditional_nested_groups
|
36
51
|
regexp = /((a)|(b)|((?(2)(c(d|e)+)?|(?(3)f|(?(4)(g|(h)(i)))))))/
|
@@ -91,7 +106,6 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
91
106
|
end
|
92
107
|
end
|
93
108
|
|
94
|
-
|
95
109
|
def test_parse_conditional_nested_alternation
|
96
110
|
regexp = /(a)(?(1)(b|c|d)|(e|f|g))(h)(?(2)(i|j|k)|(l|m|n))|o|p/
|
97
111
|
|
@@ -114,7 +128,6 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
114
128
|
end
|
115
129
|
end
|
116
130
|
|
117
|
-
|
118
131
|
def test_parse_conditional_extra_separator
|
119
132
|
regexp = /(?<A>a)(?(<A>)T|)/
|
120
133
|
|
@@ -137,6 +150,30 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
137
150
|
assert_equal '', seq_2.to_s
|
138
151
|
end
|
139
152
|
|
153
|
+
def test_parse_conditional_quantified
|
154
|
+
regexp = /(foo)(?(1)\d|(\w)){42}/
|
155
|
+
|
156
|
+
root = RP.parse(regexp, 'ruby/2.0')
|
157
|
+
conditional = root[1]
|
158
|
+
|
159
|
+
assert conditional.quantified?
|
160
|
+
assert_equal '{42}', conditional.quantifier.text
|
161
|
+
refute conditional.branches.any?(&:quantified?)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_parse_conditional_branch_content_quantified
|
165
|
+
regexp = /(foo)(?(1)\d{23}|(\w){42})/
|
166
|
+
|
167
|
+
root = RP.parse(regexp, 'ruby/2.0')
|
168
|
+
conditional = root[1]
|
169
|
+
|
170
|
+
refute conditional.quantified?
|
171
|
+
refute conditional.branches.any?(&:quantified?)
|
172
|
+
assert conditional.branches[0][0].quantified?
|
173
|
+
assert_equal '{23}', conditional.branches[0][0].quantifier.text
|
174
|
+
assert conditional.branches[1][0].quantified?
|
175
|
+
assert_equal '{42}', conditional.branches[1][0].quantifier.text
|
176
|
+
end
|
140
177
|
|
141
178
|
# For source (text) expressions only, ruby raises an error otherwise.
|
142
179
|
def test_parse_conditional_excessive_branches
|
@@ -146,5 +183,4 @@ class TestParserConditionals < Test::Unit::TestCase
|
|
146
183
|
RP.parse(regexp, 'ruby/2.0')
|
147
184
|
}
|
148
185
|
end
|
149
|
-
|
150
186
|
end
|
data/test/parser/test_groups.rb
CHANGED
@@ -19,6 +19,9 @@ class TestParserGroups < Test::Unit::TestCase
|
|
19
19
|
assert_equal true, t.expressions[0].m?
|
20
20
|
assert_equal false, t.expressions[0].i?
|
21
21
|
assert_equal false, t.expressions[0].x?
|
22
|
+
|
23
|
+
assert_equal true, t.expressions[0].option_changes[:m]
|
24
|
+
assert_equal nil, t.expressions[0].option_changes[:i]
|
22
25
|
end
|
23
26
|
|
24
27
|
def test_parse_self_defeating_option_group
|
@@ -27,6 +30,9 @@ class TestParserGroups < Test::Unit::TestCase
|
|
27
30
|
assert_equal false, t.expressions[0].m?
|
28
31
|
assert_equal false, t.expressions[0].i?
|
29
32
|
assert_equal false, t.expressions[0].x?
|
33
|
+
|
34
|
+
assert_equal false, t.expressions[0].option_changes[:m]
|
35
|
+
assert_equal nil, t.expressions[0].option_changes[:i]
|
30
36
|
end
|
31
37
|
|
32
38
|
def test_parse_nested_options_activate_one
|
@@ -39,6 +45,10 @@ class TestParserGroups < Test::Unit::TestCase
|
|
39
45
|
assert_equal true, t.expressions[0].expressions[1].m?
|
40
46
|
assert_equal false, t.expressions[0].expressions[1].i?
|
41
47
|
assert_equal true, t.expressions[0].expressions[1].x?
|
48
|
+
|
49
|
+
assert_equal true, t.expressions[0].expressions[1].option_changes[:m]
|
50
|
+
assert_equal nil, t.expressions[0].expressions[1].option_changes[:i]
|
51
|
+
assert_equal nil, t.expressions[0].expressions[1].option_changes[:x]
|
42
52
|
end
|
43
53
|
|
44
54
|
def test_parse_nested_options_deactivate_one
|
@@ -51,6 +61,10 @@ class TestParserGroups < Test::Unit::TestCase
|
|
51
61
|
assert_equal false, t.expressions[0].expressions[1].m?
|
52
62
|
assert_equal false, t.expressions[0].expressions[1].i?
|
53
63
|
assert_equal true, t.expressions[0].expressions[1].x?
|
64
|
+
|
65
|
+
assert_equal false, t.expressions[0].expressions[1].option_changes[:i]
|
66
|
+
assert_equal nil, t.expressions[0].expressions[1].option_changes[:m]
|
67
|
+
assert_equal nil, t.expressions[0].expressions[1].option_changes[:x]
|
54
68
|
end
|
55
69
|
|
56
70
|
def test_parse_nested_options_invert_all
|
@@ -63,6 +77,10 @@ class TestParserGroups < Test::Unit::TestCase
|
|
63
77
|
assert_equal true, t.expressions[0].expressions[1].m?
|
64
78
|
assert_equal false, t.expressions[0].expressions[1].i?
|
65
79
|
assert_equal false, t.expressions[0].expressions[1].x?
|
80
|
+
|
81
|
+
assert_equal true, t.expressions[0].expressions[1].option_changes[:m]
|
82
|
+
assert_equal false, t.expressions[0].expressions[1].option_changes[:i]
|
83
|
+
assert_equal false, t.expressions[0].expressions[1].option_changes[:x]
|
66
84
|
end
|
67
85
|
|
68
86
|
def test_parse_nested_options_affect_literal_subexpressions
|
@@ -88,6 +106,10 @@ class TestParserGroups < Test::Unit::TestCase
|
|
88
106
|
assert_equal false, t.expressions[1].m?
|
89
107
|
assert_equal true, t.expressions[1].i?
|
90
108
|
assert_equal false, t.expressions[1].x?
|
109
|
+
|
110
|
+
assert_equal true, t.expressions[1].option_changes[:i]
|
111
|
+
assert_equal false, t.expressions[1].option_changes[:m]
|
112
|
+
assert_equal nil, t.expressions[1].option_changes[:x]
|
91
113
|
end
|
92
114
|
|
93
115
|
def test_parse_option_switch_affects_following_expressions
|
@@ -12,6 +12,13 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
12
12
|
assert_equal 0, exp.quantifier.min
|
13
13
|
assert_equal 1, exp.quantifier.max
|
14
14
|
assert_equal :greedy, exp.quantifier.mode
|
15
|
+
assert_equal true, exp.quantifier.greedy?
|
16
|
+
assert_equal true, exp.greedy?
|
17
|
+
|
18
|
+
assert_equal false, exp.quantifier.reluctant?
|
19
|
+
assert_equal false, exp.reluctant?
|
20
|
+
assert_equal false, exp.quantifier.possessive?
|
21
|
+
assert_equal false, exp.possessive?
|
15
22
|
end
|
16
23
|
|
17
24
|
def test_parse_zero_or_one_reluctant
|
@@ -23,7 +30,13 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
23
30
|
assert_equal 0, exp.quantifier.min
|
24
31
|
assert_equal 1, exp.quantifier.max
|
25
32
|
assert_equal :reluctant, exp.quantifier.mode
|
33
|
+
assert_equal true, exp.quantifier.reluctant?
|
26
34
|
assert_equal true, exp.reluctant?
|
35
|
+
|
36
|
+
assert_equal false, exp.quantifier.greedy?
|
37
|
+
assert_equal false, exp.greedy?
|
38
|
+
assert_equal false, exp.quantifier.possessive?
|
39
|
+
assert_equal false, exp.possessive?
|
27
40
|
end
|
28
41
|
|
29
42
|
def test_parse_zero_or_one_possessive
|
@@ -35,7 +48,13 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
35
48
|
assert_equal 0, exp.quantifier.min
|
36
49
|
assert_equal 1, exp.quantifier.max
|
37
50
|
assert_equal :possessive, exp.quantifier.mode
|
51
|
+
assert_equal true, exp.quantifier.possessive?
|
38
52
|
assert_equal true, exp.possessive?
|
53
|
+
|
54
|
+
assert_equal false, exp.quantifier.greedy?
|
55
|
+
assert_equal false, exp.greedy?
|
56
|
+
assert_equal false, exp.quantifier.reluctant?
|
57
|
+
assert_equal false, exp.reluctant?
|
39
58
|
end
|
40
59
|
|
41
60
|
# *: zero-or-more
|
@@ -48,6 +67,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
48
67
|
assert_equal 0, exp.quantifier.min
|
49
68
|
assert_equal(-1, exp.quantifier.max)
|
50
69
|
assert_equal :greedy, exp.quantifier.mode
|
70
|
+
assert_equal true, exp.quantifier.greedy?
|
71
|
+
assert_equal true, exp.greedy?
|
51
72
|
end
|
52
73
|
|
53
74
|
def test_parse_zero_or_more_reluctant
|
@@ -59,6 +80,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
59
80
|
assert_equal 0, exp.quantifier.min
|
60
81
|
assert_equal(-1, exp.quantifier.max)
|
61
82
|
assert_equal :reluctant, exp.quantifier.mode
|
83
|
+
assert_equal true, exp.quantifier.reluctant?
|
62
84
|
assert_equal true, exp.reluctant?
|
63
85
|
end
|
64
86
|
|
@@ -71,6 +93,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
71
93
|
assert_equal 0, exp.quantifier.min
|
72
94
|
assert_equal(-1, exp.quantifier.max)
|
73
95
|
assert_equal :possessive, exp.quantifier.mode
|
96
|
+
assert_equal true, exp.quantifier.possessive?
|
74
97
|
assert_equal true, exp.possessive?
|
75
98
|
end
|
76
99
|
|
@@ -84,6 +107,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
84
107
|
assert_equal 1, exp.quantifier.min
|
85
108
|
assert_equal(-1, exp.quantifier.max)
|
86
109
|
assert_equal :greedy, exp.quantifier.mode
|
110
|
+
assert_equal true, exp.quantifier.greedy?
|
111
|
+
assert_equal true, exp.greedy?
|
87
112
|
end
|
88
113
|
|
89
114
|
def test_parse_one_or_more_reluctant
|
@@ -95,6 +120,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
95
120
|
assert_equal 1, exp.quantifier.min
|
96
121
|
assert_equal(-1, exp.quantifier.max)
|
97
122
|
assert_equal :reluctant, exp.quantifier.mode
|
123
|
+
assert_equal true, exp.quantifier.reluctant?
|
98
124
|
assert_equal true, exp.reluctant?
|
99
125
|
end
|
100
126
|
|
@@ -107,6 +133,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
107
133
|
assert_equal 1, exp.quantifier.min
|
108
134
|
assert_equal(-1, exp.quantifier.max)
|
109
135
|
assert_equal :possessive, exp.quantifier.mode
|
136
|
+
assert_equal true, exp.quantifier.possessive?
|
110
137
|
assert_equal true, exp.possessive?
|
111
138
|
end
|
112
139
|
|
@@ -120,6 +147,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
120
147
|
assert_equal 2, exp.quantifier.min
|
121
148
|
assert_equal 4, exp.quantifier.max
|
122
149
|
assert_equal :greedy, exp.quantifier.mode
|
150
|
+
assert_equal true, exp.quantifier.greedy?
|
151
|
+
assert_equal true, exp.greedy?
|
123
152
|
end
|
124
153
|
|
125
154
|
def test_parse_intervals_min_max_reluctant
|
@@ -131,6 +160,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
131
160
|
assert_equal 3, exp.quantifier.min
|
132
161
|
assert_equal 5, exp.quantifier.max
|
133
162
|
assert_equal :reluctant, exp.quantifier.mode
|
163
|
+
assert_equal true, exp.quantifier.reluctant?
|
134
164
|
assert_equal true, exp.reluctant?
|
135
165
|
end
|
136
166
|
|
@@ -143,6 +173,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
143
173
|
assert_equal 2, exp.quantifier.min
|
144
174
|
assert_equal 4, exp.quantifier.max
|
145
175
|
assert_equal :possessive, exp.quantifier.mode
|
176
|
+
assert_equal true, exp.quantifier.possessive?
|
146
177
|
assert_equal true, exp.possessive?
|
147
178
|
end
|
148
179
|
|
@@ -156,6 +187,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
156
187
|
assert_equal 2, exp.quantifier.min
|
157
188
|
assert_equal(-1, exp.quantifier.max)
|
158
189
|
assert_equal :greedy, exp.quantifier.mode
|
190
|
+
assert_equal true, exp.quantifier.greedy?
|
191
|
+
assert_equal true, exp.greedy?
|
159
192
|
end
|
160
193
|
|
161
194
|
def test_parse_intervals_min_only_reluctant
|
@@ -168,6 +201,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
168
201
|
assert_equal 2, exp.quantifier.min
|
169
202
|
assert_equal(-1, exp.quantifier.max)
|
170
203
|
assert_equal :reluctant, exp.quantifier.mode
|
204
|
+
assert_equal true, exp.quantifier.reluctant?
|
171
205
|
assert_equal true, exp.reluctant?
|
172
206
|
end
|
173
207
|
|
@@ -181,6 +215,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
181
215
|
assert_equal 3, exp.quantifier.min
|
182
216
|
assert_equal(-1, exp.quantifier.max)
|
183
217
|
assert_equal :possessive, exp.quantifier.mode
|
218
|
+
assert_equal true, exp.quantifier.possessive?
|
184
219
|
assert_equal true, exp.possessive?
|
185
220
|
end
|
186
221
|
|
@@ -194,6 +229,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
194
229
|
assert_equal 0, exp.quantifier.min
|
195
230
|
assert_equal 2, exp.quantifier.max
|
196
231
|
assert_equal :greedy, exp.quantifier.mode
|
232
|
+
assert_equal true, exp.quantifier.greedy?
|
233
|
+
assert_equal true, exp.greedy?
|
197
234
|
end
|
198
235
|
|
199
236
|
def test_parse_intervals_max_only_reluctant
|
@@ -205,6 +242,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
205
242
|
assert_equal 0, exp.quantifier.min
|
206
243
|
assert_equal 4, exp.quantifier.max
|
207
244
|
assert_equal :reluctant, exp.quantifier.mode
|
245
|
+
assert_equal true, exp.quantifier.reluctant?
|
208
246
|
assert_equal true, exp.reluctant?
|
209
247
|
end
|
210
248
|
|
@@ -217,6 +255,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
217
255
|
assert_equal 0, exp.quantifier.min
|
218
256
|
assert_equal 3, exp.quantifier.max
|
219
257
|
assert_equal :possessive, exp.quantifier.mode
|
258
|
+
assert_equal true, exp.quantifier.possessive?
|
220
259
|
assert_equal true, exp.possessive?
|
221
260
|
end
|
222
261
|
|
@@ -230,6 +269,8 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
230
269
|
assert_equal 2, exp.quantifier.min
|
231
270
|
assert_equal 2, exp.quantifier.max
|
232
271
|
assert_equal :greedy, exp.quantifier.mode
|
272
|
+
assert_equal true, exp.quantifier.greedy?
|
273
|
+
assert_equal true, exp.greedy?
|
233
274
|
end
|
234
275
|
|
235
276
|
def test_parse_intervals_exact_reluctant
|
@@ -241,6 +282,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
241
282
|
assert_equal 3, exp.quantifier.min
|
242
283
|
assert_equal 3, exp.quantifier.max
|
243
284
|
assert_equal :reluctant, exp.quantifier.mode
|
285
|
+
assert_equal true, exp.quantifier.reluctant?
|
244
286
|
assert_equal true, exp.reluctant?
|
245
287
|
end
|
246
288
|
|
@@ -253,7 +295,7 @@ class TestRegexpParserQuantifiers < Test::Unit::TestCase
|
|
253
295
|
assert_equal 3, exp.quantifier.min
|
254
296
|
assert_equal 3, exp.quantifier.max
|
255
297
|
assert_equal :possessive, exp.quantifier.mode
|
298
|
+
assert_equal true, exp.quantifier.possessive?
|
256
299
|
assert_equal true, exp.possessive?
|
257
300
|
end
|
258
|
-
|
259
301
|
end
|
@@ -3,7 +3,7 @@ require File.expand_path("../../helpers", __FILE__)
|
|
3
3
|
class TestParserRefcalls < Test::Unit::TestCase
|
4
4
|
def test_parse_traditional_number_backref
|
5
5
|
root = RP.parse('(abc)\1', 'ruby/1.9')
|
6
|
-
exp = root
|
6
|
+
exp = root[1]
|
7
7
|
|
8
8
|
assert_instance_of Backreference::Number, exp
|
9
9
|
assert_equal 1, exp.number
|
@@ -11,7 +11,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
def test_parse_backref_named_ab
|
13
13
|
root = RP.parse('(?<X>abc)\k<X>', 'ruby/1.9')
|
14
|
-
exp = root
|
14
|
+
exp = root[1]
|
15
15
|
|
16
16
|
assert_instance_of Backreference::Name, exp
|
17
17
|
assert_equal 'X', exp.name
|
@@ -19,7 +19,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
19
19
|
|
20
20
|
def test_parse_backref_named_sq
|
21
21
|
root = RP.parse("(?<X>abc)\\k'X'", 'ruby/1.9')
|
22
|
-
exp = root
|
22
|
+
exp = root[1]
|
23
23
|
|
24
24
|
assert_instance_of Backreference::Name, exp
|
25
25
|
assert_equal 'X', exp.name
|
@@ -27,7 +27,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
27
27
|
|
28
28
|
def test_parse_backref_number_ab
|
29
29
|
root = RP.parse('(abc)\k<1>', 'ruby/1.9')
|
30
|
-
exp = root
|
30
|
+
exp = root[1]
|
31
31
|
|
32
32
|
assert_instance_of Backreference::Number, exp
|
33
33
|
assert_equal 1, exp.number
|
@@ -35,7 +35,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
35
35
|
|
36
36
|
def test_parse_backref_number_sq
|
37
37
|
root = RP.parse("(abc)\\k'1'", 'ruby/1.9')
|
38
|
-
exp = root
|
38
|
+
exp = root[1]
|
39
39
|
|
40
40
|
assert_instance_of Backreference::Number, exp
|
41
41
|
assert_equal 1, exp.number
|
@@ -43,7 +43,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
43
43
|
|
44
44
|
def test_parse_backref_number_relative_ab
|
45
45
|
root = RP.parse('(abc)\k<-1>', 'ruby/1.9')
|
46
|
-
exp = root
|
46
|
+
exp = root[1]
|
47
47
|
|
48
48
|
assert_instance_of Backreference::NumberRelative, exp
|
49
49
|
assert_equal(-1, exp.number)
|
@@ -51,7 +51,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
51
51
|
|
52
52
|
def test_parse_backref_number_relative_sq
|
53
53
|
root = RP.parse("(abc)\\k'-1'", 'ruby/1.9')
|
54
|
-
exp = root
|
54
|
+
exp = root[1]
|
55
55
|
|
56
56
|
assert_instance_of Backreference::NumberRelative, exp
|
57
57
|
assert_equal(-1, exp.number)
|
@@ -59,7 +59,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
59
59
|
|
60
60
|
def test_parse_backref_name_call_ab
|
61
61
|
root = RP.parse('(?<X>abc)\g<X>', 'ruby/1.9')
|
62
|
-
exp = root
|
62
|
+
exp = root[1]
|
63
63
|
|
64
64
|
assert_instance_of Backreference::NameCall, exp
|
65
65
|
assert_equal 'X', exp.name
|
@@ -67,7 +67,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
67
67
|
|
68
68
|
def test_parse_backref_name_call_sq
|
69
69
|
root = RP.parse("(?<X>abc)\\g'X'", 'ruby/1.9')
|
70
|
-
exp = root
|
70
|
+
exp = root[1]
|
71
71
|
|
72
72
|
assert_instance_of Backreference::NameCall, exp
|
73
73
|
assert_equal 'X', exp.name
|
@@ -75,7 +75,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
75
75
|
|
76
76
|
def test_parse_backref_number_call_ab
|
77
77
|
root = RP.parse('(abc)\g<1>', 'ruby/1.9')
|
78
|
-
exp = root
|
78
|
+
exp = root[1]
|
79
79
|
|
80
80
|
assert_instance_of Backreference::NumberCall, exp
|
81
81
|
assert_equal 1, exp.number
|
@@ -83,7 +83,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
83
83
|
|
84
84
|
def test_parse_backref_number_call_sq
|
85
85
|
root = RP.parse("(abc)\\g'1'", 'ruby/1.9')
|
86
|
-
exp = root
|
86
|
+
exp = root[1]
|
87
87
|
|
88
88
|
assert_instance_of Backreference::NumberCall, exp
|
89
89
|
assert_equal 1, exp.number
|
@@ -91,7 +91,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
91
91
|
|
92
92
|
def test_parse_backref_number_relative_call_ab
|
93
93
|
root = RP.parse('(abc)\g<-1>', 'ruby/1.9')
|
94
|
-
exp = root
|
94
|
+
exp = root[1]
|
95
95
|
|
96
96
|
assert_instance_of Backreference::NumberCallRelative, exp
|
97
97
|
assert_equal(-1, exp.number)
|
@@ -99,15 +99,31 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
99
99
|
|
100
100
|
def test_parse_backref_number_relative_call_sq
|
101
101
|
root = RP.parse("(abc)\\g'-1'", 'ruby/1.9')
|
102
|
-
exp = root
|
102
|
+
exp = root[1]
|
103
103
|
|
104
104
|
assert_instance_of Backreference::NumberCallRelative, exp
|
105
105
|
assert_equal(-1, exp.number)
|
106
106
|
end
|
107
107
|
|
108
|
+
def test_parse_backref_number_relative_forward_call_ab
|
109
|
+
root = RP.parse('\g<+1>(abc)', 'ruby/1.9')
|
110
|
+
exp = root[0]
|
111
|
+
|
112
|
+
assert_instance_of Backreference::NumberCallRelative, exp
|
113
|
+
assert_equal 1, exp.number
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_parse_backref_number_relative_forward_call_sq
|
117
|
+
root = RP.parse("\\g'+1'(abc)", 'ruby/1.9')
|
118
|
+
exp = root[0]
|
119
|
+
|
120
|
+
assert_instance_of Backreference::NumberCallRelative, exp
|
121
|
+
assert_equal 1, exp.number
|
122
|
+
end
|
123
|
+
|
108
124
|
def test_parse_backref_name_recursion_level_ab
|
109
125
|
root = RP.parse('(?<X>abc)\k<X-0>', 'ruby/1.9')
|
110
|
-
exp = root
|
126
|
+
exp = root[1]
|
111
127
|
|
112
128
|
assert_instance_of Backreference::NameRecursionLevel, exp
|
113
129
|
assert_equal 'X', exp.name
|
@@ -116,7 +132,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
116
132
|
|
117
133
|
def test_parse_backref_name_recursion_level_sq
|
118
134
|
root = RP.parse("(?<X>abc)\\k'X-0'", 'ruby/1.9')
|
119
|
-
exp = root
|
135
|
+
exp = root[1]
|
120
136
|
|
121
137
|
assert_instance_of Backreference::NameRecursionLevel, exp
|
122
138
|
assert_equal 'X', exp.name
|
@@ -125,7 +141,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
125
141
|
|
126
142
|
def test_parse_backref_number_recursion_level_ab
|
127
143
|
root = RP.parse('(abc)\k<1-0>', 'ruby/1.9')
|
128
|
-
exp = root
|
144
|
+
exp = root[1]
|
129
145
|
|
130
146
|
assert_instance_of Backreference::NumberRecursionLevel, exp
|
131
147
|
assert_equal 1, exp.number
|
@@ -134,7 +150,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
134
150
|
|
135
151
|
def test_parse_backref_number_recursion_level_sq
|
136
152
|
root = RP.parse("(abc)\\k'1-0'", 'ruby/1.9')
|
137
|
-
exp = root
|
153
|
+
exp = root[1]
|
138
154
|
|
139
155
|
assert_instance_of Backreference::NumberRecursionLevel, exp
|
140
156
|
assert_equal 1, exp.number
|
@@ -143,7 +159,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
143
159
|
|
144
160
|
def test_parse_backref_negative_number_recursion_level
|
145
161
|
root = RP.parse("(abc)\\k'-1+0'", 'ruby/1.9')
|
146
|
-
exp = root
|
162
|
+
exp = root[1]
|
147
163
|
|
148
164
|
assert_instance_of Backreference::NumberRecursionLevel, exp
|
149
165
|
assert_equal(-1, exp.number)
|
@@ -152,7 +168,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
152
168
|
|
153
169
|
def test_parse_backref_number_positive_recursion_level
|
154
170
|
root = RP.parse("(abc)\\k'1+1'", 'ruby/1.9')
|
155
|
-
exp = root
|
171
|
+
exp = root[1]
|
156
172
|
|
157
173
|
assert_instance_of Backreference::NumberRecursionLevel, exp
|
158
174
|
assert_equal 1, exp.number
|
@@ -161,7 +177,7 @@ class TestParserRefcalls < Test::Unit::TestCase
|
|
161
177
|
|
162
178
|
def test_parse_backref_number_negative_recursion_level
|
163
179
|
root = RP.parse("(abc)\\k'1-1'", 'ruby/1.9')
|
164
|
-
exp = root
|
180
|
+
exp = root[1]
|
165
181
|
|
166
182
|
assert_instance_of Backreference::NumberRecursionLevel, exp
|
167
183
|
assert_equal 1, exp.number
|
data/test/scanner/test_all.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require File.expand_path("../../helpers", __FILE__)
|
2
2
|
|
3
|
-
%w
|
4
|
-
anchors errors escapes free_space groups literals
|
5
|
-
|
6
|
-
|
3
|
+
%w[
|
4
|
+
anchors errors escapes free_space groups literals meta
|
5
|
+
properties quantifiers refcalls scripts sets types unicode_blocks
|
6
|
+
].each do |tc|
|
7
7
|
require File.expand_path("../test_#{tc}", __FILE__)
|
8
8
|
end
|
9
9
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require File.expand_path("../../helpers", __FILE__)
|
2
2
|
|
3
3
|
class ScannerRefCalls < Test::Unit::TestCase
|
4
|
-
|
5
4
|
tests = {
|
6
5
|
# Traditional numerical group back-reference
|
7
6
|
'(abc)\1' => [3, :backref, :number, '\1', 5, 7],
|
@@ -26,6 +25,9 @@ class ScannerRefCalls < Test::Unit::TestCase
|
|
26
25
|
'(abc)\g<-1>' => [3, :backref, :number_rel_call_ab, '\g<-1>', 5, 11],
|
27
26
|
"(abc)\\g'-1'" => [3, :backref, :number_rel_call_sq, "\\g'-1'", 5, 11],
|
28
27
|
|
28
|
+
'\g<+1>(abc)' => [0, :backref, :number_rel_call_ab, '\g<+1>', 0, 6],
|
29
|
+
"\\g'+1'(abc)" => [0, :backref, :number_rel_call_sq, "\\g'+1'", 0, 6],
|
30
|
+
|
29
31
|
# Group back-references, with recursion level
|
30
32
|
'(?<X>abc)\k<X-0>' => [3, :backref, :name_recursion_ref_ab, '\k<X-0>', 9, 16],
|
31
33
|
"(?<X>abc)\\k'X-0'" => [3, :backref, :name_recursion_ref_sq, "\\k'X-0'", 9, 16],
|
@@ -47,5 +49,4 @@ class ScannerRefCalls < Test::Unit::TestCase
|
|
47
49
|
assert_equal text, pattern[ts, te]
|
48
50
|
end
|
49
51
|
end
|
50
|
-
|
51
52
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: regexp_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ammar Ali
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A library for tokenizing, lexing, and parsing Ruby regular expressions.
|
14
14
|
email:
|