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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a48ea55ff32a9a023b9f07c13590acbafa412fbb4e8289f4ac8b825c37f9dc5
4
- data.tar.gz: 5fd466646d0e9cfc22cae4f4d4dce1e2647d066d49ad230d6f09a98f790c2be6
3
+ metadata.gz: 467bef34ff29198ccbde0063f1b2f62f03cf8237c46fe59be8f06e974c00c367
4
+ data.tar.gz: b876e662f889449954f0beeddedded8e462b4daec5fbb4692b65f9f7a012fec8
5
5
  SHA512:
6
- metadata.gz: b1b26d0a1431ebd9a00423a98f58abfd5098e5f625b075270b13ed34c73e9b0bc74cdb6fb5b50ca84f6aad2786df86d2128ace3a7e645571a11656580ca64dfe
7
- data.tar.gz: 1536cf6aaa222823fc5319a03aa67a7cc157d60a47ce41e70384d86a986c42de2f252a0c9ca7088b87cb1dd4d89a666d0d7080bf5e9d18e0c3e54b20aa9f5606
6
+ metadata.gz: b2064de034cf83f157da79225fc587374f744884f37934fd1828e4f3127bc45f899d62986495d9344fd4a5f2e96f7b2cf90c7961c0895fd0ee52ab8e24428d67
7
+ data.tar.gz: 146440a8fc9e2c48bb1bdedad539f6883ecbc5874276eb3e56876df7b74e42630ec789f6cc6b4ca7e79d5e6b2e986b5a2f5b2fc0be4d273c02d8ff62fa2cd35c
data/CHANGELOG.md CHANGED
@@ -1,54 +1,71 @@
1
- ## [Unreleased]
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
- * #scan now emits the same tokens as outside sets (no longer :set, :member)
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 #negative?
15
- * #scan emits :(non)posixclass, :<type> instead of :set, :char_(non)<type>
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]"]; used to be ["[a]", "a"]
19
- - Changed Expression emissions for some escape sequences
20
- * EscapeSequence::Codepoint, CodepointList, Hex and Octal are now all used
21
- * they already existed, but were all parsed as EscapeSequence::Literal
22
- * e.g. \x97 is now EscapeSequence::Hex instead of EscapeSequence::Literal
23
- - Changed naming of many property tokens (emitted for \p{...})
24
- * if you work with these tokens, see PR #56 for details
25
- * e.g. :punct_dash is now :dash_punctuation
26
- - Changed (?m) and the likes to emit as :options_switch token (@4ade4d1)
27
- * allows differentiating from group-local :options, e.g. (?m:.)
28
- - Changed name of Backreference::..NestLevel to ..RecursionLevel (@4184339)
29
- - Changed Backreference::Number#number from String to Integer (@40a2231)
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 "\p{mark}")
35
- - Added #char(s) and #codepoint(s) methods to all EscapeSequence expressions
36
- - Added #number/#name/#recursion_level to all backref/call expressions (@174bf21)
37
- - Added #number and #number_at_level to capturing group expressions (@40a2231)
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 ruby version mapping of some properties
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. \u{10FFFF})
45
- - Fixed scanning of \R and \X within sets; they act as literals there
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 | &#x22ef; |
318
318
  | ------------------------------------- | ------------------------------------------------------- |:--------:|
319
319
  | **Alternation** | `a\|b\|c` | &#x2713; |
320
- | **Anchors** | `^`, `$`, `\b` | &#x2713; |
320
+ | **Anchors** | `\A`, `^`, `\b` | &#x2713; |
321
321
  | **Character Classes** | `[abc]`, `[^\\]`, `[a-d&&g-h]`, `[a=e=b]` | &#x2713; |
322
322
  | **Character Types** | `\d`, `\H`, `\s` | &#x2713; |
323
323
  | **Cluster Types** | `\R`, `\X` | &#x2713; |
@@ -341,7 +341,7 @@ _Note that not all of these are available in all versions of Ruby_
341
341
  | &emsp;&nbsp;_**Capturing**_ | `(abc)` | &#x2713; |
342
342
  | &emsp;&nbsp;_**Comments**_ | `(?# comment text)` | &#x2713; |
343
343
  | &emsp;&nbsp;_**Named**_ | `(?<name>abc)`, `(?'name'abc)` | &#x2713; |
344
- | &emsp;&nbsp;_**Options**_ | `(?mi-x:abc)`, `(?a:\s\w+)` | &#x2713; |
344
+ | &emsp;&nbsp;_**Options**_ | `(?mi-x:abc)`, `(?a:\s\w+)`, `(?i)` | &#x2713; |
345
345
  | &emsp;&nbsp;_**Passive**_ | `(?:abc)` | &#x2713; |
346
346
  | &emsp;&nbsp;_**Subexp. Calls**_ | `\g<name>`, `\g<1>` | &#x2713; |
347
347
  | **Keep** | `\K`, `(ab\Kc\|d\Ke)f` | &#x2713; |
@@ -357,14 +357,14 @@ _Note that not all of these are available in all versions of Ruby_
357
357
  | &emsp;&nbsp;_**Meta**_ | `\M-c`, `\M-\C-C`, `\M-\cC`, `\C-\M-C`, `\c\M-C` | &#x2713; |
358
358
  | &emsp;&nbsp;_**Octal**_ | `\0`, `\01`, `\012` | &#x2713; |
359
359
  | &emsp;&nbsp;_**Unicode**_ | `\uHHHH`, `\u{H+ H+}` | &#x2713; |
360
- | **Unicode Properties** | _<sub>([Unicode 7.0.0](http://www.unicode.org/versions/Unicode7.0.0/))</sub>_ | &#x22f1; |
361
- | &emsp;&nbsp;_**Age**_ | `\p{Age=5.2}`, `\P{age=7.0}` | &#x2713; |
362
- | &emsp;&nbsp;_**Blocks**_ | `\p{InArmenian}`, `\P{InKhmer}` | &#x2713; |
363
- | &emsp;&nbsp;_**Classes**_ | `\p{Alpha}`, `\P{Space}` | &#x2713; |
364
- | &emsp;&nbsp;_**Derived**_ | `\p{Math}`, `\P{Lowercase}` | &#x2713; |
365
- | &emsp;&nbsp;_**General Categories**_ | `\p{Lu}`, `\P{Cs}` | &#x2713; |
366
- | &emsp;&nbsp;_**Scripts**_ | `\p{Arabic}`, `\P{Hiragana}` | &#x2713; |
367
- | &emsp;&nbsp;_**Simple**_ | `\p{Dash}`, `\p{Extender}` | &#x2713; |
360
+ | **Unicode Properties** | _<sub>([Unicode 10.0.0](http://www.unicode.org/versions/Unicode10.0.0/))</sub>_ | &#x22f1; |
361
+ | &emsp;&nbsp;_**Age**_ | `\p{Age=5.2}`, `\P{age=7.0}`, `\p{^age=8.0}` | &#x2713; |
362
+ | &emsp;&nbsp;_**Blocks**_ | `\p{InArmenian}`, `\P{InKhmer}`, `\p{^InThai}` | &#x2713; |
363
+ | &emsp;&nbsp;_**Classes**_ | `\p{Alpha}`, `\P{Space}`, `\p{^Alnum}` | &#x2713; |
364
+ | &emsp;&nbsp;_**Derived**_ | `\p{Math}`, `\P{Lowercase}`, `\p{^Cased}` | &#x2713; |
365
+ | &emsp;&nbsp;_**General Categories**_ | `\p{Lu}`, `\P{Cs}`, \p{^sc} | &#x2713; |
366
+ | &emsp;&nbsp;_**Scripts**_ | `\p{Arabic}`, `\P{Hiragana}`, \p{^Greek} | &#x2713; |
367
+ | &emsp;&nbsp;_**Simple**_ | `\p{Dash}`, `\p{Extender}`, \p{^Hyphen} | &#x2713; |
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.mode == :greedy
75
+ quantified? and quantifier.greedy?
76
76
  end
77
77
 
78
78
  def reluctant?
79
- quantified? and quantifier.mode == :reluctant
79
+ quantified? and quantifier.reluctant?
80
80
  end
81
81
  alias :lazy? :reluctant?
82
82
 
83
83
  def possessive?
84
- quantified? and quantifier.mode == :possessive
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; end
11
- class Branch < Regexp::Expression::Sequence; end
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 Expression < Regexp::Expression::Subexpression
14
- attr_reader :branches, :condition
18
+ class Branch < Regexp::Expression::Sequence; end
15
19
 
16
- def initialize(token, options = {})
17
- super
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 branch(exp = nil)
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
- sequence = Branch.new(level, set_level, conditional_level + 1)
34
-
35
- expressions << sequence
36
- branches << expressions.last
38
+ def branches
39
+ expressions - [condition]
37
40
  end
38
41
 
39
- def quantify(token, text, min = nil, max = nil, mode = :greedy)
40
- branches.last.last.quantify(token, text, min, max, mode)
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
- def initialize(options = {})
5
- super(Regexp::Token.new(:expression, :root, '', 0), options)
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
- alias ignore_case? case_insensitive?
9
- alias extended? free_spacing?
10
- end
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
@@ -58,6 +58,5 @@ module Regexp::Expression
58
58
 
59
59
  result
60
60
  end
61
-
62
61
  end
63
62
  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 and Conditional
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
- def initialize(level, set_level, conditional_level)
11
- super Regexp::Token.new(
12
- :expression,
13
- :sequence,
14
- '',
15
- nil, # ts
16
- nil, # te
17
- level,
18
- set_level,
19
- conditional_level
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
- exp = self.class::OPERAND.new(level, set_level, conditional_level)
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 |m|
29
- define_method(m) { |*args, &block| expressions.send(m, *args, &block) }
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
@@ -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.new(options_from_input(input))
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
- node << exp
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
- new_options = active_opts.dup
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
- new_options[flag.to_sym] = true if positive.include?(flag)
504
- new_options.delete(flag.to_sym) if negative.include?(flag)
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| new_options.delete(key.to_sym) }
512
- new_options[flag.to_sym] = true
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 << new_options
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(Group::Options.new(token, active_opts))
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-](\w+)?>/ # angle-brackets
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-](\w+)?'/ #single quotes
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 /^\\([gk])<-\d+>/ # angle-brackets
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 /^\\([gk])'-\d+'/ # single quotes
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-](\w+)?[+\-]\d+>/ # angle-brackets
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-](\w+)?[+\-]\d+'/ # single-quotes
2179
+ when /^\\k'[^\d+\-]\w*[+\-]\d+'/ # single-quotes
2180
2180
  emit(:backref, :name_recursion_ref_sq, text, ts, te)
2181
2181
 
2182
- when /^\\([gk])<-?\d+[+\-]\d+>/ # angle-brackets
2182
+ when /^\\([gk])<[+\-]?\d+[+\-]\d+>/ # angle-brackets
2183
2183
  emit(:backref, :number_recursion_ref_ab, text, ts, te)
2184
2184
 
2185
- when /^\\([gk])'-?\d+[+\-]\d+'/ # single-quotes
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-](\w+)?>/ # angle-brackets
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-](\w+)?'/ #single quotes
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 /^\\([gk])<-\d+>/ # angle-brackets
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 /^\\([gk])'-\d+'/ # single quotes
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-](\w+)?[+\-]\d+>/ # angle-brackets
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-](\w+)?[+\-]\d+'/ # single-quotes
630
+ when /^\\k'[^\d+\-]\w*[+\-]\d+'/ # single-quotes
631
631
  emit(:backref, :name_recursion_ref_sq, text, ts, te)
632
632
 
633
- when /^\\([gk])<-?\d+[+\-]\d+>/ # angle-brackets
633
+ when /^\\([gk])<[+\-]?\d+[+\-]\d+>/ # angle-brackets
634
634
  emit(:backref, :number_recursion_ref_ab, text, ts, te)
635
635
 
636
- when /^\\([gk])'-?\d+[+\-]\d+'/ # single-quotes
636
+ when /^\\([gk])'[+\-]?\d+[+\-]\d+'/ # single-quotes
637
637
  emit(:backref, :number_recursion_ref_sq, text, ts, te)
638
638
 
639
639
  else
@@ -1,5 +1,5 @@
1
1
  class Regexp
2
2
  class Parser
3
- VERSION = '1.0.0'
3
+ VERSION = '1.1.0'
4
4
  end
5
5
  end
@@ -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
@@ -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],
@@ -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
- }.each do|tc|
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{conditionals keep}.each do|tc|
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, :conditional
15
- assert_equal exp.token, :open
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, :conditional
30
- assert_equal exp.token, :condition
31
- assert_equal exp.text, '(<A>)'
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
@@ -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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
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.expressions.at(1)
180
+ exp = root[1]
165
181
 
166
182
  assert_instance_of Backreference::NumberRecursionLevel, exp
167
183
  assert_equal 1, exp.number
@@ -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
- meta properties quantifiers scripts sets types unicode_blocks
6
- }.each do|tc|
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.0.0
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-01 00:00:00.000000000 Z
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: