dendroid 0.2.00 → 0.2.01

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.
@@ -1,293 +1,301 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'walk_progress'
4
-
5
- module Dendroid
6
- module Parsing
7
- class ChartWalker
8
- attr_reader :chart
9
- attr_reader :last_item
10
-
11
- def initialize(theChart)
12
- @chart = theChart
13
- end
14
-
15
- def walk(start_item)
16
- curr_rank = chart.size - 1
17
-
18
- parents = []
19
- progress = WalkProgress.new(curr_rank, start_item, parents)
20
- paths = [progress]
21
-
22
- if start_item.predecessors.size > 1
23
- # Create n times start_item as predecessors, then for each path initialize to its unique own predecessor
24
- forerunners = disambiguate(progress, start_item.predecessors)
25
- if forerunners.size == 1
26
- parents << ANDNode.new(start_item, curr_rank)
27
- else
28
- preds = sort_predecessors(forerunners)
29
- if start_item.rule.rhs.size == 1
30
- parents << ANDNode.new(start_item, curr_rank)
31
- progress.push_or_node(start_item.origin, preds.size)
32
- progress.curr_item = start_item
33
- fork(progress, paths, preds)
34
- else
35
- parents << OrNode.new(start_item.lhs, start_item.origin, curr_rank, preds.size)
36
- progress.curr_item = start_item
37
- fork(progress, paths, preds)
38
- end
39
- end
40
- else
41
- parents << ANDNode.new(start_item, curr_rank)
42
- end
43
- token2node = {}
44
- entry2node = {}
45
- sharing = {}
46
- or_nodes_crossed = {}
47
-
48
- loop do # Iterate over rank values
49
- pass = :primary
50
- loop do # Iterate over paths until all are ready for previous rank
51
- paths.each do |prg|
52
- next if prg.state == :Complete || prg.state == :Delegating
53
- next if pass == :secondary && prg.state == :Waiting
54
-
55
- step_back(prg, paths, token2node, entry2node, sharing, or_nodes_crossed)
56
- end
57
- # TODO: handle path removal
58
- break if paths.none? { |pg| pg.state == :Running || pg.state == :Forking }
59
- pass = :secondary
60
- end
61
- break if paths.all? { |prg| prg.state == :Complete }
62
-
63
- entry2node.clear
64
- end
65
-
66
- parents[0]
67
- end
68
-
69
- def step_back(walk_progress, paths, token2node, entry2node, sharing, or_nodes_crossed)
70
- loop do
71
- case walk_progress.state
72
- when :Waiting, :New
73
- predecessors = predecessors_of(walk_progress.curr_item, walk_progress.parents)
74
- last_parent = walk_progress.parents.last
75
- if sharing.include? last_parent
76
- delegating = sharing[last_parent]
77
- unless delegating.include? walk_progress
78
- delegating.each do |dlg|
79
- dlg.curr_rank = walk_progress.curr_rank
80
- dlg.curr_item = walk_progress.curr_item
81
- dlg.state = :Waiting
82
- end
83
- sharing.delete(last_parent)
84
- end
85
- end
86
- walk_progress.state = :Running
87
-
88
- when :Running
89
- predecessors = predecessors_of(walk_progress.curr_item, walk_progress.parents)
90
-
91
- when :Forking
92
- # predecessors = [walk_progress.curr_item]
93
- predecessors = [walk_progress.predecessor]
94
- walk_progress.predecessor = nil
95
- walk_progress.state = :Running
96
- end
97
-
98
- if predecessors.empty?
99
- walk_progress.state = :Complete
100
- break
101
- end
102
-
103
- case walk_progress.curr_item.algo
104
- when :completer
105
- completer_backwards(walk_progress, paths, entry2node, sharing, predecessors)
106
- break if walk_progress.state == :Delegating
107
-
108
- when :scanner
109
- curr_token = chart.tokens[walk_progress.curr_rank - 1]
110
- if token2node.include? curr_token
111
- walk_progress.add_child_node(token2node[curr_token])
112
- walk_progress.curr_rank -= 1
113
- else
114
- new_node = walk_progress.add_terminal_node(chart.tokens[walk_progress.curr_rank - 1])
115
- token2node[curr_token] = new_node
116
- end
117
- if predecessors.size == 1
118
- walk_progress.curr_item = predecessors[0]
119
- walk_progress.state = :Waiting
120
- break
121
- else
122
- # TODO: fix assumption single predecessor
123
- raise StandardError
124
- end
125
-
126
- when :predictor
127
- unless walk_progress.parents.last.partial?
128
- last_parent = walk_progress.parents.pop
129
- if sharing.include? last_parent
130
- delegating = sharing[last_parent]
131
- unless delegating.include? walk_progress
132
- delegating.each do |dlg|
133
- dlg.curr_rank = walk_progress.curr_rank
134
- dlg.curr_item = walk_progress.curr_item
135
- dlg.state = :Running
136
- end
137
- sharing.delete(last_parent)
138
- end
139
- end
140
- if last_parent.is_a?(OrNode)
141
- if or_nodes_crossed.include?(last_parent)
142
- walk_progress.state = :Complete
143
- break
144
- else
145
- or_nodes_crossed[last_parent] = true
146
- end
147
- end
148
- end
149
- index_empty = predecessors.find_index { |entry| entry.dotted_item.empty? }
150
- if index_empty
151
- entry_empty = predecessors.delete_at(index_empty)
152
- walk_progress.add_node_empty(entry_empty)
153
- raise StandardError unless predecessors.empty? # Uncovered case
154
- walk_progress.curr_item = entry_empty
155
- next
156
- end
157
- if predecessors.size == 1
158
- walk_progress.curr_item = predecessors[0]
159
- else
160
- # curr_item has multiple predecessors from distinct rules
161
- # look in lineage the latest entry that matches one of the ancestors AND
162
- # has a free slot for the current symbol
163
- matches = walk_progress.match_parent?(predecessors, true)
164
- if matches.empty?
165
- walk_progress.state = :Complete
166
- break
167
- end
168
- (matching_pred, stack_offset) = matches.first
169
- walk_progress.curr_item = matching_pred
170
- unless stack_offset.zero?
171
- removed = walk_progress.parents.pop(stack_offset)
172
- if removed.is_a?(Array)
173
- or_nodes = removed.select { |entry| entry.is_a?(OrNode) }
174
- unless or_nodes.empty?
175
- or_nodes.reverse_each do |or_nd|
176
- if or_nodes_crossed.include?(or_nd)
177
- walk_progress.state = :Complete
178
- break
179
- else
180
- or_nodes_crossed[or_nd] = true
181
- end
182
- end
183
- break if walk_progress.state == :Complete
184
-
185
- end
186
- elsif removed.is_a?(OrNode)
187
- if or_nodes_crossed.include?(removed)
188
- walk_progress.state = :Complete
189
- break
190
- else
191
- or_nodes_crossed[removed] = true
192
- end
193
- end
194
- end
195
- end
196
- else
197
- raise StandardError
198
- end
199
- end
200
-
201
- walk_progress
202
- end
203
-
204
- def disambiguate(_progress, predecessors)
205
- predecessors
206
- end
207
-
208
- def sort_predecessors(predecessors)
209
- predecessors
210
- end
211
-
212
- def predecessors_of(anEItem, parents)
213
- # Rule: if anEItem has itself as predecessor AND parents contains
214
- # only a start item, then remove anEItem from its own predecessor(s).
215
- if (parents.size == 1) && anEItem.predecessors.include?(anEItem)
216
- # raise StandardError unless parents[0].match(anEItem)
217
- unless parents[0].match(anEItem)
218
- raise StandardError
219
- end
220
- preds = anEItem.predecessors.dup
221
- preds.delete(anEItem)
222
- preds
223
- else
224
- anEItem.predecessors
225
- end
226
- end
227
-
228
- def completer_backwards(walk_progress, paths, entry2node, sharing, predecessors)
229
- # Trying to remove some predecessors with some disambiguation technique
230
- forerunners = disambiguate(walk_progress, predecessors)
231
-
232
- if forerunners.size == 1
233
- pred = forerunners[0]
234
- if entry2node.include? pred
235
- shared_node = entry2node[pred]
236
- if sharing.include? shared_node
237
- sharing[shared_node] << walk_progress
238
- else
239
- sharing[shared_node] = [walk_progress]
240
- end
241
- walk_progress.add_child_node(shared_node)
242
- walk_progress.parents.push(shared_node)
243
- walk_progress.state = :Delegating
244
-
245
- elsif pred.predecessors.size == 1
246
- new_node = walk_progress.push_and_node(pred)
247
- walk_progress.curr_item = pred
248
- entry2node[pred] = new_node
249
- else
250
- pre_forerunners = disambiguate(walk_progress, pred.predecessors)
251
- index_empty = pre_forerunners.find_index { |entry| entry.dotted_item.empty? }
252
- if index_empty
253
- entry_empty = pre_forerunners.delete_at(index_empty)
254
- walk_progress.add_node_empty(entry_empty)
255
- walk_progress.curr_item = entry_empty.predecessors[0] # Assuming only one predecessor
256
- end
257
- if pre_forerunners.size == 1
258
- pred = forerunners[0]
259
- new_node = walk_progress.push_and_node(pre_forerunners[0])
260
- walk_progress.curr_item = pred
261
- entry2node[pred] = new_node
262
- else
263
- prepreds = sort_predecessors(pre_forerunners)
264
- new_node = walk_progress.push_or_node(pred.origin, prepreds.size)
265
- walk_progress.curr_item = pred
266
- entry2node[pred] = new_node
267
- fork(walk_progress, paths, prepreds)
268
- end
269
- end
270
- else
271
- # AMBIGUITY: multiple valid predecessors
272
- preds = sort_predecessors(forerunners)
273
- walk_progress.push_or_node(preds)
274
- fork(walk_progress, paths, preds)
275
- end
276
- end
277
-
278
- def fork(walk_progress, paths, sorted_predecessors)
279
- progs = [walk_progress]
280
- walk_progress.fork(sorted_predecessors[0])
281
- sorted_predecessors[1..-1].each do |prd|
282
- alternate = walk_progress.dup
283
- alternate.fork(prd)
284
- paths << alternate
285
- progs << alternate
286
- end
287
-
288
- progs.each { |pg| pg.push_and_node(pg.curr_item) }
289
- end
290
-
291
- end # class
292
- end # module
293
- end # module
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'walk_progress'
4
+
5
+ module Dendroid
6
+ module Parsing
7
+ class ChartWalker
8
+ attr_reader :chart
9
+ attr_reader :last_item
10
+
11
+ # rubocop: disable Metrics/AbcSize
12
+ # rubocop: disable Metrics/CyclomaticComplexity
13
+ # rubocop: disable Metrics/PerceivedComplexity
14
+
15
+ def initialize(theChart)
16
+ @chart = theChart
17
+ end
18
+
19
+ def walk(start_item)
20
+ curr_rank = chart.size - 1
21
+
22
+ parents = []
23
+ progress = WalkProgress.new(curr_rank, start_item, parents)
24
+ paths = [progress]
25
+
26
+ if start_item.predecessors.size > 1
27
+ # Create n times start_item as predecessors, then for each path initialize to its unique own predecessor
28
+ forerunners = disambiguate(progress, start_item.predecessors)
29
+ if forerunners.size == 1
30
+ parents << ANDNode.new(start_item, curr_rank)
31
+ else
32
+ preds = sort_predecessors(forerunners)
33
+ if start_item.rule.rhs.size == 1
34
+ parents << ANDNode.new(start_item, curr_rank)
35
+ progress.push_or_node(start_item.origin, preds.size)
36
+ else
37
+ parents << OrNode.new(start_item.lhs, start_item.origin, curr_rank, preds.size)
38
+ end
39
+ progress.curr_item = start_item
40
+ fork(progress, paths, preds)
41
+ end
42
+ else
43
+ parents << ANDNode.new(start_item, curr_rank)
44
+ end
45
+ token2node = {}
46
+ entry2node = {}
47
+ sharing = {}
48
+ or_nodes_crossed = {}
49
+
50
+ loop do # Iterate over rank values
51
+ pass = :primary
52
+ loop do # Iterate over paths until all are ready for previous rank
53
+ paths.each do |prg|
54
+ next if prg.state == :Complete || prg.state == :Delegating
55
+ next if pass == :secondary && prg.state == :Waiting
56
+
57
+ step_back(prg, paths, token2node, entry2node, sharing, or_nodes_crossed)
58
+ end
59
+ # TODO: handle path removal
60
+ break if paths.none? { |pg| pg.state == :Running || pg.state == :Forking }
61
+
62
+ pass = :secondary
63
+ end
64
+ break if paths.all? { |prg| prg.state == :Complete }
65
+
66
+ entry2node.clear
67
+ end
68
+
69
+ parents[0]
70
+ end
71
+
72
+ def step_back(walk_progress, paths, token2node, entry2node, sharing, or_nodes_crossed)
73
+ loop do
74
+ case walk_progress.state
75
+ when :Waiting, :New
76
+ predecessors = predecessors_of(walk_progress.curr_item, walk_progress.parents)
77
+ last_parent = walk_progress.parents.last
78
+ if sharing.include? last_parent
79
+ delegating = sharing[last_parent]
80
+ unless delegating.include? walk_progress
81
+ delegating.each do |dlg|
82
+ dlg.curr_rank = walk_progress.curr_rank
83
+ dlg.curr_item = walk_progress.curr_item
84
+ dlg.state = :Waiting
85
+ end
86
+ sharing.delete(last_parent)
87
+ end
88
+ end
89
+ walk_progress.state = :Running
90
+
91
+ when :Running
92
+ predecessors = predecessors_of(walk_progress.curr_item, walk_progress.parents)
93
+
94
+ when :Forking
95
+ # predecessors = [walk_progress.curr_item]
96
+ predecessors = [walk_progress.predecessor]
97
+ walk_progress.predecessor = nil
98
+ walk_progress.state = :Running
99
+ end
100
+
101
+ if predecessors.empty?
102
+ walk_progress.state = :Complete
103
+ break
104
+ end
105
+
106
+ case walk_progress.curr_item.algo
107
+ when :completer
108
+ completer_backwards(walk_progress, paths, entry2node, sharing, predecessors)
109
+ break if walk_progress.state == :Delegating
110
+
111
+ when :scanner
112
+ curr_token = chart.tokens[walk_progress.curr_rank - 1]
113
+ if token2node.include? curr_token
114
+ walk_progress.add_child_node(token2node[curr_token])
115
+ walk_progress.curr_rank -= 1
116
+ else
117
+ new_node = walk_progress.add_terminal_node(chart.tokens[walk_progress.curr_rank - 1])
118
+ token2node[curr_token] = new_node
119
+ end
120
+ if predecessors.size == 1
121
+ walk_progress.curr_item = predecessors[0]
122
+ walk_progress.state = :Waiting
123
+ break
124
+ else
125
+ # TODO: challenge assumption single predecessor
126
+ raise StandardError
127
+ end
128
+
129
+ when :predictor
130
+ unless walk_progress.parents.last.partial?
131
+ last_parent = walk_progress.parents.pop
132
+ if sharing.include? last_parent
133
+ delegating = sharing[last_parent]
134
+ unless delegating.include? walk_progress
135
+ delegating.each do |dlg|
136
+ dlg.curr_rank = walk_progress.curr_rank
137
+ dlg.curr_item = walk_progress.curr_item
138
+ dlg.state = :Running
139
+ end
140
+ sharing.delete(last_parent)
141
+ end
142
+ end
143
+ if last_parent.is_a?(OrNode)
144
+ if or_nodes_crossed.include?(last_parent)
145
+ walk_progress.state = :Complete
146
+ break
147
+ else
148
+ or_nodes_crossed[last_parent] = true
149
+ end
150
+ end
151
+ end
152
+ index_empty = predecessors.find_index { |entry| entry.dotted_item.empty? }
153
+ if index_empty
154
+ entry_empty = predecessors.delete_at(index_empty)
155
+ walk_progress.add_node_empty(entry_empty)
156
+ raise StandardError unless predecessors.empty? # Uncovered case
157
+
158
+ walk_progress.curr_item = entry_empty
159
+ next
160
+ end
161
+ if predecessors.size == 1
162
+ walk_progress.curr_item = predecessors[0]
163
+ else
164
+ # curr_item has multiple predecessors from distinct rules
165
+ # look in lineage the latest entry that matches one of the ancestors AND
166
+ # has a free slot for the current symbol
167
+ matches = walk_progress.match_parent?(predecessors, true)
168
+ if matches.empty?
169
+ walk_progress.state = :Complete
170
+ break
171
+ end
172
+ (matching_pred, stack_offset) = matches.first
173
+ walk_progress.curr_item = matching_pred
174
+ unless stack_offset.zero?
175
+ removed = walk_progress.parents.pop(stack_offset)
176
+ if removed.is_a?(Array)
177
+ or_nodes = removed.select { |entry| entry.is_a?(OrNode) }
178
+ unless or_nodes.empty?
179
+ or_nodes.reverse_each do |or_nd|
180
+ if or_nodes_crossed.include?(or_nd)
181
+ walk_progress.state = :Complete
182
+ break
183
+ else
184
+ or_nodes_crossed[or_nd] = true
185
+ end
186
+ end
187
+ break if walk_progress.state == :Complete
188
+
189
+ end
190
+ elsif removed.is_a?(OrNode)
191
+ if or_nodes_crossed.include?(removed)
192
+ walk_progress.state = :Complete
193
+ break
194
+ else
195
+ or_nodes_crossed[removed] = true
196
+ end
197
+ end
198
+ end
199
+ end
200
+ else
201
+ raise StandardError
202
+ end
203
+ end
204
+
205
+ walk_progress
206
+ end
207
+
208
+ def disambiguate(_progress, predecessors)
209
+ predecessors
210
+ end
211
+
212
+ def sort_predecessors(predecessors)
213
+ predecessors
214
+ end
215
+
216
+ def predecessors_of(anEItem, parents)
217
+ # Rule: if anEItem has itself as predecessor AND parents contains
218
+ # only a start item, then remove anEItem from its own predecessor(s).
219
+ if (parents.size == 1) && anEItem.predecessors.include?(anEItem)
220
+ # raise StandardError unless parents[0].match(anEItem)
221
+ unless parents[0].match(anEItem)
222
+ raise StandardError
223
+
224
+ end
225
+ preds = anEItem.predecessors.dup
226
+ preds.delete(anEItem)
227
+ preds
228
+ else
229
+ anEItem.predecessors
230
+ end
231
+ end
232
+
233
+ def completer_backwards(walk_progress, paths, entry2node, sharing, predecessors)
234
+ # Trying to remove some predecessors with some disambiguation technique
235
+ forerunners = disambiguate(walk_progress, predecessors)
236
+
237
+ if forerunners.size == 1
238
+ pred = forerunners[0]
239
+ if entry2node.include? pred
240
+ shared_node = entry2node[pred]
241
+ if sharing.include? shared_node
242
+ sharing[shared_node] << walk_progress
243
+ else
244
+ sharing[shared_node] = [walk_progress]
245
+ end
246
+ walk_progress.add_child_node(shared_node)
247
+ walk_progress.parents.push(shared_node)
248
+ walk_progress.state = :Delegating
249
+
250
+ elsif pred.predecessors.size == 1
251
+ new_node = walk_progress.push_and_node(pred)
252
+ walk_progress.curr_item = pred
253
+ entry2node[pred] = new_node
254
+ else
255
+ pre_forerunners = disambiguate(walk_progress, pred.predecessors)
256
+ index_empty = pre_forerunners.find_index { |entry| entry.dotted_item.empty? }
257
+ if index_empty
258
+ entry_empty = pre_forerunners.delete_at(index_empty)
259
+ walk_progress.add_node_empty(entry_empty)
260
+ walk_progress.curr_item = entry_empty.predecessors[0] # Assuming only one predecessor
261
+ end
262
+ if pre_forerunners.size == 1
263
+ pred = forerunners[0]
264
+ new_node = walk_progress.push_and_node(pre_forerunners[0])
265
+ walk_progress.curr_item = pred
266
+ entry2node[pred] = new_node
267
+ else
268
+ prepreds = sort_predecessors(pre_forerunners)
269
+ new_node = walk_progress.push_or_node(pred.origin, prepreds.size)
270
+ walk_progress.curr_item = pred
271
+ entry2node[pred] = new_node
272
+ fork(walk_progress, paths, prepreds)
273
+ end
274
+ end
275
+ else
276
+ # AMBIGUITY: multiple valid predecessors
277
+ preds = sort_predecessors(forerunners)
278
+ walk_progress.push_or_node(preds)
279
+ fork(walk_progress, paths, preds)
280
+ end
281
+ end
282
+
283
+ def fork(walk_progress, paths, sorted_predecessors)
284
+ progs = [walk_progress]
285
+ walk_progress.fork(sorted_predecessors[0])
286
+ sorted_predecessors[1..].each do |prd|
287
+ alternate = walk_progress.dup
288
+ alternate.fork(prd)
289
+ paths << alternate
290
+ progs << alternate
291
+ end
292
+
293
+ progs.each { |pg| pg.push_and_node(pg.curr_item) }
294
+ end
295
+ end # class
296
+
297
+ # rubocop: enable Metrics/AbcSize
298
+ # rubocop: enable Metrics/CyclomaticComplexity
299
+ # rubocop: enable Metrics/PerceivedComplexity
300
+ end # module
301
+ end # module
@@ -1,21 +1,21 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'parse_node'
4
-
5
- module Dendroid
6
- module Parsing
7
- class CompositeParseNode < ParseNode
8
- attr_reader :range
9
- attr_reader :children
10
-
11
- def initialize(lowerBound, upperBound, child_count)
12
- super(lowerBound, upperBound)
13
- @children = Array.new(child_count, nil)
14
- end
15
-
16
- def add_child(child_node, index)
17
- children[index] = child_node
18
- end
19
- end # class
20
- end # module
21
- end # module
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'parse_node'
4
+
5
+ module Dendroid
6
+ module Parsing
7
+ class CompositeParseNode < ParseNode
8
+ attr_reader :range
9
+ attr_reader :children
10
+
11
+ def initialize(lowerBound, upperBound, child_count)
12
+ super(lowerBound, upperBound)
13
+ @children = Array.new(child_count, nil)
14
+ end
15
+
16
+ def add_child(child_node, index)
17
+ children[index] = child_node
18
+ end
19
+ end # class
20
+ end # module
21
+ end # module