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.
@@ -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