rley 0.4.01 → 0.4.02
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 +4 -0
- data/LICENSE.txt +2 -2
- data/README.md +3 -3
- data/examples/NLP/mini_en_demo.rb +1 -1
- data/examples/data_formats/JSON/JSON_demo.rb +1 -0
- data/examples/data_formats/JSON/JSON_lexer.rb +4 -4
- data/examples/general/calc/calc_lexer.rb +2 -2
- data/lib/rley.rb +1 -1
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/formatter/debug.rb +2 -2
- data/lib/rley/formatter/json.rb +4 -4
- data/lib/rley/parse_tree_visitor.rb +9 -9
- data/lib/rley/parser/base_parser.rb +1 -1
- data/lib/rley/parser/gfg_parsing.rb +9 -0
- data/lib/rley/parser/parse_tree_builder.rb +176 -126
- data/lib/rley/parser/parse_tree_factory.rb +57 -0
- data/lib/rley/ptree/non_terminal_node.rb +10 -9
- data/lib/rley/ptree/parse_tree_node.rb +10 -5
- data/lib/rley/ptree/terminal_node.rb +14 -6
- data/lib/rley/sppf/sppf_node.rb +2 -2
- data/lib/rley/{parser → tokens}/token.rb +1 -4
- data/lib/rley/{ptree → tokens}/token_range.rb +1 -1
- data/spec/rley/formatter/debug_spec.rb +16 -16
- data/spec/rley/formatter/json_spec.rb +8 -8
- data/spec/rley/parse_forest_visitor_spec.rb +1 -1
- data/spec/rley/parse_tree_visitor_spec.rb +28 -28
- data/spec/rley/parser/error_reason_spec.rb +3 -3
- data/spec/rley/parser/gfg_chart_spec.rb +2 -2
- data/spec/rley/parser/gfg_earley_parser_spec.rb +2 -2
- data/spec/rley/parser/gfg_parsing_spec.rb +2 -2
- data/spec/rley/parser/groucho_spec.rb +1 -1
- data/spec/rley/parser/parse_tracer_spec.rb +2 -2
- data/spec/rley/parser/parse_tree_builder_spec.rb +213 -140
- data/spec/rley/parser/parse_tree_factory_spec.rb +85 -0
- data/spec/rley/parser/parse_walker_factory_spec.rb +11 -10
- data/spec/rley/ptree/non_terminal_node_spec.rb +23 -20
- data/spec/rley/ptree/terminal_node_spec.rb +7 -12
- data/spec/rley/sppf/alternative_node_spec.rb +2 -2
- data/spec/rley/sppf/non_terminal_node_spec.rb +2 -2
- data/spec/rley/support/ambiguous_grammar_helper.rb +2 -2
- data/spec/rley/support/expectation_helper.rb +1 -1
- data/spec/rley/support/grammar_ambig01_helper.rb +2 -2
- data/spec/rley/support/grammar_b_expr_helper.rb +2 -2
- data/spec/rley/support/grammar_helper.rb +3 -3
- data/spec/rley/support/grammar_l0_helper.rb +2 -2
- data/spec/rley/support/grammar_pb_helper.rb +2 -2
- data/spec/rley/{ptree → tokens}/token_range_spec.rb +2 -2
- data/spec/rley/{parser → tokens}/token_spec.rb +2 -2
- metadata +11 -17
- data/lib/rley/parser/chart.rb +0 -82
- data/lib/rley/parser/earley_parser.rb +0 -203
- data/lib/rley/parser/parsing.rb +0 -265
- data/spec/rley/parser/chart_spec.rb +0 -120
- data/spec/rley/parser/earley_parser_spec.rb +0 -710
- data/spec/rley/parser/parsing_spec.rb +0 -408
@@ -1,5 +1,5 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
require_relative '../../../lib/rley/
|
2
|
+
require_relative '../../../lib/rley/tokens/token'
|
3
3
|
|
4
4
|
# Load the class under test
|
5
5
|
require_relative '../../../lib/rley/parser/error_reason'
|
@@ -61,7 +61,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
61
61
|
describe UnexpectedToken do
|
62
62
|
let(:err_lexeme) { '-'}
|
63
63
|
let(:err_terminal) { Syntax::Terminal.new('MINUS') }
|
64
|
-
let(:err_token) { Token.new(err_lexeme, err_terminal) }
|
64
|
+
let(:err_token) { Tokens::Token.new(err_lexeme, err_terminal) }
|
65
65
|
let(:terminals) do
|
66
66
|
['PLUS', 'LPAREN'].map { |name| Syntax::Terminal.new(name) }
|
67
67
|
end
|
@@ -90,7 +90,7 @@ MSG_END
|
|
90
90
|
describe PrematureInputEnd do
|
91
91
|
let(:err_lexeme) { '+'}
|
92
92
|
let(:err_terminal) { Syntax::Terminal.new('PLUS') }
|
93
|
-
let(:err_token) { Token.new(err_lexeme, err_terminal) }
|
93
|
+
let(:err_token) { Tokens::Token.new(err_lexeme, err_terminal) }
|
94
94
|
let(:terminals) do
|
95
95
|
['INT', 'LPAREN'].map { |name| Syntax::Terminal.new(name) }
|
96
96
|
end
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
require_relative '../../../lib/rley/syntax/terminal'
|
5
|
-
require_relative '../../../lib/rley/
|
5
|
+
require_relative '../../../lib/rley/tokens/token'
|
6
6
|
require_relative '../../../lib/rley/gfg/start_vertex'
|
7
7
|
require_relative '../../../lib/rley/parser/parse_entry'
|
8
8
|
require_relative '../../../lib/rley/parser/parse_tracer'
|
@@ -39,7 +39,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
39
39
|
|
40
40
|
let(:token_seq) do
|
41
41
|
literals = %w(a a b c c)
|
42
|
-
literals.map { |lexeme| Token.new(lexeme, nil) }
|
42
|
+
literals.map { |lexeme| Tokens::Token.new(lexeme, nil) }
|
43
43
|
end
|
44
44
|
|
45
45
|
# Helper method. Create an array of dotted items
|
@@ -4,7 +4,7 @@ require_relative '../../../lib/rley/syntax/verbatim_symbol'
|
|
4
4
|
require_relative '../../../lib/rley/syntax/non_terminal'
|
5
5
|
require_relative '../../../lib/rley/syntax/production'
|
6
6
|
require_relative '../../../lib/rley/syntax/grammar_builder'
|
7
|
-
require_relative '../../../lib/rley/
|
7
|
+
require_relative '../../../lib/rley/tokens/token'
|
8
8
|
require_relative '../../../lib/rley/parser/dotted_item'
|
9
9
|
require_relative '../../../lib/rley/parser/gfg_parsing'
|
10
10
|
|
@@ -288,7 +288,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
288
288
|
builder.add_terminals(t_x)
|
289
289
|
builder.add_production('Ss' => %w(A A x))
|
290
290
|
builder.add_production('A' => [])
|
291
|
-
tokens = [ Token.new('x', t_x) ]
|
291
|
+
tokens = [ Tokens::Token.new('x', t_x) ]
|
292
292
|
|
293
293
|
instance = GFGEarleyParser.new(builder.grammar)
|
294
294
|
expect { instance.parse(tokens) }.not_to raise_error
|
@@ -6,7 +6,7 @@ require_relative '../../../lib/rley/syntax/verbatim_symbol'
|
|
6
6
|
require_relative '../../../lib/rley/syntax/production'
|
7
7
|
require_relative '../../../lib/rley/syntax/grammar_builder'
|
8
8
|
require_relative '../../../lib/rley/parser/dotted_item'
|
9
|
-
require_relative '../../../lib/rley/
|
9
|
+
require_relative '../../../lib/rley/tokens/token'
|
10
10
|
require_relative '../../../lib/rley/parser/parse_tracer'
|
11
11
|
require_relative '../../../lib/rley/gfg/grm_flow_graph'
|
12
12
|
require_relative '../../../lib/rley/parser/grm_items_builder'
|
@@ -298,7 +298,7 @@ SNIPPET
|
|
298
298
|
|
299
299
|
let(:token_seq1) do
|
300
300
|
%w(a a b c c).map do |letter|
|
301
|
-
Token.new(letter, sample_grammar1.name2symbol[letter])
|
301
|
+
Tokens::Token.new(letter, sample_grammar1.name2symbol[letter])
|
302
302
|
end
|
303
303
|
end
|
304
304
|
|
@@ -54,7 +54,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
54
54
|
raise StandardError, "Word '#{word}' not found in lexicon"
|
55
55
|
end
|
56
56
|
terminal = aGrammar.name2symbol[term_name]
|
57
|
-
Rley::
|
57
|
+
Rley::Tokens::Token.new(word, terminal)
|
58
58
|
end
|
59
59
|
|
60
60
|
return tokens
|
@@ -6,7 +6,7 @@ require_relative '../../../lib/rley/syntax/non_terminal'
|
|
6
6
|
require_relative '../../../lib/rley/syntax/production'
|
7
7
|
require_relative '../../../lib/rley/parser/dotted_item'
|
8
8
|
require_relative '../../../lib/rley/parser/parse_state'
|
9
|
-
require_relative '../../../lib/rley/
|
9
|
+
require_relative '../../../lib/rley/tokens/token'
|
10
10
|
|
11
11
|
# Load the class under test
|
12
12
|
require_relative '../../../lib/rley/parser/parse_tracer'
|
@@ -18,7 +18,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
18
18
|
|
19
19
|
let(:token_seq) do
|
20
20
|
literals = %w(I saw John with a dog)
|
21
|
-
literals.map { |lexeme| Token.new(lexeme, nil) }
|
21
|
+
literals.map { |lexeme| Tokens::Token.new(lexeme, nil) }
|
22
22
|
end
|
23
23
|
|
24
24
|
subject { ParseTracer.new(1, output, token_seq) }
|
@@ -1,178 +1,251 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
|
3
|
-
require_relative '../../../lib/rley/parser/
|
4
|
-
require_relative '../../../lib/rley/parser/
|
2
|
+
|
3
|
+
require_relative '../../../lib/rley/parser/gfg_earley_parser'
|
4
|
+
require_relative '../../../lib/rley/parser/parse_walker_factory'
|
5
|
+
|
6
|
+
require_relative '../support/expectation_helper'
|
7
|
+
require_relative '../support/grammar_b_expr_helper'
|
8
|
+
|
5
9
|
# Load the class under test
|
6
10
|
require_relative '../../../lib/rley/parser/parse_tree_builder'
|
7
|
-
require_relative '../support/grammar_abc_helper'
|
8
11
|
|
9
12
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
10
|
-
module Parser
|
13
|
+
module Parser
|
11
14
|
describe ParseTreeBuilder do
|
12
|
-
include
|
15
|
+
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
16
|
+
include GrammarBExprHelper # Mix-in for basic arithmetic language
|
13
17
|
|
14
|
-
let(:
|
15
|
-
|
16
|
-
|
18
|
+
let(:sample_grammar) do
|
19
|
+
builder = grammar_expr_builder()
|
20
|
+
builder.grammar
|
17
21
|
end
|
18
22
|
|
19
|
-
let(:
|
20
|
-
|
21
|
-
|
22
|
-
let(:small_b) { grammar_abc.name2symbol['b'] }
|
23
|
-
let(:small_c) { grammar_abc.name2symbol['c'] }
|
23
|
+
let(:sample_tokens) do
|
24
|
+
expr_tokenizer('2 + 3 * 4', sample_grammar)
|
25
|
+
end
|
24
26
|
|
25
|
-
let(:
|
27
|
+
let(:sample_result) do
|
28
|
+
parser = Parser::GFGEarleyParser.new(sample_grammar)
|
29
|
+
parser.parse(sample_tokens)
|
30
|
+
end
|
31
|
+
|
32
|
+
subject { ParseTreeBuilder.new(sample_tokens) }
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
# Emit a text representation of the current path.
|
35
|
+
def path_to_s()
|
36
|
+
text_parts = subject.curr_path.map do |path_element|
|
37
|
+
path_element.to_s
|
30
38
|
end
|
39
|
+
return text_parts.join('/')
|
31
40
|
end
|
32
41
|
|
33
|
-
|
34
|
-
|
35
|
-
|
42
|
+
def next_event(eventType, anEntryText)
|
43
|
+
event = @walker.next
|
44
|
+
subject.receive_event(*event)
|
45
|
+
expect(event[0]).to eq(eventType)
|
46
|
+
expect(event[1].to_s).to eq(anEntryText)
|
36
47
|
end
|
37
48
|
|
38
|
-
|
49
|
+
def expected_curr_parent(anExpectation)
|
50
|
+
expect(subject.curr_parent.to_string(0)).to eq(anExpectation)
|
51
|
+
end
|
52
|
+
|
53
|
+
def expected_curr_path(anExpectation)
|
54
|
+
expect(path_to_s).to eq(anExpectation)
|
55
|
+
end
|
56
|
+
|
57
|
+
def expected_first_child(anExpectation)
|
58
|
+
child = subject.curr_parent.subnodes.first
|
59
|
+
expect(child.to_string(0)).to eq(anExpectation)
|
60
|
+
end
|
39
61
|
|
40
62
|
context 'Initialization:' do
|
41
|
-
it 'should be created with a
|
42
|
-
expect { ParseTreeBuilder.new(
|
63
|
+
it 'should be created with a sequence of tokens' do
|
64
|
+
expect { ParseTreeBuilder.new(sample_tokens) }.not_to raise_error
|
43
65
|
end
|
44
66
|
|
45
|
-
it 'should
|
46
|
-
|
67
|
+
it 'should know the input tokens' do
|
68
|
+
expect(subject.tokens).to eq(sample_tokens)
|
47
69
|
end
|
48
70
|
|
49
|
-
it 'should have
|
50
|
-
|
71
|
+
it 'should have an empty path' do
|
72
|
+
expect(subject.curr_path).to be_empty
|
51
73
|
end
|
74
|
+
end # context
|
52
75
|
|
53
|
-
|
54
|
-
|
76
|
+
context 'Parse tree construction:' do
|
77
|
+
before(:each) do
|
78
|
+
factory = ParseWalkerFactory.new
|
79
|
+
accept_entry = sample_result.accepting_entry
|
80
|
+
accept_index = sample_result.chart.last_index
|
81
|
+
@walker = factory.build_walker(accept_entry, accept_index)
|
55
82
|
end
|
56
|
-
end # context
|
57
83
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
expect(subject.root.children.size).to eq(1)
|
65
|
-
child1 = subject.root.children[0]
|
66
|
-
expect(child1.symbol).to eq(capital_a)
|
67
|
-
expect(child1.range.low).to eq(0)
|
68
|
-
expect(child1.range.high).to eq(5)
|
69
|
-
expect(subject.current_node).to eq(child1)
|
70
|
-
|
71
|
-
# Add children to A
|
72
|
-
other_state = sample_parsing.chart.state_sets.last.states.first
|
73
|
-
subject.use_complete_state(other_state)
|
74
|
-
|
75
|
-
# Tree is:
|
76
|
-
# S[0,5]
|
77
|
-
# +- A[0,5]
|
78
|
-
# +- a[0, ?]
|
79
|
-
# +- A[?, ?]
|
80
|
-
# +- c[?, 5]
|
81
|
-
expect(child1.children.size).to eq(3) # a A c
|
82
|
-
%w(a A c).each_with_index do |letter, i|
|
83
|
-
grm_symbol = grammar_abc.name2symbol[letter]
|
84
|
-
expect(child1.children[i].symbol).to eq(grm_symbol)
|
85
|
-
end
|
86
|
-
expect(child1.children[0].range.low).to eq(0)
|
87
|
-
expect(child1.children[-1].range.high).to eq(5)
|
88
|
-
|
89
|
-
subject.move_down # ... to c
|
90
|
-
subject.range = { low: 4 }
|
91
|
-
expect(child1.children[-1].range.low).to eq(4)
|
92
|
-
expect(child1.children.last).to eq(subject.current_node)
|
93
|
-
subject.move_back # ... to A
|
94
|
-
expect(subject.current_node).to eq(child1.children[1])
|
95
|
-
grand_child_A = subject.current_node
|
96
|
-
|
97
|
-
other_state = sample_parsing.chart.state_sets[4].first
|
98
|
-
subject.use_complete_state(other_state)
|
99
|
-
expect(grand_child_A.children.size).to eq(3) # a A c
|
100
|
-
%w(a A c).each_with_index do |letter, i|
|
101
|
-
grm_symbol = grammar_abc.name2symbol[letter]
|
102
|
-
expect(grand_child_A.children[i].symbol).to eq(grm_symbol)
|
103
|
-
end
|
84
|
+
it 'should initialize the root node' do
|
85
|
+
next_event(:visit, 'P. | 0')
|
86
|
+
tree = subject.tree
|
87
|
+
|
88
|
+
expect(tree.root.to_string(0)).to eq('P[0, 5]')
|
89
|
+
expected_curr_path('P[0, 5]')
|
104
90
|
end
|
105
|
-
end # context
|
106
91
|
|
107
|
-
|
108
|
-
|
109
|
-
#
|
110
|
-
|
111
|
-
#
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
#
|
119
|
-
# +- A[0,?]
|
120
|
-
# +- a[0, ?]
|
121
|
-
# +- A[?, ?]
|
122
|
-
# +- c[?, ?]
|
123
|
-
subject.move_down # ...to grand-child c
|
124
|
-
expect(subject.current_node.symbol).to eq(small_c)
|
125
|
-
|
126
|
-
|
127
|
-
subject.move_back # ...to grand-child A
|
128
|
-
expect(subject.current_node.symbol).to eq(capital_a)
|
129
|
-
|
130
|
-
# Add more children
|
131
|
-
other_state = sample_parsing.chart.state_sets[4].states.first
|
132
|
-
subject.use_complete_state(other_state)
|
133
|
-
|
134
|
-
# Tree is:
|
135
|
-
tree_snapshot = <<-SNIPPET
|
136
|
-
S[0, 5]
|
137
|
-
+- A[0, 5]
|
138
|
-
+- a[0, ?]: '(nil)'
|
139
|
-
+- A[1, ?]
|
140
|
-
+- a[1, ?]: '(nil)'
|
141
|
-
+- A[?, ?]
|
142
|
-
+- c[?, ?]: '(nil)'
|
143
|
-
+- c[?, 5]: '(nil)'
|
144
|
-
SNIPPET
|
145
|
-
expect(subject.root.to_string(0)).to eq(tree_snapshot.chomp)
|
146
|
-
|
147
|
-
subject.move_down # ...to grand-grand-child c
|
148
|
-
expect(subject.current_node.to_string(0)).to eq("c[?, ?]: '(nil)'")
|
149
|
-
|
150
|
-
subject.move_back # ...to grand-grand-child A
|
151
|
-
expect(subject.current_node.to_string(0)).to eq('A[?, ?]')
|
152
|
-
|
153
|
-
subject.move_back # ...to grand-grand-child a
|
154
|
-
expect(subject.current_node.to_string(0)).to eq("a[1, ?]: '(nil)'")
|
155
|
-
|
156
|
-
subject.move_back # ...to grand-child a
|
157
|
-
expect(subject.current_node.to_string(0)).to eq("a[0, ?]: '(nil)'")
|
158
|
-
|
159
|
-
subject.move_back # ...to S
|
160
|
-
expect(subject.current_node.symbol).to eq(capital_s)
|
92
|
+
it 'should initialize the first child of the root node' do
|
93
|
+
next_event(:visit, 'P. | 0') # Event 1
|
94
|
+
next_event(:visit, 'P => S . | 0') # Event 2
|
95
|
+
next_event(:visit, 'S. | 0') # Event 3
|
96
|
+
next_event(:visit, 'S => S + M . | 0') # Event 4
|
97
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
98
|
+
next_event(:visit, 'M. | 2') # Event 5
|
99
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]')
|
100
|
+
next_event(:visit, 'M => M * T . | 2') # Event 6
|
101
|
+
next_event(:visit, 'T. | 4') # Event 7
|
102
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/T[4, 5]')
|
103
|
+
next_event(:visit, 'T => integer . | 4') # Event 8
|
161
104
|
end
|
162
105
|
|
163
|
-
it 'should
|
106
|
+
it 'should build token node when scan edge was detected' do
|
107
|
+
8.times do
|
108
|
+
event = @walker.next
|
109
|
+
subject.receive_event(*event)
|
110
|
+
end
|
111
|
+
|
112
|
+
next_event(:visit, 'T => . integer | 4') # Event 9
|
113
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/T[4, 5]')
|
114
|
+
expected_first_child("integer[4, 5]: '4'")
|
115
|
+
expect(subject.curr_parent.subnodes.size).to eq(1)
|
164
116
|
end
|
165
|
-
end # context
|
166
117
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
118
|
+
it 'should handle the remaining events' do
|
119
|
+
9.times do
|
120
|
+
event = @walker.next
|
121
|
+
subject.receive_event(*event)
|
122
|
+
end
|
123
|
+
|
124
|
+
next_event(:visit, '.T | 4') # Event 10
|
125
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]')
|
126
|
+
|
127
|
+
next_event(:visit, 'M => M * . T | 2') # Event 11
|
128
|
+
|
129
|
+
next_event(:visit, 'M => M . * T | 2') # Event 12
|
130
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]')
|
131
|
+
expect(subject.curr_parent.subnodes.size).to eq(2)
|
132
|
+
expected_first_child("*[3, 4]: '*'")
|
133
|
+
|
134
|
+
next_event(:visit, 'M. | 2') # Event 13
|
135
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]')
|
136
|
+
|
137
|
+
next_event(:visit, 'M => T . | 2') # Event 14
|
138
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]')
|
139
|
+
|
140
|
+
next_event(:visit, 'T. | 2') # Event 15
|
141
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]/T[2, 3]')
|
142
|
+
|
143
|
+
next_event(:visit, 'T => integer . | 2') # Event 16
|
144
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]/T[2, 3]')
|
145
|
+
expect(subject.curr_parent.subnodes.size).to eq(1)
|
146
|
+
expected_first_child("integer[2, 3]: '3'")
|
147
|
+
|
148
|
+
next_event(:visit, 'T => . integer | 2') # Event 17
|
149
|
+
|
150
|
+
next_event(:visit, '.T | 2') # Event 18
|
151
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]')
|
152
|
+
|
153
|
+
next_event(:visit, 'M => . T | 2') # Event 19
|
154
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]/M[2, 3]')
|
155
|
+
|
156
|
+
next_event(:visit, '.M | 2') # Event 20
|
157
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]')
|
158
|
+
|
159
|
+
next_event(:visit, 'M => . M * T | 2') # Event 21
|
160
|
+
expected_curr_path('P[0, 5]/S[0, 5]/M[2, 5]')
|
161
|
+
|
162
|
+
next_event(:revisit, '.M | 2') # Revisit Event 22
|
163
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
164
|
+
|
165
|
+
next_event(:visit, 'S => S + . M | 0') # Event 23
|
166
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
167
|
+
|
168
|
+
next_event(:visit, 'S => S . + M | 0') # Event 24
|
169
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
170
|
+
expect(subject.curr_parent.subnodes.size).to eq(2)
|
171
|
+
expected_first_child("+[1, 2]: '+'")
|
172
|
+
|
173
|
+
next_event(:visit, 'S. | 0') # Event 25
|
174
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]')
|
175
|
+
|
176
|
+
next_event(:visit, 'S => M . | 0') # Event 26
|
177
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]')
|
178
|
+
|
179
|
+
next_event(:visit, 'M. | 0') # Event 27
|
180
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]')
|
181
|
+
|
182
|
+
next_event(:visit, 'M => T . | 0') # Event 28
|
183
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]')
|
184
|
+
|
185
|
+
next_event(:visit, 'T. | 0') # Event 29
|
186
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]/T[0, 1]')
|
187
|
+
|
188
|
+
next_event(:visit, 'T => integer . | 0') # Event 30
|
189
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]/T[0, 1]')
|
190
|
+
|
191
|
+
next_event(:visit, 'T => . integer | 0') # Event 31
|
192
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]/T[0, 1]')
|
193
|
+
expect(subject.curr_parent.subnodes.size).to eq(1)
|
194
|
+
expected_first_child("integer[0, 1]: '2'")
|
195
|
+
|
196
|
+
next_event(:visit, '.T | 0') # Event 32
|
197
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]')
|
198
|
+
|
199
|
+
next_event(:visit, 'M => . T | 0') # Event 33
|
200
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]/M[0, 1]')
|
201
|
+
|
202
|
+
next_event(:visit, '.M | 0') # Event 34
|
203
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]')
|
204
|
+
|
205
|
+
next_event(:visit, 'S => . M | 0') # Event 35
|
206
|
+
expected_curr_path('P[0, 5]/S[0, 5]/S[0, 1]')
|
207
|
+
|
208
|
+
next_event(:visit, '.S | 0') # Event 36
|
209
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
210
|
+
|
211
|
+
next_event(:visit, 'S => . S + M | 0') # Event 37
|
212
|
+
expected_curr_path('P[0, 5]/S[0, 5]')
|
213
|
+
|
214
|
+
next_event(:revisit, '.S | 0') # Event 38
|
215
|
+
expected_curr_path('P[0, 5]')
|
216
|
+
|
217
|
+
next_event(:visit, 'P => . S | 0') # Event 39
|
218
|
+
expected_curr_path('P[0, 5]')
|
219
|
+
|
220
|
+
next_event(:visit, '.P | 0') # Event 39
|
221
|
+
expect(path_to_s).to be_empty
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should build parse trees' do
|
225
|
+
loop do
|
226
|
+
event = @walker.next
|
227
|
+
subject.receive_event(*event)
|
228
|
+
break if path_to_s.empty?
|
229
|
+
end
|
230
|
+
|
231
|
+
# Lightweight sanity check
|
232
|
+
expect(subject.tree).not_to be_nil
|
233
|
+
expect(subject.tree).to be_kind_of(PTree::ParseTree)
|
234
|
+
expect(subject.tree.root.to_s).to eq('P[0, 5]')
|
235
|
+
expect(subject.tree.root.subnodes.size).to eq(1)
|
236
|
+
child_node = subject.tree.root.subnodes[0]
|
237
|
+
expect(child_node.to_s).to eq('S[0, 5]')
|
238
|
+
expect(child_node.subnodes.size).to eq(3)
|
239
|
+
first_grandchild = child_node.subnodes[0]
|
240
|
+
expect(first_grandchild.to_s).to eq('S[0, 1]')
|
241
|
+
second_grandchild = child_node.subnodes[1]
|
242
|
+
expect(second_grandchild.to_s).to eq("+[1, 2]: '+'")
|
243
|
+
third_grandchild = child_node.subnodes[2]
|
244
|
+
expect(third_grandchild.to_s).to eq('M[2, 5]')
|
172
245
|
end
|
173
246
|
end # context
|
247
|
+
|
174
248
|
end # describe
|
175
249
|
end # module
|
176
250
|
end # module
|
177
|
-
|
178
251
|
# End of file
|