lrama 0.6.11 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/gh-pages.yml +46 -0
- data/.github/workflows/test.yaml +35 -7
- data/.gitignore +1 -0
- data/.rdoc_options +2 -0
- data/Gemfile +4 -2
- data/NEWS.md +60 -0
- data/README.md +44 -15
- data/Rakefile +13 -1
- data/Steepfile +2 -0
- data/doc/Index.md +58 -0
- data/lib/lrama/bitmap.rb +3 -0
- data/lib/lrama/command.rb +2 -1
- data/lib/lrama/digraph.rb +30 -0
- data/lib/lrama/grammar/binding.rb +47 -15
- data/lib/lrama/grammar/rule.rb +8 -0
- data/lib/lrama/grammar/rule_builder.rb +3 -15
- data/lib/lrama/grammar.rb +8 -3
- data/lib/lrama/lexer/grammar_file.rb +8 -1
- data/lib/lrama/lexer/location.rb +17 -1
- data/lib/lrama/lexer/token/char.rb +1 -0
- data/lib/lrama/lexer/token/ident.rb +1 -0
- data/lib/lrama/lexer/token/instantiate_rule.rb +6 -1
- data/lib/lrama/lexer/token/tag.rb +3 -1
- data/lib/lrama/lexer/token/user_code.rb +5 -1
- data/lib/lrama/lexer/token.rb +14 -2
- data/lib/lrama/lexer.rb +4 -5
- data/lib/lrama/logger.rb +4 -0
- data/lib/lrama/option_parser.rb +10 -8
- data/lib/lrama/options.rb +2 -1
- data/lib/lrama/parser.rb +10 -4
- data/lib/lrama/state.rb +288 -1
- data/lib/lrama/states/item.rb +8 -0
- data/lib/lrama/states.rb +69 -2
- data/lib/lrama/trace_reporter.rb +17 -2
- data/lib/lrama/version.rb +1 -1
- data/lrama.gemspec +1 -1
- data/parser.y +4 -3
- data/rbs_collection.lock.yaml +3 -3
- data/sig/generated/lrama/bitmap.rbs +11 -0
- data/sig/generated/lrama/digraph.rbs +39 -0
- data/sig/generated/lrama/grammar/binding.rbs +34 -0
- data/sig/generated/lrama/lexer/grammar_file.rbs +28 -0
- data/sig/generated/lrama/lexer/location.rbs +52 -0
- data/sig/{lrama → generated/lrama}/lexer/token/char.rbs +2 -0
- data/sig/{lrama → generated/lrama}/lexer/token/ident.rbs +2 -0
- data/sig/{lrama → generated/lrama}/lexer/token/instantiate_rule.rbs +8 -0
- data/sig/{lrama → generated/lrama}/lexer/token/tag.rbs +3 -0
- data/sig/{lrama → generated/lrama}/lexer/token/user_code.rbs +6 -1
- data/sig/{lrama → generated/lrama}/lexer/token.rbs +26 -3
- data/sig/generated/lrama/logger.rbs +14 -0
- data/sig/generated/lrama/trace_reporter.rbs +25 -0
- data/sig/lrama/grammar/rule_builder.rbs +0 -1
- data/sig/lrama/options.rbs +1 -0
- metadata +19 -14
- data/sig/lrama/bitmap.rbs +0 -7
- data/sig/lrama/digraph.rbs +0 -23
- data/sig/lrama/grammar/binding.rbs +0 -19
- data/sig/lrama/lexer/grammar_file.rbs +0 -17
- data/sig/lrama/lexer/location.rbs +0 -26
data/lib/lrama/state.rb
CHANGED
@@ -10,7 +10,7 @@ module Lrama
|
|
10
10
|
class State
|
11
11
|
attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
|
12
12
|
:default_reduction_rule, :closure, :items
|
13
|
-
attr_accessor :shifts, :reduces
|
13
|
+
attr_accessor :shifts, :reduces, :ielr_isocores, :lalr_isocore
|
14
14
|
|
15
15
|
def initialize(id, accessing_symbol, kernels)
|
16
16
|
@id = id
|
@@ -23,6 +23,12 @@ module Lrama
|
|
23
23
|
@conflicts = []
|
24
24
|
@resolved_conflicts = []
|
25
25
|
@default_reduction_rule = nil
|
26
|
+
@predecessors = []
|
27
|
+
@lalr_isocore = self
|
28
|
+
@ielr_isocores = [self]
|
29
|
+
@internal_dependencies = {}
|
30
|
+
@successor_dependencies = {}
|
31
|
+
@always_follows = {}
|
26
32
|
end
|
27
33
|
|
28
34
|
def closure=(closure)
|
@@ -84,6 +90,18 @@ module Lrama
|
|
84
90
|
@transitions ||= shifts.map {|shift| [shift, @items_to_state[shift.next_items]] }
|
85
91
|
end
|
86
92
|
|
93
|
+
def update_transition(shift, next_state)
|
94
|
+
set_items_to_state(shift.next_items, next_state)
|
95
|
+
next_state.append_predecessor(self)
|
96
|
+
clear_transitions_cache
|
97
|
+
end
|
98
|
+
|
99
|
+
def clear_transitions_cache
|
100
|
+
@nterm_transitions = nil
|
101
|
+
@term_transitions = nil
|
102
|
+
@transitions = nil
|
103
|
+
end
|
104
|
+
|
87
105
|
def selected_term_transitions
|
88
106
|
term_transitions.reject do |shift, next_state|
|
89
107
|
shift.not_selected
|
@@ -142,5 +160,274 @@ module Lrama
|
|
142
160
|
conflict.type == :reduce_reduce
|
143
161
|
end
|
144
162
|
end
|
163
|
+
|
164
|
+
def propagate_lookaheads(next_state)
|
165
|
+
next_state.kernels.map {|item|
|
166
|
+
lookahead_sets =
|
167
|
+
if item.position == 1
|
168
|
+
goto_follow_set(item.lhs)
|
169
|
+
else
|
170
|
+
kernel = kernels.find {|k| k.predecessor_item_of?(item) }
|
171
|
+
item_lookahead_set[kernel]
|
172
|
+
end
|
173
|
+
|
174
|
+
[item, lookahead_sets & next_state.lookahead_set_filters[item]]
|
175
|
+
}.to_h
|
176
|
+
end
|
177
|
+
|
178
|
+
def lookaheads_recomputed
|
179
|
+
!@item_lookahead_set.nil?
|
180
|
+
end
|
181
|
+
|
182
|
+
def compatible_lookahead?(filtered_lookahead)
|
183
|
+
!lookaheads_recomputed ||
|
184
|
+
@lalr_isocore.annotation_list.all? {|token, actions|
|
185
|
+
a = dominant_contribution(token, actions, item_lookahead_set)
|
186
|
+
b = dominant_contribution(token, actions, filtered_lookahead)
|
187
|
+
a.nil? || b.nil? || a == b
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
def lookahead_set_filters
|
192
|
+
kernels.map {|kernel|
|
193
|
+
[kernel,
|
194
|
+
@lalr_isocore.annotation_list.select {|token, actions|
|
195
|
+
token.term? && actions.any? {|action, contributions|
|
196
|
+
!contributions.nil? && contributions.key?(kernel) && contributions[kernel]
|
197
|
+
}
|
198
|
+
}.map {|token, _| token }
|
199
|
+
]
|
200
|
+
}.to_h
|
201
|
+
end
|
202
|
+
|
203
|
+
def dominant_contribution(token, actions, lookaheads)
|
204
|
+
a = actions.select {|action, contributions|
|
205
|
+
contributions.nil? || contributions.any? {|item, contributed| contributed && lookaheads[item].include?(token) }
|
206
|
+
}.map {|action, _| action }
|
207
|
+
return nil if a.empty?
|
208
|
+
a.reject {|action|
|
209
|
+
if action.is_a?(State::Shift)
|
210
|
+
action.not_selected
|
211
|
+
elsif action.is_a?(State::Reduce)
|
212
|
+
action.not_selected_symbols.include?(token)
|
213
|
+
end
|
214
|
+
}
|
215
|
+
end
|
216
|
+
|
217
|
+
def inadequacy_list
|
218
|
+
return @inadequacy_list if @inadequacy_list
|
219
|
+
|
220
|
+
shift_contributions = shifts.map {|shift|
|
221
|
+
[shift.next_sym, [shift]]
|
222
|
+
}.to_h
|
223
|
+
reduce_contributions = reduces.map {|reduce|
|
224
|
+
(reduce.look_ahead || []).map {|sym|
|
225
|
+
[sym, [reduce]]
|
226
|
+
}.to_h
|
227
|
+
}.reduce(Hash.new([])) {|hash, cont|
|
228
|
+
hash.merge(cont) {|_, a, b| a | b }
|
229
|
+
}
|
230
|
+
|
231
|
+
list = shift_contributions.merge(reduce_contributions) {|_, a, b| a | b }
|
232
|
+
@inadequacy_list = list.select {|token, actions| token.term? && actions.size > 1 }
|
233
|
+
end
|
234
|
+
|
235
|
+
def annotation_list
|
236
|
+
return @annotation_list if @annotation_list
|
237
|
+
|
238
|
+
@annotation_list = annotate_manifestation
|
239
|
+
@annotation_list = @items_to_state.values.map {|next_state| next_state.annotate_predecessor(self) }
|
240
|
+
.reduce(@annotation_list) {|result, annotations|
|
241
|
+
result.merge(annotations) {|_, actions_a, actions_b|
|
242
|
+
if actions_a.nil? || actions_b.nil?
|
243
|
+
actions_a || actions_b
|
244
|
+
else
|
245
|
+
actions_a.merge(actions_b) {|_, contributions_a, contributions_b|
|
246
|
+
if contributions_a.nil? || contributions_b.nil?
|
247
|
+
next contributions_a || contributions_b
|
248
|
+
end
|
249
|
+
|
250
|
+
contributions_a.merge(contributions_b) {|_, contributed_a, contributed_b|
|
251
|
+
contributed_a || contributed_b
|
252
|
+
}
|
253
|
+
}
|
254
|
+
end
|
255
|
+
}
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
def annotate_manifestation
|
260
|
+
inadequacy_list.transform_values {|actions|
|
261
|
+
actions.map {|action|
|
262
|
+
if action.is_a?(Shift)
|
263
|
+
[action, nil]
|
264
|
+
elsif action.is_a?(Reduce)
|
265
|
+
if action.rule.empty_rule?
|
266
|
+
[action, lhs_contributions(action.rule.lhs, inadequacy_list.key(actions))]
|
267
|
+
else
|
268
|
+
contributions = kernels.map {|kernel| [kernel, kernel.rule == action.rule && kernel.end_of_rule?] }.to_h
|
269
|
+
[action, contributions]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
}.to_h
|
273
|
+
}
|
274
|
+
end
|
275
|
+
|
276
|
+
def annotate_predecessor(predecessor)
|
277
|
+
annotation_list.transform_values {|actions|
|
278
|
+
token = annotation_list.key(actions)
|
279
|
+
actions.transform_values {|inadequacy|
|
280
|
+
next nil if inadequacy.nil?
|
281
|
+
lhs_adequacy = kernels.any? {|kernel|
|
282
|
+
inadequacy[kernel] && kernel.position == 1 && predecessor.lhs_contributions(kernel.lhs, token).nil?
|
283
|
+
}
|
284
|
+
if lhs_adequacy
|
285
|
+
next nil
|
286
|
+
else
|
287
|
+
predecessor.kernels.map {|pred_k|
|
288
|
+
[pred_k, kernels.any? {|k|
|
289
|
+
inadequacy[k] && (
|
290
|
+
pred_k.predecessor_item_of?(k) && predecessor.item_lookahead_set[pred_k].include?(token) ||
|
291
|
+
k.position == 1 && predecessor.lhs_contributions(k.lhs, token)[pred_k]
|
292
|
+
)
|
293
|
+
}]
|
294
|
+
}.to_h
|
295
|
+
end
|
296
|
+
}
|
297
|
+
}
|
298
|
+
end
|
299
|
+
|
300
|
+
def lhs_contributions(sym, token)
|
301
|
+
shift, next_state = nterm_transitions.find {|sh, _| sh.next_sym == sym }
|
302
|
+
if always_follows(shift, next_state).include?(token)
|
303
|
+
nil
|
304
|
+
else
|
305
|
+
kernels.map {|kernel| [kernel, follow_kernel_items(shift, next_state, kernel) && item_lookahead_set[kernel].include?(token)] }.to_h
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def follow_kernel_items(shift, next_state, kernel)
|
310
|
+
queue = [[self, shift, next_state]]
|
311
|
+
until queue.empty?
|
312
|
+
st, sh, next_st = queue.pop
|
313
|
+
return true if kernel.next_sym == sh.next_sym && kernel.symbols_after_transition.all?(&:nullable)
|
314
|
+
st.internal_dependencies(sh, next_st).each {|v| queue << v }
|
315
|
+
end
|
316
|
+
false
|
317
|
+
end
|
318
|
+
|
319
|
+
def item_lookahead_set
|
320
|
+
return @item_lookahead_set if @item_lookahead_set
|
321
|
+
|
322
|
+
kernels.map {|item|
|
323
|
+
value =
|
324
|
+
if item.lhs.accept_symbol?
|
325
|
+
[]
|
326
|
+
elsif item.position > 1
|
327
|
+
prev_items = predecessors_with_item(item)
|
328
|
+
prev_items.map {|st, i| st.item_lookahead_set[i] }.reduce([]) {|acc, syms| acc |= syms }
|
329
|
+
elsif item.position == 1
|
330
|
+
prev_state = @predecessors.find {|p| p.shifts.any? {|shift| shift.next_sym == item.lhs } }
|
331
|
+
shift, next_state = prev_state.nterm_transitions.find {|shift, _| shift.next_sym == item.lhs }
|
332
|
+
prev_state.goto_follows(shift, next_state)
|
333
|
+
end
|
334
|
+
[item, value]
|
335
|
+
}.to_h
|
336
|
+
end
|
337
|
+
|
338
|
+
def item_lookahead_set=(k)
|
339
|
+
@item_lookahead_set = k
|
340
|
+
end
|
341
|
+
|
342
|
+
def predecessors_with_item(item)
|
343
|
+
result = []
|
344
|
+
@predecessors.each do |pre|
|
345
|
+
pre.items.each do |i|
|
346
|
+
result << [pre, i] if i.predecessor_item_of?(item)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
result
|
350
|
+
end
|
351
|
+
|
352
|
+
def append_predecessor(prev_state)
|
353
|
+
@predecessors << prev_state
|
354
|
+
@predecessors.uniq!
|
355
|
+
end
|
356
|
+
|
357
|
+
def goto_follow_set(nterm_token)
|
358
|
+
return [] if nterm_token.accept_symbol?
|
359
|
+
shift, next_state = @lalr_isocore.nterm_transitions.find {|sh, _| sh.next_sym == nterm_token }
|
360
|
+
|
361
|
+
@kernels
|
362
|
+
.select {|kernel| follow_kernel_items(shift, next_state, kernel) }
|
363
|
+
.map {|kernel| item_lookahead_set[kernel] }
|
364
|
+
.reduce(always_follows(shift, next_state)) {|result, terms| result |= terms }
|
365
|
+
end
|
366
|
+
|
367
|
+
def goto_follows(shift, next_state)
|
368
|
+
queue = internal_dependencies(shift, next_state) + predecessor_dependencies(shift, next_state)
|
369
|
+
terms = always_follows(shift, next_state)
|
370
|
+
until queue.empty?
|
371
|
+
st, sh, next_st = queue.pop
|
372
|
+
terms |= st.always_follows(sh, next_st)
|
373
|
+
st.internal_dependencies(sh, next_st).each {|v| queue << v }
|
374
|
+
st.predecessor_dependencies(sh, next_st).each {|v| queue << v }
|
375
|
+
end
|
376
|
+
terms
|
377
|
+
end
|
378
|
+
|
379
|
+
def always_follows(shift, next_state)
|
380
|
+
return @always_follows[[shift, next_state]] if @always_follows[[shift, next_state]]
|
381
|
+
|
382
|
+
queue = internal_dependencies(shift, next_state) + successor_dependencies(shift, next_state)
|
383
|
+
terms = []
|
384
|
+
until queue.empty?
|
385
|
+
st, sh, next_st = queue.pop
|
386
|
+
terms |= next_st.term_transitions.map {|sh, _| sh.next_sym }
|
387
|
+
st.internal_dependencies(sh, next_st).each {|v| queue << v }
|
388
|
+
st.successor_dependencies(sh, next_st).each {|v| queue << v }
|
389
|
+
end
|
390
|
+
@always_follows[[shift, next_state]] = terms
|
391
|
+
end
|
392
|
+
|
393
|
+
def internal_dependencies(shift, next_state)
|
394
|
+
return @internal_dependencies[[shift, next_state]] if @internal_dependencies[[shift, next_state]]
|
395
|
+
|
396
|
+
syms = @items.select {|i|
|
397
|
+
i.next_sym == shift.next_sym && i.symbols_after_transition.all?(&:nullable) && i.position == 0
|
398
|
+
}.map(&:lhs).uniq
|
399
|
+
@internal_dependencies[[shift, next_state]] = nterm_transitions.select {|sh, _| syms.include?(sh.next_sym) }.map {|goto| [self, *goto] }
|
400
|
+
end
|
401
|
+
|
402
|
+
def successor_dependencies(shift, next_state)
|
403
|
+
return @successor_dependencies[[shift, next_state]] if @successor_dependencies[[shift, next_state]]
|
404
|
+
|
405
|
+
@successor_dependencies[[shift, next_state]] =
|
406
|
+
next_state.nterm_transitions
|
407
|
+
.select {|next_shift, _| next_shift.next_sym.nullable }
|
408
|
+
.map {|transition| [next_state, *transition] }
|
409
|
+
end
|
410
|
+
|
411
|
+
def predecessor_dependencies(shift, next_state)
|
412
|
+
state_items = []
|
413
|
+
@kernels.select {|kernel|
|
414
|
+
kernel.next_sym == shift.next_sym && kernel.symbols_after_transition.all?(&:nullable)
|
415
|
+
}.each do |item|
|
416
|
+
queue = predecessors_with_item(item)
|
417
|
+
until queue.empty?
|
418
|
+
st, i = queue.pop
|
419
|
+
if i.position == 0
|
420
|
+
state_items << [st, i]
|
421
|
+
else
|
422
|
+
st.predecessors_with_item(i).each {|v| queue << v }
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
state_items.map {|state, item|
|
428
|
+
sh, next_st = state.nterm_transitions.find {|shi, _| shi.next_sym == item.lhs }
|
429
|
+
[state, sh, next_st]
|
430
|
+
}
|
431
|
+
end
|
145
432
|
end
|
146
433
|
end
|
data/lib/lrama/states/item.rb
CHANGED
@@ -64,6 +64,10 @@ module Lrama
|
|
64
64
|
rhs[position..-1]
|
65
65
|
end
|
66
66
|
|
67
|
+
def symbols_after_transition
|
68
|
+
rhs[position+1..-1]
|
69
|
+
end
|
70
|
+
|
67
71
|
def to_s
|
68
72
|
"#{lhs.id.s_value}: #{display_name}"
|
69
73
|
end
|
@@ -78,6 +82,10 @@ module Lrama
|
|
78
82
|
r = symbols_after_dot.map(&:display_name).join(" ")
|
79
83
|
". #{r} (rule #{rule_id})"
|
80
84
|
end
|
85
|
+
|
86
|
+
def predecessor_item_of?(other_item)
|
87
|
+
rule == other_item.rule && position == other_item.position - 1
|
88
|
+
end
|
81
89
|
end
|
82
90
|
end
|
83
91
|
end
|
data/lib/lrama/states.rb
CHANGED
@@ -41,6 +41,8 @@ module Lrama
|
|
41
41
|
# value is array of [state.id, nterm.token_id].
|
42
42
|
@reads_relation = {}
|
43
43
|
|
44
|
+
# `Read(p, A) =s DR(p, A) ∪ ∪{Read(r, C) | (p, A) reads (r, C)}`
|
45
|
+
#
|
44
46
|
# `@read_sets` is a hash whose
|
45
47
|
# key is [state.id, nterm.token_id],
|
46
48
|
# value is bitmap of term.
|
@@ -62,6 +64,8 @@ module Lrama
|
|
62
64
|
# value is array of [state.id, nterm.token_id].
|
63
65
|
@lookback_relation = {}
|
64
66
|
|
67
|
+
# `Follow(p, A) =s Read(p, A) ∪ ∪{Follow(p', B) | (p, A) includes (p', B)}`
|
68
|
+
#
|
65
69
|
# `@follow_sets` is a hash whose
|
66
70
|
# key is [state.id, rule.id],
|
67
71
|
# value is bitmap of term.
|
@@ -92,6 +96,20 @@ module Lrama
|
|
92
96
|
report_duration(:compute_default_reduction) { compute_default_reduction }
|
93
97
|
end
|
94
98
|
|
99
|
+
def compute_ielr
|
100
|
+
report_duration(:split_states) { split_states }
|
101
|
+
report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
|
102
|
+
report_duration(:compute_reads_relation) { compute_reads_relation }
|
103
|
+
report_duration(:compute_read_sets) { compute_read_sets }
|
104
|
+
report_duration(:compute_includes_relation) { compute_includes_relation }
|
105
|
+
report_duration(:compute_lookback_relation) { compute_lookback_relation }
|
106
|
+
report_duration(:compute_follow_sets) { compute_follow_sets }
|
107
|
+
report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
|
108
|
+
report_duration(:compute_conflicts) { compute_conflicts }
|
109
|
+
|
110
|
+
report_duration(:compute_default_reduction) { compute_default_reduction }
|
111
|
+
end
|
112
|
+
|
95
113
|
def reporter
|
96
114
|
StatesReporter.new(self)
|
97
115
|
end
|
@@ -235,7 +253,7 @@ module Lrama
|
|
235
253
|
# Trace
|
236
254
|
previous = state.kernels.first.previous_sym
|
237
255
|
trace_state do |out|
|
238
|
-
out << sprintf("state_list_append (state = %d, symbol = %d (%s))",
|
256
|
+
out << sprintf("state_list_append (state = %d, symbol = %d (%s))\n",
|
239
257
|
@states.count, previous.number, previous.display_name)
|
240
258
|
end
|
241
259
|
|
@@ -265,7 +283,10 @@ module Lrama
|
|
265
283
|
state.shifts.each do |shift|
|
266
284
|
new_state, created = create_state(shift.next_sym, shift.next_items, states_created)
|
267
285
|
state.set_items_to_state(shift.next_items, new_state)
|
268
|
-
|
286
|
+
if created
|
287
|
+
enqueue_state(states, new_state)
|
288
|
+
new_state.append_predecessor(state)
|
289
|
+
end
|
269
290
|
end
|
270
291
|
end
|
271
292
|
end
|
@@ -524,5 +545,51 @@ module Lrama
|
|
524
545
|
end.first
|
525
546
|
end
|
526
547
|
end
|
548
|
+
|
549
|
+
def split_states
|
550
|
+
@states.each do |state|
|
551
|
+
state.transitions.each do |shift, next_state|
|
552
|
+
compute_state(state, shift, next_state)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
def merge_lookaheads(state, filtered_lookaheads)
|
558
|
+
return if state.kernels.all? {|item| (filtered_lookaheads[item] - state.item_lookahead_set[item]).empty? }
|
559
|
+
|
560
|
+
state.item_lookahead_set = state.item_lookahead_set.merge {|_, v1, v2| v1 | v2 }
|
561
|
+
state.transitions.each do |shift, next_state|
|
562
|
+
next if next_state.lookaheads_recomputed
|
563
|
+
compute_state(state, shift, next_state)
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
def compute_state(state, shift, next_state)
|
568
|
+
filtered_lookaheads = state.propagate_lookaheads(next_state)
|
569
|
+
s = next_state.ielr_isocores.find {|st| st.compatible_lookahead?(filtered_lookaheads) }
|
570
|
+
|
571
|
+
if s.nil?
|
572
|
+
s = next_state.ielr_isocores.last
|
573
|
+
new_state = State.new(@states.count, s.accessing_symbol, s.kernels)
|
574
|
+
new_state.closure = s.closure
|
575
|
+
new_state.compute_shifts_reduces
|
576
|
+
s.transitions.each do |sh, next_state|
|
577
|
+
new_state.set_items_to_state(sh.next_items, next_state)
|
578
|
+
end
|
579
|
+
@states << new_state
|
580
|
+
new_state.lalr_isocore = s
|
581
|
+
s.ielr_isocores << new_state
|
582
|
+
s.ielr_isocores.each do |st|
|
583
|
+
st.ielr_isocores = s.ielr_isocores
|
584
|
+
end
|
585
|
+
new_state.item_lookahead_set = filtered_lookaheads
|
586
|
+
state.update_transition(shift, new_state)
|
587
|
+
elsif(!s.lookaheads_recomputed)
|
588
|
+
s.item_lookahead_set = filtered_lookaheads
|
589
|
+
else
|
590
|
+
state.update_transition(shift, s)
|
591
|
+
merge_lookaheads(s, filtered_lookaheads)
|
592
|
+
end
|
593
|
+
end
|
527
594
|
end
|
528
595
|
end
|
data/lib/lrama/trace_reporter.rb
CHANGED
@@ -1,27 +1,42 @@
|
|
1
|
+
# rbs_inline: enabled
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Lrama
|
4
5
|
class TraceReporter
|
6
|
+
# @rbs (Lrama::Grammar grammar) -> void
|
5
7
|
def initialize(grammar)
|
6
8
|
@grammar = grammar
|
7
9
|
end
|
8
10
|
|
11
|
+
# @rbs (**Hash[Symbol, bool] options) -> void
|
9
12
|
def report(**options)
|
10
13
|
_report(**options)
|
11
14
|
end
|
12
15
|
|
13
16
|
private
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
# @rbs rules: (bool rules, bool actions, bool only_explicit_rules, **untyped _) -> void
|
19
|
+
def _report(rules: false, actions: false, only_explicit_rules: false, **_)
|
20
|
+
report_rules if rules && !only_explicit_rules
|
21
|
+
report_only_explicit_rules if only_explicit_rules
|
17
22
|
report_actions if actions
|
18
23
|
end
|
19
24
|
|
25
|
+
# @rbs () -> void
|
20
26
|
def report_rules
|
21
27
|
puts "Grammar rules:"
|
22
28
|
@grammar.rules.each { |rule| puts rule.display_name }
|
23
29
|
end
|
24
30
|
|
31
|
+
# @rbs () -> void
|
32
|
+
def report_only_explicit_rules
|
33
|
+
puts "Grammar rules:"
|
34
|
+
@grammar.rules.each do |rule|
|
35
|
+
puts rule.display_name_without_action if rule.lhs.first_set.any?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @rbs () -> void
|
25
40
|
def report_actions
|
26
41
|
puts "Grammar rules with actions:"
|
27
42
|
@grammar.rules.each { |rule| puts rule.with_actions }
|
data/lib/lrama/version.rb
CHANGED
data/lrama.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
23
23
|
spec.metadata["source_code_uri"] = spec.homepage
|
24
|
-
spec.metadata["documentation_uri"] =
|
24
|
+
spec.metadata["documentation_uri"] = "https://ruby.github.io/lrama/"
|
25
25
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
|
26
26
|
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
|
27
27
|
|
data/parser.y
CHANGED
@@ -25,7 +25,7 @@ rule
|
|
25
25
|
|
26
26
|
bison_declaration: grammar_declaration
|
27
27
|
| "%expect" INTEGER { @grammar.expect = val[1] }
|
28
|
-
| "%define" variable value
|
28
|
+
| "%define" variable value { @grammar.define[val[1].s_value] = val[2]&.s_value }
|
29
29
|
| "%param" param+
|
30
30
|
| "%lex-param" param+
|
31
31
|
{
|
@@ -428,17 +428,18 @@ end
|
|
428
428
|
|
429
429
|
include Lrama::Report::Duration
|
430
430
|
|
431
|
-
def initialize(text, path, debug = false)
|
431
|
+
def initialize(text, path, debug = false, define = {})
|
432
432
|
@grammar_file = Lrama::Lexer::GrammarFile.new(path, text)
|
433
433
|
@yydebug = debug
|
434
434
|
@rule_counter = Lrama::Grammar::Counter.new(0)
|
435
435
|
@midrule_action_counter = Lrama::Grammar::Counter.new(1)
|
436
|
+
@define = define
|
436
437
|
end
|
437
438
|
|
438
439
|
def parse
|
439
440
|
report_duration(:parse) do
|
440
441
|
@lexer = Lrama::Lexer.new(@grammar_file)
|
441
|
-
@grammar = Lrama::Grammar.new(@rule_counter)
|
442
|
+
@grammar = Lrama::Grammar.new(@rule_counter, @define)
|
442
443
|
@precedence_number = 0
|
443
444
|
reset_precs
|
444
445
|
do_parse
|
data/rbs_collection.lock.yaml
CHANGED
@@ -6,7 +6,7 @@ gems:
|
|
6
6
|
source:
|
7
7
|
type: git
|
8
8
|
name: ruby/gem_rbs_collection
|
9
|
-
revision:
|
9
|
+
revision: 7651e7b92c15bd5b4bc11fd3dd455be0ea571fd0
|
10
10
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
11
11
|
repo_dir: gems
|
12
12
|
- name: erb
|
@@ -26,7 +26,7 @@ gems:
|
|
26
26
|
source:
|
27
27
|
type: git
|
28
28
|
name: ruby/gem_rbs_collection
|
29
|
-
revision:
|
29
|
+
revision: 7651e7b92c15bd5b4bc11fd3dd455be0ea571fd0
|
30
30
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
31
31
|
repo_dir: gems
|
32
32
|
- name: stackprof
|
@@ -34,7 +34,7 @@ gems:
|
|
34
34
|
source:
|
35
35
|
type: git
|
36
36
|
name: ruby/gem_rbs_collection
|
37
|
-
revision:
|
37
|
+
revision: 7651e7b92c15bd5b4bc11fd3dd455be0ea571fd0
|
38
38
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
39
39
|
repo_dir: gems
|
40
40
|
- name: strscan
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Generated from lib/lrama/bitmap.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
module Bitmap
|
5
|
+
# @rbs (Array[Integer] ary) -> Integer
|
6
|
+
def self.from_array: (Array[Integer] ary) -> Integer
|
7
|
+
|
8
|
+
# @rbs (Integer int) -> Array[Integer]
|
9
|
+
def self.to_array: (Integer int) -> Array[Integer]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Generated from lib/lrama/digraph.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
# Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
|
5
|
+
#
|
6
|
+
# @rbs generic X < Object -- Type of a member of `sets`
|
7
|
+
# @rbs generic Y < _Or -- Type of sets assigned to a member of `sets`
|
8
|
+
class Digraph[X < Object, Y < _Or]
|
9
|
+
interface _Or
|
10
|
+
def |: (self) -> self
|
11
|
+
end
|
12
|
+
|
13
|
+
@sets: Array[X]
|
14
|
+
|
15
|
+
@relation: Hash[X, Array[X]]
|
16
|
+
|
17
|
+
@base_function: Hash[X, Y]
|
18
|
+
|
19
|
+
@stack: Array[X]
|
20
|
+
|
21
|
+
@h: Hash[X, (Integer | Float)?]
|
22
|
+
|
23
|
+
@result: Hash[X, Y]
|
24
|
+
|
25
|
+
# @rbs sets: Array[X]
|
26
|
+
# @rbs relation: Hash[X, Array[X]]
|
27
|
+
# @rbs base_function: Hash[X, Y]
|
28
|
+
# @rbs return: void
|
29
|
+
def initialize: (Array[X] sets, Hash[X, Array[X]] relation, Hash[X, Y] base_function) -> void
|
30
|
+
|
31
|
+
# @rbs () -> Hash[X, Y]
|
32
|
+
def compute: () -> Hash[X, Y]
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# @rbs (X x) -> void
|
37
|
+
def traverse: (X x) -> void
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Generated from lib/lrama/grammar/binding.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
class Grammar
|
5
|
+
class Binding
|
6
|
+
@actual_args: Array[Lexer::Token]
|
7
|
+
|
8
|
+
@param_to_arg: Hash[String, Lexer::Token]
|
9
|
+
|
10
|
+
# @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> void
|
11
|
+
def initialize: (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> void
|
12
|
+
|
13
|
+
# @rbs (Lexer::Token sym) -> Lexer::Token
|
14
|
+
def resolve_symbol: (Lexer::Token sym) -> Lexer::Token
|
15
|
+
|
16
|
+
# @rbs (Lexer::Token::InstantiateRule token) -> String
|
17
|
+
def concatenated_args_str: (Lexer::Token::InstantiateRule token) -> String
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# @rbs (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> Hash[String, Lexer::Token]
|
22
|
+
def map_params_to_args: (Array[Lexer::Token] params, Array[Lexer::Token] actual_args) -> Hash[String, Lexer::Token]
|
23
|
+
|
24
|
+
# @rbs (Lexer::Token::InstantiateRule sym) -> Array[Lexer::Token]
|
25
|
+
def resolved_args: (Lexer::Token::InstantiateRule sym) -> Array[Lexer::Token]
|
26
|
+
|
27
|
+
# @rbs (Lexer::Token sym) -> Lexer::Token
|
28
|
+
def param_to_arg: (Lexer::Token sym) -> Lexer::Token
|
29
|
+
|
30
|
+
# @rbs (Lexer::Token::InstantiateRule token) -> Array[String]
|
31
|
+
def token_to_args_s_values: (Lexer::Token::InstantiateRule token) -> Array[String]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Generated from lib/lrama/lexer/grammar_file.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
class Lexer
|
5
|
+
class GrammarFile
|
6
|
+
class Text < String
|
7
|
+
# @rbs () -> String
|
8
|
+
def inspect: () -> String
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader path: String
|
12
|
+
|
13
|
+
attr_reader text: String
|
14
|
+
|
15
|
+
# @rbs (String path, String text) -> void
|
16
|
+
def initialize: (String path, String text) -> void
|
17
|
+
|
18
|
+
# @rbs () -> String
|
19
|
+
def inspect: () -> String
|
20
|
+
|
21
|
+
# @rbs (GrammarFile other) -> bool
|
22
|
+
def ==: (GrammarFile other) -> bool
|
23
|
+
|
24
|
+
# @rbs () -> Array[String]
|
25
|
+
def lines: () -> Array[String]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|