rley 0.5.04 → 0.5.05

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 anIndex [_index] The token index at end of anEntry
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
@@ -17,7 +17,7 @@ module Rley # This module is used as a namespace
17
17
  else
18
18
  CSTBuilder.new(aParseResult.tokens)
19
19
  end
20
- end
20
+ end
21
21
  end # class
22
22
  end # module
23
23
  end # module
@@ -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
- # Jump to related start entry...
120
- pairs = aContext.nterm2start[anEntry.vertex.non_terminal]
121
- new_entry = pairs[anEntry.origin]
122
- aContext.curr_entry = new_entry
123
- aContext.entry_set_index = new_entry.origin
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, trace' do
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 'should traverse the parse graph backwards' do
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.04
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-10-26 00:00:00.000000000 Z
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