tdparser 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README +5 -0
- data/Rakefile +4 -0
- data/lib/tdparser/action_parser.rb +29 -0
- data/lib/tdparser/any_parser.rb +20 -0
- data/lib/tdparser/backref_parser.rb +29 -0
- data/lib/tdparser/buffer_utils.rb +13 -0
- data/lib/tdparser/choice_parser.rb +80 -0
- data/lib/tdparser/composite_parser.rb +29 -0
- data/lib/tdparser/concat_parser.rb +21 -0
- data/lib/tdparser/condition_parser.rb +28 -0
- data/lib/tdparser/empty_parser.rb +15 -0
- data/lib/tdparser/fail_parser.rb +15 -0
- data/lib/tdparser/grammar.rb +23 -0
- data/lib/tdparser/iteration_parser.rb +73 -0
- data/lib/tdparser/label_parser.rb +25 -0
- data/lib/tdparser/negative_parser.rb +17 -0
- data/lib/tdparser/non_terminal_parser.rb +33 -0
- data/lib/tdparser/none_parser.rb +18 -0
- data/lib/tdparser/parallel_parser.rb +18 -0
- data/lib/tdparser/parser.rb +104 -0
- data/lib/tdparser/reference_parser.rb +23 -0
- data/lib/tdparser/sequence.rb +7 -0
- data/lib/tdparser/stack_parser.rb +29 -0
- data/lib/tdparser/stackref_parser.rb +29 -0
- data/lib/tdparser/state_parser.rb +28 -0
- data/lib/tdparser/terminal_parser.rb +28 -0
- data/lib/tdparser/token_buffer.rb +43 -0
- data/lib/tdparser/token_generator.rb +43 -0
- data/lib/tdparser/utils.rb +3 -3
- data/lib/tdparser/version.rb +1 -1
- data/lib/tdparser/xml.rb +13 -11
- data/lib/tdparser.rb +45 -799
- data/sig/tdparser.rbs +334 -0
- data/updoc +11 -0
- metadata +32 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9df17ece1521def452aa92e124da446abd512000073b36a989e53fb0f5032574
|
4
|
+
data.tar.gz: 1f1766675086fcba1870127d05419eaa5aa6de6f436347fad23f7b5d37afc8c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3821c0d37e95f49d3db3fe8230ba9e662cb9bb648497698dac95c34c0507396d78c02720943ab1cd4028f457c930e90f37a93024b68a2bf06664498ef7290357
|
7
|
+
data.tar.gz: c8ac3e9fca74e15a1a888f376ff9058fdb797f6944876a3f77f224dd4de4cf20f7ed88891b115d7138c624cb91a07bed0144f1cc8d0ee1a96b97a1275ed02295
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## 1.6.0 - 2024-11-17
|
4
|
+
|
5
|
+
* Add more readable method aliases.
|
6
|
+
* Make token buffer's state accessible attribute.
|
7
|
+
* Split files such as parsers. You might need to require individual files.
|
8
|
+
* Change token buffer class not to inherit from array class.
|
9
|
+
* Move XML token generator class to upper namespace.
|
10
|
+
|
3
11
|
## 1.5.1 - 2024-11-10
|
4
12
|
|
5
13
|
This is a maintenance release, no user facing changes.
|
data/README
CHANGED
@@ -23,6 +23,11 @@ the feature of (2), we need not consider how to prevent conflicts
|
|
23
23
|
among production rules. In addition, TDParser can be viewed as an
|
24
24
|
internal DSL for writing LL(k) grammars because of (3).
|
25
25
|
|
26
|
+
Repository is located at:
|
27
|
+
|
28
|
+
* Disroot[https://git.disroot.org/gemmaro/tdparser]
|
29
|
+
* GitHub[https://github.com/gemmaro/tdparser] (for GitHub Pages)
|
30
|
+
|
26
31
|
== License
|
27
32
|
|
28
33
|
Copyright(C) 2003, 2004, 2005, 2006 Takaaki Tateishi <ttate@ttsky.net>
|
data/Rakefile
CHANGED
@@ -16,3 +16,7 @@ Rake::TestTask.new do |t|
|
|
16
16
|
t.libs << 'samples' << 'test'
|
17
17
|
t.test_files = FileList['test/*_test.rb']
|
18
18
|
end
|
19
|
+
|
20
|
+
task :gensig do
|
21
|
+
sh 'typeprof', '-r', 'forwardable', '-r', 'strscan', '-r', 'enumerable', '-o', 'sig/tdparser.gen.rbs', 'sig/tdparser.rbs', *Dir['lib/**/*.rb']
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ActionParser < CompositeParser # :nodoc:
|
3
|
+
attr_reader :action
|
4
|
+
|
5
|
+
def initialize(parser, act)
|
6
|
+
@action = act
|
7
|
+
super(parser)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(tokens, buff)
|
11
|
+
if (x = @parsers[0].call(tokens, buff)).nil?
|
12
|
+
nil
|
13
|
+
else
|
14
|
+
x = TokenBuffer[*x]
|
15
|
+
x.map = buff.map
|
16
|
+
Sequence[@action[x]]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
super(other) &&
|
22
|
+
(@action == other.action)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"(#{@parsers[0]} <action>)"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TDParser
|
2
|
+
class BackrefParser < ReferenceParser # :nodoc:
|
3
|
+
attr_reader :label, :equality
|
4
|
+
|
5
|
+
def initialize(label, eqsym)
|
6
|
+
@label = label
|
7
|
+
@equality = eqsym
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(tokens, buff)
|
11
|
+
ys = buff.map[@label]
|
12
|
+
if ys.nil? || ys.empty?
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
back_ref(ys.dup, @equality).call(tokens, buff)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"<backref:#{@label}>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
super(other) &&
|
25
|
+
(@label == other.label) &&
|
26
|
+
(@equality == other.equality)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ChoiceParser < CompositeParser # :nodoc:
|
3
|
+
def call(tokens, buff)
|
4
|
+
b = prepare(buff)
|
5
|
+
if (x = @parsers[0].call(tokens, b)).nil?
|
6
|
+
recover(b, tokens)
|
7
|
+
@parsers[1].call(tokens, buff)
|
8
|
+
else
|
9
|
+
buff.insert(0, *b)
|
10
|
+
x
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"(#{@parsers[0]} | #{@parsers[1]})"
|
16
|
+
end
|
17
|
+
|
18
|
+
def shared_sequence(r1, r2)
|
19
|
+
if r1.is_a?(ConcatParser) && r2.is_a?(ConcatParser)
|
20
|
+
r11 = r1.parsers[0]
|
21
|
+
r12 = r1.parsers[1]
|
22
|
+
r21 = r2.parsers[0]
|
23
|
+
r22 = r2.parsers[1]
|
24
|
+
if r11.same?(r21)
|
25
|
+
share, r12, r22, = shared_sequence(r12, r22)
|
26
|
+
return [r11 - share, r12, r22] if share
|
27
|
+
|
28
|
+
return [r11, r12, r22]
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
[nil, r1, r2]
|
33
|
+
end
|
34
|
+
|
35
|
+
def optimize(default = false)
|
36
|
+
r1 = @parsers[0]
|
37
|
+
r2 = @parsers[1]
|
38
|
+
if r1.is_a?(ActionParser)
|
39
|
+
act1 = r1.action
|
40
|
+
r1 = r1.parsers[0]
|
41
|
+
end
|
42
|
+
if r2.is_a?(ActionParser)
|
43
|
+
act2 = r2.action
|
44
|
+
r2 = r2.parsers[0]
|
45
|
+
end
|
46
|
+
share, r12, r22, = shared_sequence(r1, r2)
|
47
|
+
if share
|
48
|
+
r = share - (r12 + r22)
|
49
|
+
if act1
|
50
|
+
r = if act2
|
51
|
+
r >> proc do |x|
|
52
|
+
y0, y1, *_ = x.pop
|
53
|
+
if y0
|
54
|
+
act1.call(x.push(*y0))
|
55
|
+
else
|
56
|
+
act2.call(x.push(*y1))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
r >> proc do |x|
|
61
|
+
y0, = x.pop
|
62
|
+
act1.call(x.push(*y0)) if y0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
elsif act2
|
66
|
+
r = r >> proc do |x|
|
67
|
+
_, y1, = x.pop
|
68
|
+
act2.call(x.push(*y1)) if y1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
return r
|
72
|
+
end
|
73
|
+
if default
|
74
|
+
dup
|
75
|
+
else
|
76
|
+
super(default)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TDParser
|
2
|
+
class CompositeParser < Parser # :nodoc:
|
3
|
+
attr_accessor :parsers
|
4
|
+
|
5
|
+
def initialize(*parsers)
|
6
|
+
@parsers = parsers
|
7
|
+
end
|
8
|
+
|
9
|
+
def optimize(default = false)
|
10
|
+
parser = dup
|
11
|
+
parser.parsers = @parsers.collect { |x| x.optimize(default) }
|
12
|
+
parser
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
(self.class == other.class) &&
|
17
|
+
(@parsers == other.parsers)
|
18
|
+
end
|
19
|
+
|
20
|
+
def same?(r)
|
21
|
+
super(r) &&
|
22
|
+
@parsers.zip(r.parsers).all? { |x, y| x.same?(y) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"<composite: #{@parsers.collect(&:to_s)}>"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ConcatParser < CompositeParser # :nodoc:
|
3
|
+
def call(tokens, buff)
|
4
|
+
if (x = @parsers[0].call(tokens, buff)).nil?
|
5
|
+
nil
|
6
|
+
elsif (y = @parsers[1].call(tokens, buff)).nil?
|
7
|
+
nil
|
8
|
+
else
|
9
|
+
x + y
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def -(other)
|
14
|
+
@parsers[0] - (@parsers[1] - other)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"(#{@parsers[0]} #{@parsers[1]})"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ConditionParser < Parser # :nodoc:
|
3
|
+
attr_reader :condition
|
4
|
+
|
5
|
+
def initialize(&condition)
|
6
|
+
@condition = condition
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(_tokens, buff)
|
10
|
+
return unless (res = @condition.call(buff.map))
|
11
|
+
|
12
|
+
Sequence[res]
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"<condition:#{@condition}>"
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
super(other) &&
|
21
|
+
(@condition == other.condition)
|
22
|
+
end
|
23
|
+
|
24
|
+
def same?(_r)
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TDParser
|
2
|
+
class Grammar # :nodoc:
|
3
|
+
include TDParser
|
4
|
+
|
5
|
+
alias define instance_eval
|
6
|
+
|
7
|
+
def method_missing(sym, *args)
|
8
|
+
if sym[-1, 1] == '='
|
9
|
+
parser, = args
|
10
|
+
name = sym[0..-2]
|
11
|
+
parser.is_a?(Parser) or parser = token(parser)
|
12
|
+
self.class.instance_eval do
|
13
|
+
instance_methods.include?(name.intern) or
|
14
|
+
define_method(name) { parser }
|
15
|
+
end
|
16
|
+
elsif args.empty?
|
17
|
+
rule(sym)
|
18
|
+
else
|
19
|
+
raise(NoMethodError, "undefined method `#{sym}' for #{inspect}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module TDParser
|
2
|
+
class IterationParser < CompositeParser # :nodoc:
|
3
|
+
attr_reader :min, :range
|
4
|
+
|
5
|
+
def initialize(parser, n, range)
|
6
|
+
@min = n
|
7
|
+
@range = range
|
8
|
+
super(parser)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(ts, buff)
|
12
|
+
r = @parsers[0]
|
13
|
+
n = @min
|
14
|
+
x = true
|
15
|
+
xs = []
|
16
|
+
while n.positive?
|
17
|
+
n -= 1
|
18
|
+
b = prepare(buff)
|
19
|
+
if (x = r.call(ts, b)).nil?
|
20
|
+
recover(b, ts)
|
21
|
+
break
|
22
|
+
else
|
23
|
+
buff.insert(0, *b)
|
24
|
+
xs.push(x)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if x.nil?
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
if range
|
31
|
+
range.each do
|
32
|
+
loop do
|
33
|
+
y = x
|
34
|
+
b = prepare(buff)
|
35
|
+
if (x = r.call(ts, b)).nil?
|
36
|
+
recover(b, ts)
|
37
|
+
x = y
|
38
|
+
break
|
39
|
+
else
|
40
|
+
buff.insert(0, *b)
|
41
|
+
xs.push(x)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
loop do
|
47
|
+
y = x
|
48
|
+
b = prepare(buff)
|
49
|
+
if (x = r.call(ts, b)).nil?
|
50
|
+
recover(b, ts)
|
51
|
+
x = y
|
52
|
+
break
|
53
|
+
else
|
54
|
+
buff.insert(0, *b)
|
55
|
+
xs.push(x)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
Sequence[xs]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"(#{@parsers[0]})*#{@range ? @range.to_s : @min.to_s}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def ==(other)
|
68
|
+
super(other) &&
|
69
|
+
(@min == other.min) &&
|
70
|
+
(@range == other.range)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module TDParser
|
2
|
+
class LabelParser < CompositeParser # :nodoc:
|
3
|
+
attr_reader :label
|
4
|
+
|
5
|
+
def initialize(parser, label)
|
6
|
+
@label = label
|
7
|
+
super(parser)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(tokens, buff)
|
11
|
+
x = @parsers[0].call(tokens, buff)
|
12
|
+
buff.map[@label] = x
|
13
|
+
x
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
super(other) &&
|
18
|
+
(@label == other.label)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"(#{@parsers[0]}/#{@label})"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module TDParser
|
2
|
+
class NegativeParser < CompositeParser # :nodoc:
|
3
|
+
def call(tokens, buff)
|
4
|
+
b = prepare(buff)
|
5
|
+
r = @parsers[0].call(tokens, b)
|
6
|
+
rev = b.reverse
|
7
|
+
recover(b, tokens)
|
8
|
+
return unless r.nil?
|
9
|
+
|
10
|
+
Sequence[Sequence[*rev]]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"~#{@parsers[0]}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TDParser
|
2
|
+
class NonTerminalParser < Parser # :nodoc:
|
3
|
+
attr_reader :context, :symbol, :options
|
4
|
+
|
5
|
+
def initialize(context, sym, *options)
|
6
|
+
@context = context
|
7
|
+
@symbol = sym
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(tokens, buff)
|
12
|
+
res = nil
|
13
|
+
case @symbol
|
14
|
+
when Symbol, String
|
15
|
+
res = @context.__send__(@symbol, *@options).call(tokens, buff)
|
16
|
+
when Parser
|
17
|
+
res = @symbol.call(tokens, buff)
|
18
|
+
end
|
19
|
+
res
|
20
|
+
end
|
21
|
+
|
22
|
+
def ==(other)
|
23
|
+
(self.class == other.class) &&
|
24
|
+
(@context == other.context) &&
|
25
|
+
(@symbol == other.symbol) &&
|
26
|
+
(@options == other.options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
@symbol.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ParallelParser < CompositeParser # :nodoc:
|
3
|
+
def call(tokens, buff)
|
4
|
+
b = prepare(buff)
|
5
|
+
if (x = @parsers[0].call(tokens, b)).nil?
|
6
|
+
recover(b, tokens)
|
7
|
+
Sequence[Sequence[nil, @parsers[1].call(tokens, buff)]]
|
8
|
+
else
|
9
|
+
buff.insert(0, *b)
|
10
|
+
Sequence[Sequence[x, nil]]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"(#{@parsers[0]} + #{@parsers[1]})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module TDParser
|
2
|
+
class Parser
|
3
|
+
include BufferUtils
|
4
|
+
include TDParser
|
5
|
+
|
6
|
+
def to_proc
|
7
|
+
proc { |*x| call(*x) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
'??'
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(*args); end
|
15
|
+
|
16
|
+
def optimize(_default = false)
|
17
|
+
dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(_other)
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def same?(r)
|
25
|
+
self == r
|
26
|
+
end
|
27
|
+
|
28
|
+
def -(other)
|
29
|
+
ConcatParser.new(self, other)
|
30
|
+
end
|
31
|
+
|
32
|
+
def +(other)
|
33
|
+
ParallelParser.new(self, other)
|
34
|
+
end
|
35
|
+
|
36
|
+
def |(other)
|
37
|
+
ChoiceParser.new(self, other).optimize(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
def *(other)
|
41
|
+
if other.is_a?(Range)
|
42
|
+
n = other.min
|
43
|
+
else
|
44
|
+
n = other
|
45
|
+
other = nil
|
46
|
+
end
|
47
|
+
IterationParser.new(self, n, other)
|
48
|
+
end
|
49
|
+
|
50
|
+
def >>(other)
|
51
|
+
ActionParser.new(self, other)
|
52
|
+
end
|
53
|
+
|
54
|
+
def /(other)
|
55
|
+
LabelParser.new(self, other)
|
56
|
+
end
|
57
|
+
|
58
|
+
def %(other)
|
59
|
+
StackParser.new(self, other)
|
60
|
+
end
|
61
|
+
|
62
|
+
def >(other)
|
63
|
+
Parser.new do |tokens, buff|
|
64
|
+
buff[other] = buff.dup
|
65
|
+
self[tokens, buff]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def ~@
|
70
|
+
NegativeParser.new(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse(tokens = nil, buff = nil, &blk)
|
74
|
+
buff ||= TokenBuffer.new
|
75
|
+
@tokens = if blk.nil?
|
76
|
+
if tokens.respond_to?(:shift) && tokens.respond_to?(:unshift)
|
77
|
+
tokens
|
78
|
+
elsif tokens.respond_to?(:each)
|
79
|
+
TokenGenerator.new(tokens)
|
80
|
+
else
|
81
|
+
tokens
|
82
|
+
end
|
83
|
+
else
|
84
|
+
TokenGenerator.new(&blk)
|
85
|
+
end
|
86
|
+
r = call(@tokens, buff)
|
87
|
+
if r.nil?
|
88
|
+
nil
|
89
|
+
else
|
90
|
+
r[0]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def peek
|
95
|
+
t = @tokens.shift
|
96
|
+
@tokens.unshift(t) unless t.nil?
|
97
|
+
t
|
98
|
+
end
|
99
|
+
|
100
|
+
def do(&block)
|
101
|
+
self >> block
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TDParser
|
2
|
+
class ReferenceParser < Parser # :nodoc:
|
3
|
+
private
|
4
|
+
|
5
|
+
def back_ref(xs, eqsym)
|
6
|
+
x = xs.shift
|
7
|
+
xs.inject(token(x, eqsym)) do |acc, x|
|
8
|
+
case x
|
9
|
+
when Sequence
|
10
|
+
acc - back_ref(x, eqsym)
|
11
|
+
else
|
12
|
+
acc - token(x, eqsym)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
alias __backref__ back_ref
|
18
|
+
|
19
|
+
def same?(_r)
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|