rley 0.5.04 → 0.5.05
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 +10 -0
- data/examples/general/calc_iter1/calc_demo.rb +1 -1
- data/examples/general/calc_iter2/calc_ast_builder.rb +200 -0
- data/examples/general/calc_iter2/calc_ast_nodes.rb +156 -0
- data/examples/general/calc_iter2/calc_demo.rb +66 -0
- data/examples/general/calc_iter2/calc_grammar.rb +31 -0
- data/examples/general/calc_iter2/calc_lexer.rb +78 -0
- data/examples/general/calc_iter2/calc_parser.rb +24 -0
- data/examples/general/calc_iter2/spec/calculator_spec.rb +113 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/gfg/grm_flow_graph.rb +41 -12
- data/lib/rley/gfg/vertex.rb +11 -4
- data/lib/rley/parser/gfg_parsing.rb +29 -1
- data/lib/rley/parser/parse_entry_set.rb +2 -1
- data/lib/rley/parser/parse_forest_factory.rb +7 -0
- data/lib/rley/parser/parse_rep_creator.rb +8 -2
- data/lib/rley/parser/parse_tree_builder.rb +5 -3
- data/lib/rley/parser/parse_tree_factory.rb +1 -1
- data/lib/rley/parser/parse_walker_factory.rb +15 -10
- data/spec/rley/parser/ambiguous_parse_spec.rb +1 -1
- data/spec/rley/parser/gfg_earley_parser_spec.rb +2 -2
- data/spec/rley/parser/gfg_parsing_spec.rb +1 -1
- data/spec/rley/parser/groucho_spec.rb +1 -1
- data/spec/rley/parser/parse_forest_builder_spec.rb +1 -1
- data/spec/rley/parser/parse_walker_factory_spec.rb +148 -11
- metadata +9 -2
@@ -13,6 +13,13 @@ module Rley # This module is used as a namespace
|
|
13
13
|
def builder(aParseResult, _builder = nil)
|
14
14
|
ParseForestBuilder.new(aParseResult.tokens)
|
15
15
|
end
|
16
|
+
|
17
|
+
# When a end vertex is re-visited then jump
|
18
|
+
# its corresponding start vertex. This behaviour
|
19
|
+
# makes sense for sharing nodes.
|
20
|
+
def jump_to_start()
|
21
|
+
true
|
22
|
+
end
|
16
23
|
end # class
|
17
24
|
end # module
|
18
25
|
end # module
|
@@ -42,8 +42,14 @@ module Rley # This module is used as a namespace
|
|
42
42
|
walker_factory = ParseWalkerFactory.new
|
43
43
|
accept_entry = aParseResult.accepting_entry
|
44
44
|
accept_index = aParseResult.chart.last_index
|
45
|
-
walker_factory.build_walker(accept_entry, accept_index)
|
46
|
-
end
|
45
|
+
walker_factory.build_walker(accept_entry, accept_index, jump_to_start)
|
46
|
+
end
|
47
|
+
|
48
|
+
# By default, when a end vertex is re-visited don't jump
|
49
|
+
# its corresponding start vertex.
|
50
|
+
def jump_to_start()
|
51
|
+
false
|
52
|
+
end
|
47
53
|
|
48
54
|
end # class
|
49
55
|
end # module
|
@@ -84,13 +84,15 @@ module Rley # This module is used as a namespace
|
|
84
84
|
# @param anIndex [anIndex] The token index at end of anEntry
|
85
85
|
def process_end_entry(anEvent, anEntry, anIndex)
|
86
86
|
case anEvent
|
87
|
-
when :visit
|
87
|
+
when :visit, :revisit
|
88
88
|
range = { low: anEntry.origin, high: anIndex }
|
89
89
|
non_terminal = entry2nonterm(anEntry)
|
90
90
|
# Create raw node and push onto stack
|
91
91
|
push_raw_node(range, non_terminal)
|
92
|
+
#when :revisit
|
93
|
+
# # TODO: design specification
|
92
94
|
else
|
93
|
-
raise NotImplementedError
|
95
|
+
raise NotImplementedError, "Cannot handle event #{anEvent}"
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
@@ -143,7 +145,7 @@ module Rley # This module is used as a namespace
|
|
143
145
|
end
|
144
146
|
|
145
147
|
# @param anEntry [ParseEntry] Entry matching (pattern: N => . alpha)
|
146
|
-
# @param
|
148
|
+
# @param _index [Integer] The token index at end of anEntry
|
147
149
|
def process_entry_entry(anEntry, _index)
|
148
150
|
dotted_item = anEntry.vertex.dotted_item
|
149
151
|
rule = dotted_item.production
|
@@ -18,7 +18,8 @@ module Rley # This module is used as a namespace
|
|
18
18
|
:nterm2start, # Nested hashes. Pairs of first level are of the form:
|
19
19
|
# non-terminal symbol => { index(=origin) => start entry }
|
20
20
|
:return_stack, # @return [Array<ParseEntry>] A stack of parse entries
|
21
|
-
:backtrack_points
|
21
|
+
:backtrack_points,
|
22
|
+
:lazy_walk # If true and revisit end vertex then jump to start vertex
|
22
23
|
)
|
23
24
|
|
24
25
|
|
@@ -26,7 +27,7 @@ module Rley # This module is used as a namespace
|
|
26
27
|
:entry_set_index, # Sigma set index of current parse entry
|
27
28
|
:return_stack, # A stack of parse entries
|
28
29
|
:visitee, # The parse entry being visited
|
29
|
-
:antecedent_index
|
30
|
+
:antecedent_index,
|
30
31
|
)
|
31
32
|
|
32
33
|
# A factory that creates an Enumerator object
|
@@ -47,11 +48,12 @@ module Rley # This module is used as a namespace
|
|
47
48
|
# @param acceptingEntry [ParseEntry] the final ParseEntry of a
|
48
49
|
# successful parse.
|
49
50
|
# @param maxIndex [Integer] the index of the last input token.
|
51
|
+
# @param lazyWalk [Boolean] if true then take some shortcut in re-visits.
|
50
52
|
# @return [Enumerator] yields visit events when walking over the
|
51
53
|
# parse result
|
52
|
-
def build_walker(acceptingEntry, maxIndex)
|
54
|
+
def build_walker(acceptingEntry, maxIndex, lazyWalk = false)
|
53
55
|
# Local context for the enumerator
|
54
|
-
ctx = init_context(acceptingEntry, maxIndex)
|
56
|
+
ctx = init_context(acceptingEntry, maxIndex, lazyWalk)
|
55
57
|
|
56
58
|
walker = Enumerator.new do |receiver| # 'receiver' is a Yielder
|
57
59
|
# At this point: current entry == accepting entry
|
@@ -79,7 +81,7 @@ module Rley # This module is used as a namespace
|
|
79
81
|
private
|
80
82
|
|
81
83
|
# Context factory method
|
82
|
-
def init_context(acceptingEntry, maxIndex)
|
84
|
+
def init_context(acceptingEntry, maxIndex, lazyWalk)
|
83
85
|
context = ParseWalkerContext.new
|
84
86
|
context.entry_set_index = maxIndex
|
85
87
|
context.curr_entry = acceptingEntry
|
@@ -87,6 +89,7 @@ module Rley # This module is used as a namespace
|
|
87
89
|
context.nterm2start = init_nterm2start
|
88
90
|
context.return_stack = []
|
89
91
|
context.backtrack_points = []
|
92
|
+
context.lazy_walk = lazyWalk
|
90
93
|
|
91
94
|
return context
|
92
95
|
end
|
@@ -116,11 +119,13 @@ module Rley # This module is used as a namespace
|
|
116
119
|
if aContext.visitees.include?(anEntry) # Already visited?...
|
117
120
|
case anEntry.vertex
|
118
121
|
when GFG::EndVertex
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
if aContext.lazy_walk
|
123
|
+
# Jump to related start entry...
|
124
|
+
pairs = aContext.nterm2start[anEntry.vertex.non_terminal]
|
125
|
+
new_entry = pairs[anEntry.origin]
|
126
|
+
aContext.curr_entry = new_entry
|
127
|
+
aContext.entry_set_index = new_entry.origin
|
128
|
+
end
|
124
129
|
event = [:revisit, anEntry, index]
|
125
130
|
|
126
131
|
when GFG::StartVertex
|
@@ -48,7 +48,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
48
48
|
factory = ParseWalkerFactory.new
|
49
49
|
accept_entry = sentence_result.accepting_entry
|
50
50
|
accept_index = sentence_result.chart.last_index
|
51
|
-
@walker = factory.build_walker(accept_entry, accept_index)
|
51
|
+
@walker = factory.build_walker(accept_entry, accept_index, true)
|
52
52
|
end
|
53
53
|
|
54
54
|
context 'Ambiguous expression' do
|
@@ -299,8 +299,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
299
299
|
expected = [
|
300
300
|
'.Ss | 0', # Initialization
|
301
301
|
"Ss => . A A 'x' | 0", # start rule
|
302
|
-
'.A | 0', # call rule
|
303
|
-
'A => . | 0', # start rule
|
302
|
+
'.A | 0', # call rule
|
303
|
+
'A => . | 0', # start rule
|
304
304
|
'A. | 0', # exit rule
|
305
305
|
"Ss => A . A 'x' | 0", # end rule
|
306
306
|
"Ss => A A . 'x' | 0" # end rule
|
@@ -60,7 +60,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
60
60
|
end
|
61
61
|
|
62
62
|
context 'Initialization:' do
|
63
|
-
it 'should be created with a GFG, tokens
|
63
|
+
it 'should be created with a GFG, tokens' do
|
64
64
|
expect { GFGParsing.new(sample_gfg, grm1_tokens) }
|
65
65
|
.not_to raise_error
|
66
66
|
end
|
@@ -107,7 +107,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
107
107
|
factory = ParseWalkerFactory.new
|
108
108
|
accept_entry = sentence_result.accepting_entry
|
109
109
|
accept_index = sentence_result.chart.last_index
|
110
|
-
@walker = factory.build_walker(accept_entry, accept_index)
|
110
|
+
@walker = factory.build_walker(accept_entry, accept_index, true)
|
111
111
|
end
|
112
112
|
|
113
113
|
context 'Parse ambiguous sentence' do
|
@@ -92,7 +92,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
92
92
|
factory = ParseWalkerFactory.new
|
93
93
|
accept_entry = sample_result.accepting_entry
|
94
94
|
accept_index = sample_result.chart.last_index
|
95
|
-
@walker = factory.build_walker(accept_entry, accept_index)
|
95
|
+
@walker = factory.build_walker(accept_entry, accept_index, true)
|
96
96
|
end
|
97
97
|
|
98
98
|
it 'should initialize the root node' do
|
@@ -84,14 +84,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'should return the accepting parse entry in the first place' do
|
87
|
-
walker = subject.build_walker(accept_entry, accept_index)
|
87
|
+
walker = subject.build_walker(accept_entry, accept_index, false)
|
88
88
|
first_event = walker.next
|
89
89
|
expectations = [:visit, sample_result.accepting_entry, 4]
|
90
90
|
event_expectations(first_event, expectations)
|
91
91
|
end
|
92
92
|
|
93
|
-
it '
|
94
|
-
walker = subject.build_walker(accept_entry, accept_index)
|
93
|
+
it 'could traverse the parse graph backwards' do
|
94
|
+
walker = subject.build_walker(accept_entry, accept_index, false)
|
95
95
|
event1 = walker.next
|
96
96
|
expectations = [:visit, 'Phi. | 0', 4]
|
97
97
|
event_expectations(event1, expectations)
|
@@ -163,9 +163,146 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
163
163
|
event_expectations(event17, expectations)
|
164
164
|
|
165
165
|
event18 = walker.next
|
166
|
-
expectations = [:revisit, 'T. | 1', 4]
|
166
|
+
expectations = [:revisit, 'T. | 1', 4] # Re-visiting end vertex
|
167
167
|
event_expectations(event18, expectations)
|
168
168
|
|
169
|
+
# No lazy walk: don't jump directly after corresponding start vertex
|
170
|
+
event19 = walker.next
|
171
|
+
expectations = [:revisit, 'T => b b b . | 1', 4]
|
172
|
+
event_expectations(event19, expectations)
|
173
|
+
|
174
|
+
event20 = walker.next
|
175
|
+
expectations = [:revisit, 'T => b b . b | 1', 3]
|
176
|
+
event_expectations(event20, expectations)
|
177
|
+
|
178
|
+
event21 = walker.next
|
179
|
+
expectations = [:revisit, 'T => b . b b | 1', 2]
|
180
|
+
event_expectations(event21, expectations)
|
181
|
+
|
182
|
+
event22 = walker.next
|
183
|
+
expectations = [:revisit, 'T => . b b b | 1', 1]
|
184
|
+
event_expectations(event22, expectations)
|
185
|
+
|
186
|
+
event23 = walker.next
|
187
|
+
expectations = [:revisit, '.T | 1', 1]
|
188
|
+
event_expectations(event23, expectations)
|
189
|
+
|
190
|
+
# Multiple visit occurred: jump to antecedent of start entry
|
191
|
+
event24 = walker.next
|
192
|
+
expectations = [:visit, 'S => A . T | 0', 1]
|
193
|
+
event_expectations(event24, expectations)
|
194
|
+
|
195
|
+
event25 = walker.next
|
196
|
+
expectations = [:visit, 'A. | 0', 1]
|
197
|
+
event_expectations(event25, expectations)
|
198
|
+
|
199
|
+
# Backtrack created: first alternative selected
|
200
|
+
event26 = walker.next
|
201
|
+
expectations = [:visit, 'A => a . | 0', 1]
|
202
|
+
event_expectations(event26, expectations)
|
203
|
+
|
204
|
+
event27 = walker.next
|
205
|
+
expectations = [:visit, 'A => . a | 0', 0]
|
206
|
+
event_expectations(event27, expectations)
|
207
|
+
|
208
|
+
event28 = walker.next
|
209
|
+
expectations = [:visit, '.A | 0', 0]
|
210
|
+
event_expectations(event28, expectations)
|
211
|
+
|
212
|
+
event29 = walker.next
|
213
|
+
expectations = [:visit, 'S => . A T | 0', 0]
|
214
|
+
event_expectations(event29, expectations)
|
215
|
+
|
216
|
+
event30 = walker.next
|
217
|
+
expectations = [:revisit, '.S | 0', 0]
|
218
|
+
event_expectations(event30, expectations)
|
219
|
+
|
220
|
+
event31 = walker.next
|
221
|
+
expectations = [:revisit, 'Phi => . S | 0', 0]
|
222
|
+
event_expectations(event31, expectations)
|
223
|
+
|
224
|
+
event32 = walker.next
|
225
|
+
expectations = [:revisit, '.Phi | 0', 0]
|
226
|
+
event_expectations(event32, expectations)
|
227
|
+
|
228
|
+
# Backtracking is occurring
|
229
|
+
event33 = walker.next
|
230
|
+
expectations = [:backtrack, 'A. | 0', 1]
|
231
|
+
event_expectations(event33, expectations)
|
232
|
+
|
233
|
+
event34 = walker.next
|
234
|
+
expectations = [:visit, 'A => B A . | 0', 1]
|
235
|
+
event_expectations(event34, expectations)
|
236
|
+
|
237
|
+
event35 = walker.next
|
238
|
+
expectations = [:revisit, 'A. | 0', 1] # Revisiting end vertex
|
239
|
+
event_expectations(event35, expectations)
|
240
|
+
|
241
|
+
# No lazy walk: don't jump directly after corresponding start vertex
|
242
|
+
event36 = walker.next
|
243
|
+
expectations = [:revisit, 'A => a . | 0', 1]
|
244
|
+
event_expectations(event36, expectations)
|
245
|
+
|
246
|
+
event37 = walker.next
|
247
|
+
expectations = [:revisit, 'A => . a | 0', 0]
|
248
|
+
event_expectations(event37, expectations)
|
249
|
+
|
250
|
+
event38 = walker.next
|
251
|
+
expectations = [:revisit, '.A | 0', 0]
|
252
|
+
event_expectations(event38, expectations)
|
253
|
+
|
254
|
+
event39 = walker.next
|
255
|
+
expectations = [:visit, 'A => B . A | 0', 0]
|
256
|
+
event_expectations(event39, expectations)
|
257
|
+
|
258
|
+
event40 = walker.next
|
259
|
+
expectations = [:visit, 'B. | 0', 0]
|
260
|
+
event_expectations(event40, expectations)
|
261
|
+
|
262
|
+
event41 = walker.next
|
263
|
+
expectations = [:visit, 'B => . | 0', 0]
|
264
|
+
event_expectations(event41, expectations)
|
265
|
+
|
266
|
+
event42 = walker.next
|
267
|
+
expectations = [:visit, '.B | 0', 0]
|
268
|
+
event_expectations(event42, expectations)
|
269
|
+
|
270
|
+
event43 = walker.next
|
271
|
+
expectations = [:visit, 'A => . B A | 0', 0]
|
272
|
+
event_expectations(event43, expectations)
|
273
|
+
|
274
|
+
event44 = walker.next
|
275
|
+
expectations = [:revisit, '.A | 0', 0]
|
276
|
+
event_expectations(event44, expectations)
|
277
|
+
|
278
|
+
event45 = walker.next
|
279
|
+
expectations = [:revisit, 'S => . A T | 0', 0]
|
280
|
+
event_expectations(event45, expectations)
|
281
|
+
|
282
|
+
event46 = walker.next
|
283
|
+
expectations = [:revisit, '.S | 0', 0]
|
284
|
+
event_expectations(event46, expectations)
|
285
|
+
|
286
|
+
event47 = walker.next
|
287
|
+
expectations = [:revisit, 'Phi => . S | 0', 0]
|
288
|
+
event_expectations(event47, expectations)
|
289
|
+
|
290
|
+
event48 = walker.next
|
291
|
+
expectations = [:revisit, '.Phi | 0', 0]
|
292
|
+
event_expectations(event48, expectations)
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
it 'could traverse lazily the parse graph backwards' do
|
297
|
+
walker = subject.build_walker(accept_entry, accept_index, true)
|
298
|
+
|
299
|
+
17.times { walker.next }
|
300
|
+
|
301
|
+
event18 = walker.next
|
302
|
+
expectations = [:revisit, 'T. | 1', 4]
|
303
|
+
event_expectations(event18, expectations)
|
304
|
+
|
305
|
+
# Lazy walk: make start entry .T the current one
|
169
306
|
# Multiple visit occurred: jump to antecedent of start entry
|
170
307
|
event19 = walker.next
|
171
308
|
expectations = [:visit, 'S => A . T | 0', 1]
|
@@ -195,7 +332,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
195
332
|
event25 = walker.next
|
196
333
|
expectations = [:revisit, '.S | 0', 0]
|
197
334
|
event_expectations(event25, expectations)
|
198
|
-
|
335
|
+
|
199
336
|
event26 = walker.next
|
200
337
|
expectations = [:revisit, 'Phi => . S | 0', 0]
|
201
338
|
event_expectations(event26, expectations)
|
@@ -236,30 +373,30 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
236
373
|
event35 = walker.next
|
237
374
|
expectations = [:visit, 'A => . B A | 0', 0]
|
238
375
|
event_expectations(event35, expectations)
|
239
|
-
|
376
|
+
|
240
377
|
event36 = walker.next
|
241
378
|
expectations = [:revisit, '.A | 0', 0]
|
242
379
|
event_expectations(event36, expectations)
|
243
380
|
|
244
381
|
event37 = walker.next
|
245
382
|
expectations = [:revisit, 'S => . A T | 0', 0]
|
246
|
-
event_expectations(event37, expectations)
|
247
|
-
|
383
|
+
event_expectations(event37, expectations)
|
384
|
+
|
248
385
|
event38 = walker.next
|
249
386
|
expectations = [:revisit, '.S | 0', 0]
|
250
387
|
event_expectations(event38, expectations)
|
251
|
-
|
388
|
+
|
252
389
|
event39 = walker.next
|
253
390
|
expectations = [:revisit, 'Phi => . S | 0', 0]
|
254
391
|
event_expectations(event39, expectations)
|
255
392
|
|
256
393
|
event40 = walker.next
|
257
394
|
expectations = [:revisit, '.Phi | 0', 0]
|
258
|
-
event_expectations(event40, expectations)
|
395
|
+
event_expectations(event40, expectations)
|
259
396
|
end
|
260
397
|
|
261
398
|
it 'should raise an exception at end of visit' do
|
262
|
-
walker = subject.build_walker(accept_entry, accept_index)
|
399
|
+
walker = subject.build_walker(accept_entry, accept_index, true)
|
263
400
|
40.times { walker.next }
|
264
401
|
|
265
402
|
expect { walker.next }.to raise_error(StopIteration)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.05
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coveralls
|
@@ -146,6 +146,13 @@ files:
|
|
146
146
|
- examples/general/calc_iter1/calc_lexer.rb
|
147
147
|
- examples/general/calc_iter1/calc_parser.rb
|
148
148
|
- examples/general/calc_iter1/spec/calculator_spec.rb
|
149
|
+
- examples/general/calc_iter2/calc_ast_builder.rb
|
150
|
+
- examples/general/calc_iter2/calc_ast_nodes.rb
|
151
|
+
- examples/general/calc_iter2/calc_demo.rb
|
152
|
+
- examples/general/calc_iter2/calc_grammar.rb
|
153
|
+
- examples/general/calc_iter2/calc_lexer.rb
|
154
|
+
- examples/general/calc_iter2/calc_parser.rb
|
155
|
+
- examples/general/calc_iter2/spec/calculator_spec.rb
|
149
156
|
- lib/rley.rb
|
150
157
|
- lib/rley/constants.rb
|
151
158
|
- lib/rley/formatter/asciitree.rb
|