File tree Expand file tree Collapse file tree 8 files changed +53
-40
lines changed Expand file tree Collapse file tree 8 files changed +53
-40
lines changed Original file line number Diff line number Diff line change @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
8
8
## [ Unreleased]
9
9
10
+ ### Added
11
+
12
+ - ` #referenced_expressions `
13
+ - like ` #referenced_expression ` , but for multiplexing backrefs
14
+ - returns the ` Group ` expressions that are being referenced
15
+
10
16
### Fixed
11
17
12
18
- fixed ` #char ` & ` #codepoint ` errors for single-digit hex escapes
Original file line number Diff line number Diff line change 34
34
require_relative 'expression/methods/options'
35
35
require_relative 'expression/methods/parts'
36
36
require_relative 'expression/methods/printing'
37
+ require_relative 'expression/methods/referenced_expressions'
37
38
require_relative 'expression/methods/strfregexp'
38
39
require_relative 'expression/methods/tests'
39
40
require_relative 'expression/methods/traverse'
Original file line number Diff line number Diff line change 1
1
module Regexp ::Expression
2
2
module Backreference
3
- class Base < Regexp ::Expression ::Base
4
- attr_accessor :referenced_expression
5
-
6
- def initialize_copy ( orig )
7
- exp_id = [ self . class , self . starts_at ]
8
-
9
- # prevent infinite recursion for recursive subexp calls
10
- copied = @@copied ||= { }
11
- self . referenced_expression =
12
- if copied [ exp_id ]
13
- orig . referenced_expression
14
- else
15
- copied [ exp_id ] = true
16
- orig . referenced_expression . dup
17
- end
18
- copied . clear
19
-
20
- super
21
- end
22
- end
3
+ class Base < Regexp ::Expression ::Base ; end
23
4
24
5
class Number < Backreference ::Base
25
6
attr_reader :number
Original file line number Diff line number Diff line change @@ -7,26 +7,17 @@ def initialize
7
7
end
8
8
9
9
class Condition < Regexp ::Expression ::Base
10
- attr_accessor :referenced_expression
11
-
12
10
# Name or number of the referenced capturing group that determines state.
13
11
# Returns a String if reference is by name, Integer if by number.
14
12
def reference
15
13
ref = text . tr ( "'<>()" , "" )
16
14
ref =~ /\D / ? ref : Integer ( ref )
17
15
end
18
-
19
- def initialize_copy ( orig )
20
- self . referenced_expression = orig . referenced_expression . dup
21
- super
22
- end
23
16
end
24
17
25
18
class Branch < Regexp ::Expression ::Sequence ; end
26
19
27
20
class Expression < Regexp ::Expression ::Subexpression
28
- attr_accessor :referenced_expression
29
-
30
21
def <<( exp )
31
22
expressions . last << exp
32
23
end
@@ -54,11 +45,6 @@ def branches
54
45
def reference
55
46
condition . reference
56
47
end
57
-
58
- def initialize_copy ( orig )
59
- self . referenced_expression = orig . referenced_expression . dup
60
- super
61
- end
62
48
end
63
49
end
64
50
end
Original file line number Diff line number Diff line change
1
+ module Regexp ::Expression
2
+ module ReferencedExpressions
3
+ attr_accessor :referenced_expressions
4
+
5
+ def referenced_expression
6
+ referenced_expressions && referenced_expressions . first
7
+ end
8
+
9
+ def initialize_copy ( orig )
10
+ exp_id = [ self . class , self . starts_at ]
11
+
12
+ # prevent infinite recursion for recursive subexp calls
13
+ copied = self . class . instance_eval { @copied_ref_exps ||= { } }
14
+ self . referenced_expressions =
15
+ if copied [ exp_id ]
16
+ orig . referenced_expressions
17
+ else
18
+ copied [ exp_id ] = true
19
+ orig . referenced_expressions && orig . referenced_expressions . map ( &:dup )
20
+ end
21
+ copied . clear
22
+
23
+ super
24
+ end
25
+ end
26
+
27
+ Base . include ReferencedExpressions
28
+ end
Original file line number Diff line number Diff line change @@ -580,16 +580,19 @@ def active_opts
580
580
# the instance of Group::Capture that it refers to via its number.
581
581
def assign_referenced_expressions
582
582
# find all referenceable and referring expressions
583
- targets = { 0 => root }
583
+ targets = { 0 => [ root ] }
584
584
referrers = [ ]
585
585
root . each_expression do |exp |
586
- exp . is_a? ( Group ::Capture ) && targets [ exp . identifier ] = exp
587
- referrers << exp if exp . referential?
586
+ if exp . referential?
587
+ referrers << exp
588
+ elsif exp . is_a? ( Group ::Capture )
589
+ ( targets [ exp . identifier ] ||= [ ] ) << exp
590
+ end
588
591
end
589
- # assign reference expression to referring expressions
592
+ # assign referenced expressions to referring expressions
590
593
# (in a second iteration because there might be forward references)
591
594
referrers . each do |exp |
592
- exp . referenced_expression = targets [ exp . reference ] ||
595
+ exp . referenced_expressions = targets [ exp . reference ] ||
593
596
raise ( ParserError , "Invalid reference #{ exp . reference } at pos #{ exp . ts } " )
594
597
end
595
598
end
Original file line number Diff line number Diff line change 32
32
33
33
specify ( 'raises for missing references' ) do
34
34
exp = RP . parse ( /(a)\1 / ) . last
35
- exp . referenced_expression = nil
35
+ exp . referenced_expressions = nil
36
36
expect { exp . match_length } . to raise_error ( ArgumentError )
37
37
end
38
38
Original file line number Diff line number Diff line change 59
59
expect ( exp3 . referenced_expression . to_s ) . to eq '(ghi)'
60
60
end
61
61
62
+ specify ( 'parse backref referenced_expressions (multiplex)' ) do
63
+ root = RP . parse ( '(?<a>A)(?<a>B)\\k<a>' )
64
+ exp = root . last
65
+
66
+ expect ( exp . referenced_expressions ) . to eq [ root [ 0 ] , root [ 1 ] ]
67
+ expect ( exp . referenced_expressions . map ( &:to_s ) ) . to eq [ '(?<a>A)' , '(?<a>B)' ]
68
+ end
69
+
62
70
specify ( 'parse backref call referenced_expression' ) do
63
71
root = RP . parse ( '\\g<+1>(abc)\\g<+2>(def)(ghi)\\g<-2>' )
64
72
exp1 = root [ 0 ]
You can’t perform that action at this time.
0 commit comments