regexp_parser 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|