regexp_parser 1.0.0 → 1.1.0

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