rley 0.8.14 → 0.8.15
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/.rubocop.yml +20 -2
- data/CHANGELOG.md +3 -0
- data/examples/general/calc_iter1/spec/calculator_spec.rb +9 -9
- data/examples/general/calc_iter2/spec/calculator_spec.rb +39 -39
- data/examples/general/recursive_right.rb +2 -2
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/gfg/grm_flow_graph.rb +0 -1
- data/lib/rley/parser/parse_entry_set.rb +0 -1
- data/lib/rley/parser/parse_walker_factory.rb +0 -1
- data/lib/rley/rgn/grammar_builder.rb +0 -2
- data/lib/rley/rgn/tokenizer.rb +1 -1
- data/lib/rley/syntax/base_grammar_builder.rb +0 -1
- data/lib/rley/syntax/grammar.rb +0 -1
- data/spec/rley/base/dotted_item_spec.rb +46 -46
- data/spec/rley/base/grm_items_builder_spec.rb +1 -1
- data/spec/rley/engine_spec.rb +50 -50
- data/spec/rley/formatter/asciitree_spec.rb +8 -8
- data/spec/rley/formatter/bracket_notation_spec.rb +10 -10
- data/spec/rley/formatter/debug_spec.rb +10 -10
- data/spec/rley/formatter/json_spec.rb +6 -7
- data/spec/rley/gfg/call_edge_spec.rb +6 -6
- data/spec/rley/gfg/edge_spec.rb +8 -7
- data/spec/rley/gfg/end_vertex_spec.rb +8 -7
- data/spec/rley/gfg/epsilon_edge_spec.rb +5 -4
- data/spec/rley/gfg/grm_flow_graph_spec.rb +33 -34
- data/spec/rley/gfg/item_vertex_spec.rb +34 -36
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +12 -12
- data/spec/rley/gfg/return_edge_spec.rb +6 -6
- data/spec/rley/gfg/scan_edge_spec.rb +7 -6
- data/spec/rley/gfg/shortcut_edge_spec.rb +15 -15
- data/spec/rley/gfg/start_vertex_spec.rb +8 -8
- data/spec/rley/gfg/vertex_spec.rb +18 -18
- data/spec/rley/lexical/literal_spec.rb +5 -5
- data/spec/rley/lexical/token_range_spec.rb +55 -55
- data/spec/rley/lexical/token_spec.rb +17 -16
- data/spec/rley/parse_forest_visitor_spec.rb +30 -32
- data/spec/rley/parse_rep/ambiguous_parse_spec.rb +2 -2
- data/spec/rley/parse_rep/ast_builder_spec.rb +30 -30
- data/spec/rley/parse_rep/cst_builder_spec.rb +85 -85
- data/spec/rley/parse_rep/groucho_spec.rb +23 -23
- data/spec/rley/parse_rep/parse_forest_builder_spec.rb +42 -42
- data/spec/rley/parse_rep/parse_forest_factory_spec.rb +10 -12
- data/spec/rley/parse_rep/parse_tree_factory_spec.rb +10 -15
- data/spec/rley/parse_tree_visitor_spec.rb +43 -46
- data/spec/rley/parser/dangling_else_spec.rb +12 -12
- data/spec/rley/parser/error_reason_spec.rb +37 -37
- data/spec/rley/parser/gfg_chart_spec.rb +27 -29
- data/spec/rley/parser/gfg_earley_parser_spec.rb +55 -56
- data/spec/rley/parser/gfg_parsing_spec.rb +106 -103
- data/spec/rley/parser/parse_entry_set_spec.rb +63 -61
- data/spec/rley/parser/parse_entry_spec.rb +73 -71
- data/spec/rley/parser/parse_walker_factory_spec.rb +14 -15
- data/spec/rley/ptree/non_terminal_node_spec.rb +16 -16
- data/spec/rley/ptree/parse_tree_node_spec.rb +11 -11
- data/spec/rley/ptree/parse_tree_spec.rb +6 -8
- data/spec/rley/ptree/terminal_node_spec.rb +6 -6
- data/spec/rley/rgn/grammar_builder_spec.rb +69 -67
- data/spec/rley/rgn/parser_spec.rb +63 -63
- data/spec/rley/rgn/repetition_node_spec.rb +15 -15
- data/spec/rley/rgn/sequence_node_spec.rb +10 -10
- data/spec/rley/rgn/symbol_node_spec.rb +5 -6
- data/spec/rley/rgn/tokenizer_spec.rb +68 -67
- data/spec/rley/sppf/alternative_node_spec.rb +16 -16
- data/spec/rley/sppf/non_terminal_node_spec.rb +20 -20
- data/spec/rley/sppf/token_node_spec.rb +13 -13
- data/spec/rley/syntax/base_grammar_builder_spec.rb +76 -86
- data/spec/rley/syntax/grammar_spec.rb +40 -78
- data/spec/rley/syntax/grm_symbol_spec.rb +7 -7
- data/spec/rley/syntax/match_closest_spec.rb +8 -8
- data/spec/rley/syntax/non_terminal_spec.rb +25 -25
- data/spec/rley/syntax/production_spec.rb +33 -33
- data/spec/rley/syntax/symbol_seq_spec.rb +27 -27
- data/spec/rley/syntax/terminal_spec.rb +12 -11
- data/spec/support/base_tokenizer_spec.rb +9 -8
- metadata +2 -2
@@ -18,6 +18,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
18
18
|
include GrammarHelper # Mix-in with token factory method
|
19
19
|
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
20
20
|
|
21
|
+
subject(:a_builder) { described_class.new(sample_tokens) }
|
22
|
+
|
21
23
|
let(:sample_grammar) do
|
22
24
|
# Grammar based on paper from Elisabeth Scott
|
23
25
|
# "SPPF=Style Parsing From Earley Recognizers" in
|
@@ -45,11 +47,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
45
47
|
parser.parse(sample_tokens)
|
46
48
|
end
|
47
49
|
|
48
|
-
subject { ParseForestBuilder.new(sample_tokens) }
|
49
|
-
|
50
50
|
# Emit a text representation of the current path.
|
51
51
|
def path_to_s
|
52
|
-
text_parts =
|
52
|
+
text_parts = a_builder.curr_path.map do |path_element|
|
53
53
|
path_element.to_string(0)
|
54
54
|
end
|
55
55
|
text_parts.join('/')
|
@@ -57,13 +57,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
57
57
|
|
58
58
|
def next_event(eventType, anEntryText)
|
59
59
|
event = @walker.next
|
60
|
-
|
60
|
+
a_builder.receive_event(*event)
|
61
61
|
expect(event[0]).to eq(eventType)
|
62
62
|
expect(event[1].to_s).to eq(anEntryText)
|
63
63
|
end
|
64
64
|
|
65
65
|
def expected_curr_parent(anExpectation)
|
66
|
-
expect(
|
66
|
+
expect(a_builder.curr_parent.to_string(0)).to eq(anExpectation)
|
67
67
|
end
|
68
68
|
|
69
69
|
def expected_curr_path(anExpectation)
|
@@ -71,41 +71,41 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def expected_first_child(anExpectation)
|
74
|
-
child =
|
74
|
+
child = a_builder.curr_parent.subnodes.first
|
75
75
|
expect(child.to_string(0)).to eq(anExpectation)
|
76
76
|
end
|
77
77
|
|
78
78
|
context 'Initialization:' do
|
79
|
-
it '
|
80
|
-
expect {
|
79
|
+
it 'is created with a sequence of tokens' do
|
80
|
+
expect { described_class.new(sample_tokens) }.not_to raise_error
|
81
81
|
end
|
82
82
|
|
83
|
-
it '
|
84
|
-
expect(
|
83
|
+
it 'knows the input tokens' do
|
84
|
+
expect(a_builder.tokens).to eq(sample_tokens)
|
85
85
|
end
|
86
86
|
|
87
|
-
it '
|
88
|
-
expect(
|
87
|
+
it 'has an empty path' do
|
88
|
+
expect(a_builder.curr_path).to be_empty
|
89
89
|
end
|
90
90
|
end # context
|
91
91
|
|
92
92
|
context 'Parse forest construction' do
|
93
|
-
before
|
93
|
+
before do
|
94
94
|
factory = Parser::ParseWalkerFactory.new
|
95
95
|
accept_entry = sample_result.accepting_entry
|
96
96
|
accept_index = sample_result.chart.last_index
|
97
97
|
@walker = factory.build_walker(accept_entry, accept_index, true)
|
98
98
|
end
|
99
99
|
|
100
|
-
it '
|
100
|
+
it 'initializes the root node' do
|
101
101
|
next_event(:visit, 'Phi. | 0')
|
102
|
-
forest =
|
102
|
+
forest = a_builder.result
|
103
103
|
|
104
104
|
expect(forest.root.to_string(0)).to eq('Phi[0, 4]')
|
105
105
|
expected_curr_path('Phi[0, 4]')
|
106
106
|
end
|
107
107
|
|
108
|
-
it '
|
108
|
+
it 'initializes the first child of the root node' do
|
109
109
|
next_event(:visit, 'Phi. | 0') # Event 1
|
110
110
|
next_event(:visit, 'Phi => S . | 0') # Event 2
|
111
111
|
next_event(:visit, 'S. | 0') # Event 3
|
@@ -113,41 +113,41 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
113
113
|
expected_curr_path('Phi[0, 4]/S[0, 4]')
|
114
114
|
end
|
115
115
|
|
116
|
-
it '
|
116
|
+
it 'builds alternative node when detecting backtrack point' do
|
117
117
|
3.times do
|
118
118
|
event = @walker.next
|
119
|
-
|
119
|
+
a_builder.receive_event(*event)
|
120
120
|
end
|
121
121
|
|
122
122
|
next_event(:visit, 'S => a T . | 0') # Event 4
|
123
123
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]')
|
124
|
-
expect(
|
124
|
+
expect(a_builder.curr_path[-2].refinement).to eq(:or)
|
125
125
|
end
|
126
126
|
|
127
|
-
it '
|
127
|
+
it 'builds token node when scan edge was detected' do
|
128
128
|
4.times do
|
129
129
|
event = @walker.next
|
130
|
-
|
130
|
+
a_builder.receive_event(*event)
|
131
131
|
end
|
132
132
|
|
133
133
|
next_event(:visit, 'T. | 1') # Event5
|
134
134
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]/T[1, 4]')
|
135
|
-
expect(
|
135
|
+
expect(a_builder.curr_parent.subnodes).to be_empty
|
136
136
|
|
137
137
|
next_event(:visit, 'T => b b b . | 1') # Event 6
|
138
|
-
expect(
|
138
|
+
expect(a_builder.curr_parent.to_string(0)).to eq('T[1, 4]')
|
139
139
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]/T[1, 4]')
|
140
|
-
expect(
|
140
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(1)
|
141
141
|
expected_first_child('b[3, 4]')
|
142
142
|
|
143
143
|
next_event(:visit, 'T => b b . b | 1') # Event 7
|
144
144
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]/T[1, 4]')
|
145
|
-
expect(
|
145
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(2)
|
146
146
|
expected_first_child('b[2, 3]')
|
147
147
|
|
148
148
|
next_event(:visit, 'T => b . b b | 1') # Event 8
|
149
149
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]/T[1, 4]')
|
150
|
-
expect(
|
150
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(3)
|
151
151
|
expected_first_child('b[1, 2]')
|
152
152
|
|
153
153
|
next_event(:visit, 'T => . b b b | 1') # Event 9
|
@@ -158,7 +158,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
158
158
|
|
159
159
|
next_event(:visit, 'S => a . T | 0') # Event 11
|
160
160
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]')
|
161
|
-
expect(
|
161
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(2)
|
162
162
|
expected_first_child('a[0, 1]')
|
163
163
|
|
164
164
|
next_event(:visit, 'S => . a T | 0') # Event 12
|
@@ -175,26 +175,26 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
175
175
|
expect(path_to_s).to be_empty
|
176
176
|
end
|
177
177
|
|
178
|
-
it '
|
178
|
+
it 'handles backtracking' do
|
179
179
|
15.times do
|
180
180
|
event = @walker.next
|
181
|
-
|
181
|
+
a_builder.receive_event(*event)
|
182
182
|
end
|
183
183
|
|
184
184
|
# Backtracking is occurring
|
185
185
|
next_event(:backtrack, 'S. | 0') # Event 16
|
186
186
|
expected_curr_path('Phi[0, 4]/S[0, 4]')
|
187
187
|
|
188
|
-
# Alternate node
|
188
|
+
# Alternate node is created
|
189
189
|
next_event(:visit, 'S => A T . | 0') # Event 17
|
190
190
|
expected_curr_path('Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]')
|
191
|
-
expect(
|
191
|
+
expect(a_builder.curr_path[-2].refinement).to eq(:or)
|
192
192
|
end
|
193
193
|
|
194
|
-
it '
|
194
|
+
it 'detects second time visit of an entry' do
|
195
195
|
17.times do
|
196
196
|
event = @walker.next
|
197
|
-
|
197
|
+
a_builder.receive_event(*event)
|
198
198
|
end
|
199
199
|
|
200
200
|
next_event(:revisit, 'T. | 1') # REVISIT Event 18
|
@@ -210,7 +210,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
210
210
|
|
211
211
|
next_event(:visit, 'A => a . | 0') # Event 21
|
212
212
|
expected_curr_path("#{path_prefix}Alt(A => a .)[0, 1]")
|
213
|
-
expect(
|
213
|
+
expect(a_builder.curr_path[-2].refinement).to eq(:or)
|
214
214
|
|
215
215
|
next_event(:visit, 'A => . a | 0') # Event 22
|
216
216
|
expected_curr_path(expected_path20)
|
@@ -231,10 +231,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
231
231
|
expected_curr_path('')
|
232
232
|
end
|
233
233
|
|
234
|
-
it '
|
234
|
+
it 'handles remaining # Events' do
|
235
235
|
27.times do
|
236
236
|
event = @walker.next
|
237
|
-
|
237
|
+
a_builder.receive_event(*event)
|
238
238
|
end
|
239
239
|
|
240
240
|
# Backtracking is occurring
|
@@ -280,6 +280,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
280
280
|
context 'Natural language processing' do
|
281
281
|
include GrammarL0Helper
|
282
282
|
|
283
|
+
subject(:a_builder) { described_class.new(sentence_tokens) }
|
284
|
+
|
283
285
|
let(:grammar_l0) do
|
284
286
|
builder = grammar_l0_builder
|
285
287
|
builder.grammar
|
@@ -295,16 +297,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
295
297
|
parser.parse(sentence_tokens)
|
296
298
|
end
|
297
299
|
|
298
|
-
before
|
300
|
+
before do
|
299
301
|
factory = Parser::ParseWalkerFactory.new
|
300
302
|
accept_entry = sentence_result.accepting_entry
|
301
303
|
accept_index = sentence_result.chart.last_index
|
302
304
|
@walker = factory.build_walker(accept_entry, accept_index)
|
303
305
|
end
|
304
306
|
|
305
|
-
|
306
|
-
|
307
|
-
it 'should handle walker events' do
|
307
|
+
it 'handles walker events' do
|
308
308
|
next_event(:visit, 'S. | 0') # Event 1
|
309
309
|
expected_curr_path('S[0, 5]')
|
310
310
|
|
@@ -329,7 +329,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
329
329
|
|
330
330
|
next_event(:visit, 'Nominal => Nominal Noun . | 3') # Event 8
|
331
331
|
expected_curr_path('S[0, 5]/VP[1, 5]/NP[2, 5]/Nominal[3, 5]')
|
332
|
-
expect(
|
332
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(1)
|
333
333
|
expected_first_child('Noun[4, 5]')
|
334
334
|
|
335
335
|
|
@@ -344,7 +344,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
344
344
|
next_event(:visit, 'Nominal => Noun . | 3') # Event11
|
345
345
|
path11 = 'S[0, 5]/VP[1, 5]/NP[2, 5]/Nominal[3, 5]/Nominal[3, 4]'
|
346
346
|
expected_curr_path(path11)
|
347
|
-
expect(
|
347
|
+
expect(a_builder.curr_parent.subnodes.size).to eq(1)
|
348
348
|
expected_first_child('Noun[3, 4]')
|
349
349
|
|
350
350
|
next_event(:visit, 'Nominal => . Noun | 3') # Event 12
|
@@ -17,6 +17,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
17
17
|
include GrammarHelper # Mix-in with token factory method
|
18
18
|
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
19
19
|
|
20
|
+
subject(:a_factory) { described_class.new(sample_result) }
|
21
|
+
|
20
22
|
let(:sample_grammar) do
|
21
23
|
# Grammar based on paper from Elisabeth Scott
|
22
24
|
# "SPPF-Style Parsing From Earley Recognizers" in
|
@@ -44,32 +46,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
44
46
|
parser.parse(sample_tokens)
|
45
47
|
end
|
46
48
|
|
47
|
-
subject do
|
48
|
-
ParseForestFactory.new(sample_result)
|
49
|
-
end
|
50
|
-
|
51
49
|
# Emit a text representation of the current path.
|
52
50
|
def path_to_s
|
53
|
-
text_parts =
|
51
|
+
text_parts = a_factory.curr_path.map do |path_element|
|
54
52
|
path_element.to_string(0)
|
55
53
|
end
|
56
54
|
text_parts.join('/')
|
57
55
|
end
|
58
56
|
|
59
57
|
context 'Initialization:' do
|
60
|
-
it '
|
61
|
-
expect {
|
58
|
+
it 'is created with a GFGParsing' do
|
59
|
+
expect { described_class.new(sample_result) }.not_to raise_error
|
62
60
|
end
|
63
61
|
|
64
|
-
it '
|
65
|
-
expect(
|
62
|
+
it 'knows the parse result' do
|
63
|
+
expect(a_factory.parsing).to eq(sample_result)
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
69
67
|
context 'Parse forest construction' do
|
70
|
-
it '
|
71
|
-
forest =
|
72
|
-
expect(forest).to
|
68
|
+
it 'builds a parse forest' do
|
69
|
+
forest = a_factory.create
|
70
|
+
expect(forest).to be_a(SPPF::ParseForest)
|
73
71
|
end
|
74
72
|
end # context
|
75
73
|
end # describe
|
@@ -18,28 +18,23 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
18
18
|
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
19
19
|
include GrammarABCHelper # Mix-in for a sample grammar
|
20
20
|
|
21
|
+
subject(:a_factory) { described_class.new(sample_result) }
|
22
|
+
|
21
23
|
let(:sample_grammar) do
|
22
24
|
builder = grammar_abc_builder
|
23
25
|
builder.grammar
|
24
26
|
end
|
25
|
-
|
26
27
|
let(:sample_tokens) do
|
27
28
|
build_token_sequence(%w[a b c], sample_grammar)
|
28
29
|
end
|
29
|
-
|
30
30
|
let(:sample_result) do
|
31
31
|
parser = Parser::GFGEarleyParser.new(sample_grammar)
|
32
32
|
parser.parse(sample_tokens)
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
subject do
|
37
|
-
ParseTreeFactory.new(sample_result)
|
38
|
-
end
|
39
|
-
|
40
35
|
# Emit a text representation of the current path.
|
41
36
|
def path_to_s
|
42
|
-
text_parts =
|
37
|
+
text_parts = a_factory.curr_path.map do |path_element|
|
43
38
|
path_element.to_string(0)
|
44
39
|
end
|
45
40
|
text_parts.join('/')
|
@@ -47,19 +42,19 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
47
42
|
|
48
43
|
|
49
44
|
context 'Initialization:' do
|
50
|
-
it '
|
51
|
-
expect {
|
45
|
+
it 'is created with a GFGParsing' do
|
46
|
+
expect { described_class.new(sample_result) }.not_to raise_error
|
52
47
|
end
|
53
48
|
|
54
|
-
it '
|
55
|
-
expect(
|
49
|
+
it 'knows the parse result' do
|
50
|
+
expect(a_factory.parsing).to eq(sample_result)
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
59
54
|
context 'Parse tree construction' do
|
60
|
-
it '
|
61
|
-
forest =
|
62
|
-
expect(forest).to
|
55
|
+
it 'builds a parse tree' do
|
56
|
+
forest = a_factory.create
|
57
|
+
expect(forest).to be_a(PTree::ParseTree)
|
63
58
|
end
|
64
59
|
end # context
|
65
60
|
end # describe
|
@@ -19,11 +19,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
19
19
|
builder.grammar
|
20
20
|
end
|
21
21
|
|
22
|
+
# Default instantiation rule
|
23
|
+
subject(:ptree_visitor) { described_class.new(grm_abc_ptree1) }
|
24
|
+
|
22
25
|
let(:a_) { grammar_abc.name2symbol['a'] }
|
23
26
|
let(:b_) { grammar_abc.name2symbol['b'] }
|
24
27
|
let(:c_) { grammar_abc.name2symbol['c'] }
|
25
28
|
|
26
|
-
|
27
29
|
# Helper method that mimicks the output of a tokenizer
|
28
30
|
# for the language specified by grammar_abc
|
29
31
|
let(:grm_abc_tokens1) do
|
@@ -51,22 +53,17 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
51
53
|
ptree
|
52
54
|
end
|
53
55
|
|
54
|
-
|
55
|
-
# Default instantiation rule
|
56
|
-
subject { ParseTreeVisitor.new(grm_abc_ptree1) }
|
57
|
-
|
58
|
-
|
59
56
|
context 'Standard creation & initialization:' do
|
60
|
-
it '
|
61
|
-
expect {
|
57
|
+
it 'is initialized with a parse tree argument' do
|
58
|
+
expect { described_class.new(grm_abc_ptree1) }.not_to raise_error
|
62
59
|
end
|
63
60
|
|
64
|
-
it '
|
65
|
-
expect(
|
61
|
+
it 'knows the parse tree to visit' do
|
62
|
+
expect(ptree_visitor.ptree).to eq(grm_abc_ptree1)
|
66
63
|
end
|
67
64
|
|
68
|
-
it "
|
69
|
-
expect(
|
65
|
+
it "doesn't have subscribers at start" do
|
66
|
+
expect(ptree_visitor.subscribers).to be_empty
|
70
67
|
end
|
71
68
|
end # context
|
72
69
|
|
@@ -75,32 +72,32 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
75
72
|
let(:listener1) { double('fake-subscriber1') }
|
76
73
|
let(:listener2) { double('fake-subscriber2') }
|
77
74
|
|
78
|
-
it '
|
79
|
-
|
80
|
-
expect(
|
81
|
-
expect(
|
75
|
+
it 'allows subscriptions' do
|
76
|
+
ptree_visitor.subscribe(listener1)
|
77
|
+
expect(ptree_visitor.subscribers.size).to eq(1)
|
78
|
+
expect(ptree_visitor.subscribers).to eq([listener1])
|
82
79
|
|
83
|
-
|
84
|
-
expect(
|
85
|
-
expect(
|
80
|
+
ptree_visitor.subscribe(listener2)
|
81
|
+
expect(ptree_visitor.subscribers.size).to eq(2)
|
82
|
+
expect(ptree_visitor.subscribers).to eq([listener1, listener2])
|
86
83
|
end
|
87
84
|
|
88
|
-
it '
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
expect(
|
93
|
-
expect(
|
94
|
-
|
95
|
-
expect(
|
85
|
+
it 'allows un-subcriptions' do
|
86
|
+
ptree_visitor.subscribe(listener1)
|
87
|
+
ptree_visitor.subscribe(listener2)
|
88
|
+
ptree_visitor.unsubscribe(listener2)
|
89
|
+
expect(ptree_visitor.subscribers.size).to eq(1)
|
90
|
+
expect(ptree_visitor.subscribers).to eq([listener1])
|
91
|
+
ptree_visitor.unsubscribe(listener1)
|
92
|
+
expect(ptree_visitor.subscribers).to be_empty
|
96
93
|
end
|
97
94
|
end # context
|
98
95
|
|
99
96
|
|
100
97
|
context 'Notifying visit events:' do
|
101
98
|
# Default instantiation rule
|
102
|
-
subject do
|
103
|
-
instance =
|
99
|
+
subject(:ptree_visitor) do
|
100
|
+
instance = described_class.new(grm_abc_ptree1)
|
104
101
|
instance.subscribe(listener1)
|
105
102
|
instance
|
106
103
|
end
|
@@ -119,19 +116,19 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
119
116
|
# Sample terminal node
|
120
117
|
let(:term_node) { nterm_node.subnodes[0] }
|
121
118
|
|
122
|
-
it '
|
119
|
+
it 'reacts to the start_visit_ptree message' do
|
123
120
|
# Notify subscribers when start the visit of the ptree
|
124
121
|
expect(listener1).to receive(:before_ptree).with(grm_abc_ptree1)
|
125
|
-
|
122
|
+
ptree_visitor.start_visit_ptree(grm_abc_ptree1)
|
126
123
|
end
|
127
124
|
|
128
|
-
it '
|
125
|
+
it 'reacts to the start_visit_nonterminal message' do
|
129
126
|
# Notify subscribers when start the visit of a non-terminal node
|
130
127
|
expect(listener1).to receive(:before_non_terminal).with(nterm_node)
|
131
|
-
|
128
|
+
ptree_visitor.visit_nonterminal(nterm_node)
|
132
129
|
end
|
133
130
|
|
134
|
-
it '
|
131
|
+
it 'reacts to the visit_children message' do
|
135
132
|
# Notify subscribers when start the visit of children nodes
|
136
133
|
children = nterm_node.subnodes
|
137
134
|
args = [nterm_node, children]
|
@@ -139,30 +136,30 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
139
136
|
expect(listener1).to receive(:before_terminal).with(children[0])
|
140
137
|
expect(listener1).to receive(:after_terminal).with(children[0])
|
141
138
|
expect(listener1).to receive(:after_subnodes).with(nterm_node, children)
|
142
|
-
|
139
|
+
ptree_visitor.send(:traverse_subnodes, nterm_node)
|
143
140
|
end
|
144
141
|
|
145
|
-
it '
|
142
|
+
it 'reacts to the end_visit_nonterminal message' do
|
146
143
|
# Notify subscribers when ending the visit of a non-terminal node
|
147
144
|
expect(listener1).to receive(:after_non_terminal).with(nterm_node)
|
148
|
-
|
145
|
+
ptree_visitor.end_visit_nonterminal(nterm_node)
|
149
146
|
end
|
150
147
|
|
151
|
-
it '
|
148
|
+
it 'reacts to the visit_terminal message' do
|
152
149
|
# Notify subscribers when start & ending the visit of a terminal node
|
153
150
|
expect(listener1).to receive(:before_terminal).with(term_node)
|
154
151
|
expect(listener1).to receive(:after_terminal).with(term_node)
|
155
|
-
|
152
|
+
ptree_visitor.visit_terminal(term_node)
|
156
153
|
end
|
157
154
|
|
158
|
-
it '
|
155
|
+
it 'reacts to the end_visit_ptree message' do
|
159
156
|
# Notify subscribers when ending the visit of the ptree
|
160
157
|
expect(listener1).to receive(:after_ptree).with(grm_abc_ptree1)
|
161
|
-
|
158
|
+
ptree_visitor.end_visit_ptree(grm_abc_ptree1)
|
162
159
|
end
|
163
160
|
|
164
161
|
# rubocop: disable Naming/VariableNumber
|
165
|
-
it '
|
162
|
+
it 'begins the visit when requested' do
|
166
163
|
# Reminder: parse tree structure is
|
167
164
|
# S[0,5]
|
168
165
|
# +- A[0,5]
|
@@ -212,10 +209,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
212
209
|
end
|
213
210
|
|
214
211
|
# Here we go...
|
215
|
-
|
212
|
+
ptree_visitor.start
|
216
213
|
end
|
217
214
|
|
218
|
-
it '
|
215
|
+
it 'also visits in pre-order' do
|
219
216
|
# Reminder: parse tree structure is
|
220
217
|
# S[0,5]
|
221
218
|
# +- A[0,5]
|
@@ -228,7 +225,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
228
225
|
# +- c[4,5]
|
229
226
|
root = grm_abc_ptree1.root
|
230
227
|
# Here we defeat encapsulation for the good cause
|
231
|
-
|
228
|
+
ptree_visitor.instance_variable_set(:@traversal, :pre_order)
|
232
229
|
|
233
230
|
children = root.subnodes
|
234
231
|
big_a_1 = children[0]
|
@@ -270,7 +267,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
270
267
|
end
|
271
268
|
|
272
269
|
# Here we go...
|
273
|
-
|
270
|
+
ptree_visitor.start
|
274
271
|
end
|
275
272
|
# rubocop: enable Naming/VariableNumber
|
276
273
|
end # context
|
@@ -61,7 +61,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
61
61
|
|
62
62
|
let(:input) { 'if false then if true then 1 else 2' }
|
63
63
|
|
64
|
-
context 'Ambiguous parse:
|
64
|
+
context 'Ambiguous parse:' do
|
65
65
|
# Factory method. Creates a grammar builder for a simple grammar.
|
66
66
|
def grammar_if_else_amb
|
67
67
|
builder = Rley::RGN::GrammarBuilder.new do
|
@@ -81,13 +81,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
81
81
|
builder.grammar
|
82
82
|
end
|
83
83
|
|
84
|
-
subject {
|
84
|
+
subject(:a_parser) { described_class.new(grammar_if_else_amb) }
|
85
85
|
|
86
|
-
it '
|
86
|
+
it 'parses a valid simple input' do
|
87
87
|
tokens = tokenizer(input)
|
88
|
-
parse_result =
|
89
|
-
expect(parse_result.success?).to
|
90
|
-
expect(parse_result.ambiguous?).to
|
88
|
+
parse_result = a_parser.parse(tokens)
|
89
|
+
expect(parse_result.success?).to be(true)
|
90
|
+
expect(parse_result.ambiguous?).to be(true)
|
91
91
|
######################
|
92
92
|
# Expectation chart[0]:
|
93
93
|
expected = [
|
@@ -280,7 +280,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
280
280
|
end
|
281
281
|
end # context
|
282
282
|
|
283
|
-
context 'Disambiguated parse:
|
283
|
+
context 'Disambiguated parse:' do
|
284
284
|
def match_else_with_if(grammar)
|
285
285
|
# Brittle code
|
286
286
|
prod = grammar.rules[2]
|
@@ -310,13 +310,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
310
310
|
builder.grammar
|
311
311
|
end
|
312
312
|
|
313
|
-
subject {
|
313
|
+
subject(:a_parser) { described_class.new(grammar_if_else) }
|
314
314
|
|
315
|
-
it '
|
315
|
+
it 'copes with dangling else problem' do
|
316
316
|
tokens = tokenizer(input)
|
317
|
-
parse_result =
|
318
|
-
expect(parse_result.success?).to
|
319
|
-
expect(parse_result.ambiguous?).to
|
317
|
+
parse_result = a_parser.parse(tokens)
|
318
|
+
expect(parse_result.success?).to be(true)
|
319
|
+
expect(parse_result.ambiguous?).to be(true)
|
320
320
|
######################
|
321
321
|
# Expectation chart[0]:
|
322
322
|
expected = [
|