lrama 0.6.10 → 0.6.11

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +5 -1
  3. data/Gemfile +2 -2
  4. data/NEWS.md +65 -30
  5. data/Steepfile +3 -0
  6. data/doc/development/compressed_state_table/main.md +635 -0
  7. data/doc/development/compressed_state_table/parse.output +174 -0
  8. data/doc/development/compressed_state_table/parse.y +22 -0
  9. data/doc/development/compressed_state_table/parser.rb +282 -0
  10. data/lib/lrama/bitmap.rb +1 -1
  11. data/lib/lrama/context.rb +3 -3
  12. data/lib/lrama/counterexamples/derivation.rb +6 -5
  13. data/lib/lrama/counterexamples/example.rb +7 -4
  14. data/lib/lrama/counterexamples/path.rb +4 -0
  15. data/lib/lrama/counterexamples.rb +19 -9
  16. data/lib/lrama/grammar/parameterizing_rule/rhs.rb +1 -1
  17. data/lib/lrama/grammar/rule_builder.rb +1 -1
  18. data/lib/lrama/grammar/symbols/resolver.rb +4 -0
  19. data/lib/lrama/grammar.rb +2 -2
  20. data/lib/lrama/lexer/token/user_code.rb +1 -1
  21. data/lib/lrama/lexer.rb +1 -0
  22. data/lib/lrama/parser.rb +520 -487
  23. data/lib/lrama/state/reduce.rb +2 -3
  24. data/lib/lrama/version.rb +1 -1
  25. data/parser.y +38 -27
  26. data/rbs_collection.lock.yaml +10 -2
  27. data/sig/lrama/counterexamples/derivation.rbs +33 -0
  28. data/sig/lrama/counterexamples/example.rbs +45 -0
  29. data/sig/lrama/counterexamples/path.rbs +21 -0
  30. data/sig/lrama/counterexamples/production_path.rbs +11 -0
  31. data/sig/lrama/counterexamples/start_path.rbs +13 -0
  32. data/sig/lrama/counterexamples/state_item.rbs +10 -0
  33. data/sig/lrama/counterexamples/transition_path.rbs +11 -0
  34. data/sig/lrama/counterexamples/triple.rbs +20 -0
  35. data/sig/lrama/counterexamples.rbs +29 -0
  36. data/sig/lrama/grammar/symbol.rbs +1 -1
  37. data/sig/lrama/grammar/symbols/resolver.rbs +3 -3
  38. data/sig/lrama/grammar.rbs +13 -0
  39. data/sig/lrama/state/reduce_reduce_conflict.rbs +2 -2
  40. data/sig/lrama/state.rbs +79 -0
  41. data/sig/lrama/states.rbs +101 -0
  42. metadata +17 -2
@@ -0,0 +1,174 @@
1
+ Symbol
2
+
3
+ -2 EMPTY
4
+ 0 "end of file"
5
+ 1 error
6
+ 2 "invalid token" (undef)
7
+ 3 LF
8
+ 4 NUM
9
+ 5 '+'
10
+ 6 '*'
11
+ 7 '('
12
+ 8 ')'
13
+ 9 $accept # Start of nonterminal
14
+ 10 program
15
+ 11 expr
16
+
17
+
18
+ Grammar
19
+
20
+ 0 $accept: program "end of file"
21
+
22
+ 1 program: ε
23
+ 2 | expr LF
24
+
25
+ 3 expr: NUM
26
+ 4 | expr '+' expr
27
+ 5 | expr '*' expr
28
+ 6 | '(' expr ')'
29
+
30
+
31
+ State 0
32
+
33
+ 0 $accept: • program "end of file"
34
+ 1 program: ε • ["end of file"]
35
+ 2 | • expr LF
36
+ 3 expr: • NUM
37
+ 4 | • expr '+' expr
38
+ 5 | • expr '*' expr
39
+ 6 | • '(' expr ')'
40
+
41
+ NUM shift, and go to state 1
42
+ '(' shift, and go to state 2
43
+
44
+ $default reduce using rule 1 (program)
45
+
46
+ program go to state 3
47
+ expr go to state 4
48
+
49
+
50
+ State 1
51
+
52
+ 3 expr: NUM •
53
+
54
+ $default reduce using rule 3 (expr)
55
+
56
+
57
+ State 2
58
+
59
+ 3 expr: • NUM
60
+ 4 | • expr '+' expr
61
+ 5 | • expr '*' expr
62
+ 6 | • '(' expr ')'
63
+ 6 | '(' • expr ')'
64
+
65
+ NUM shift, and go to state 1
66
+ '(' shift, and go to state 2
67
+
68
+ expr go to state 5
69
+
70
+
71
+ State 3
72
+
73
+ 0 $accept: program • "end of file"
74
+
75
+ "end of file" shift, and go to state 6
76
+
77
+
78
+ State 4
79
+
80
+ 2 program: expr • LF
81
+ 4 expr: expr • '+' expr
82
+ 5 | expr • '*' expr
83
+
84
+ LF shift, and go to state 7
85
+ '+' shift, and go to state 8
86
+ '*' shift, and go to state 9
87
+
88
+
89
+ State 5
90
+
91
+ 4 expr: expr • '+' expr
92
+ 5 | expr • '*' expr
93
+ 6 | '(' expr • ')'
94
+
95
+ '+' shift, and go to state 8
96
+ '*' shift, and go to state 9
97
+ ')' shift, and go to state 10
98
+
99
+
100
+ State 6
101
+
102
+ 0 $accept: program "end of file" •
103
+
104
+ $default accept
105
+
106
+
107
+ State 7
108
+
109
+ 2 program: expr LF •
110
+
111
+ $default reduce using rule 2 (program)
112
+
113
+
114
+ State 8
115
+
116
+ 3 expr: • NUM
117
+ 4 | • expr '+' expr
118
+ 4 | expr '+' • expr
119
+ 5 | • expr '*' expr
120
+ 6 | • '(' expr ')'
121
+
122
+ NUM shift, and go to state 1
123
+ '(' shift, and go to state 2
124
+
125
+ expr go to state 11
126
+
127
+
128
+ State 9
129
+
130
+ 3 expr: • NUM
131
+ 4 | • expr '+' expr
132
+ 5 | • expr '*' expr
133
+ 5 | expr '*' • expr
134
+ 6 | • '(' expr ')'
135
+
136
+ NUM shift, and go to state 1
137
+ '(' shift, and go to state 2
138
+
139
+ expr go to state 12
140
+
141
+
142
+ State 10
143
+
144
+ 6 expr: '(' expr ')' •
145
+
146
+ $default reduce using rule 6 (expr)
147
+
148
+
149
+ State 11
150
+
151
+ 4 expr: expr • '+' expr
152
+ 4 | expr '+' expr • [LF, '+', ')']
153
+ 5 | expr • '*' expr
154
+
155
+ '*' shift, and go to state 9
156
+
157
+ $default reduce using rule 4 (expr)
158
+
159
+ Conflict between rule 4 and token '+' resolved as reduce (%left '+').
160
+ Conflict between rule 4 and token '*' resolved as shift ('+' < '*').
161
+
162
+
163
+ State 12
164
+
165
+ 4 expr: expr • '+' expr
166
+ 5 | expr • '*' expr
167
+ 5 | expr '*' expr • [LF, '+', '*', ')']
168
+
169
+ $default reduce using rule 5 (expr)
170
+
171
+ Conflict between rule 5 and token '+' resolved as reduce ('+' < '*').
172
+ Conflict between rule 5 and token '*' resolved as reduce (%left '*').
173
+
174
+
@@ -0,0 +1,22 @@
1
+ %union {
2
+ int val;
3
+ }
4
+ %token LF
5
+ %token <val> NUM
6
+ %type <val> expr
7
+ %left '+'
8
+ %left '*'
9
+
10
+ %%
11
+
12
+ program : /* empty */
13
+ | expr LF { printf("=> %d\n", $1); }
14
+ ;
15
+
16
+ expr : NUM
17
+ | expr '+' expr { $$ = $1 + $3; }
18
+ | expr '*' expr { $$ = $1 * $3; }
19
+ | '(' expr ')' { $$ = $2; }
20
+ ;
21
+
22
+ %%
@@ -0,0 +1,282 @@
1
+ class Parser
2
+ YYNTOKENS = 9
3
+ YYLAST = 13
4
+ YYTABLE_NINF = -1
5
+ YYTABLE = [ 5, 6, 7, 9, 8, 9, 11, 12, 8, 9, 1, 10, 0, 2]
6
+ YYCHECK = [ 2, 0, 3, 6, 5, 6, 8, 9, 5, 6, 4, 8, -1, 7]
7
+
8
+ YYPACT_NINF = -4
9
+ YYPACT = [ 6, -4, 6, 1, -1, 3, -4, -4, 6, 6, -4, -3, -4]
10
+ YYPGOTO = [ -4, -4, -2]
11
+
12
+ YYDEFACT = [ 2, 4, 0, 0, 0, 0, 1, 3, 0, 0, 7, 5, 6]
13
+ YYDEFGOTO = [ 0, 3, 4]
14
+
15
+ YYR1 = [ 0, 9, 10, 10, 11, 11, 11, 11]
16
+ YYR2 = [ 0, 2, 0, 2, 1, 3, 3, 3]
17
+
18
+ YYFINAL = 6
19
+
20
+ # Symbols
21
+ SYM_EMPTY = -2
22
+ SYM_EOF = 0 # "end of file"
23
+ SYM_ERROR = 1 # error
24
+ SYM_UNDEF = 2 # Invalid Token
25
+ SYM_LF = 3 # LF
26
+ SYM_NUM = 4 # NUM
27
+ SYM_PLUS = 5 # '+'
28
+ SYM_ASTER = 6 # '*'
29
+ SYM_LPAREN = 7 # '('
30
+ SYM_RPAREN = 8 # ')'
31
+ # Start of nonterminal
32
+ SYM_ACCEPT = 9 # $accept
33
+ SYM_PROGRAM = 10 # program
34
+ SYM_EXPR = 11 # expr
35
+
36
+ def initialize(debug = false)
37
+ @debug = debug
38
+ end
39
+
40
+ def parse(lexer)
41
+ state = 0
42
+ stack = []
43
+ yytoken = SYM_EMPTY
44
+ parser_action = :push_state
45
+ next_state = nil
46
+ rule = nil
47
+
48
+ while true
49
+ _parser_action = parser_action
50
+ parser_action = nil
51
+
52
+ case _parser_action
53
+ when :syntax_error
54
+ debug_print("Entering :syntax_error")
55
+
56
+ return 1
57
+ when :accept
58
+ debug_print("Entering :accept")
59
+
60
+ return 0
61
+ when :push_state
62
+ # Precondition: `state` is set to new state
63
+ debug_print("Entering :push_state")
64
+
65
+ debug_print("Push state #{state}")
66
+ stack.push(state)
67
+ debug_print("Current stack #{stack}")
68
+
69
+ if state == YYFINAL
70
+ parser_action = :accept
71
+ next
72
+ end
73
+
74
+ parser_action = :decide_parser_action
75
+ next
76
+ when :decide_parser_action
77
+ debug_print("Entering :decide_parser_action")
78
+
79
+ offset = yypact[state]
80
+ if offset == YYPACT_NINF
81
+ parser_action = :yydefault
82
+ next
83
+ end
84
+
85
+ # Ensure next token
86
+ if yytoken == SYM_EMPTY
87
+ debug_print("Reading a token")
88
+
89
+ yytoken = lexer.next_token
90
+ end
91
+
92
+ case yytoken
93
+ when SYM_EOF
94
+ debug_print("Now at end of input.")
95
+ when SYM_ERROR
96
+ parser_action = :syntax_error
97
+ next
98
+ else
99
+ debug_print("Next token is #{yytoken}")
100
+ end
101
+
102
+ idx = offset + yytoken
103
+ if idx < 0 || YYLAST < idx
104
+ debug_print("Decide next parser action as :yydefault")
105
+
106
+ parser_action = :yydefault
107
+ next
108
+ end
109
+ if yycheck[idx] != yytoken
110
+ debug_print("Decide next parser action as :yydefault")
111
+
112
+ parser_action = :yydefault
113
+ next
114
+ end
115
+
116
+ action = yytable[idx]
117
+ if action == YYTABLE_NINF
118
+ parser_action = :syntax_error
119
+ next
120
+ end
121
+ if action > 0
122
+ # Shift
123
+ debug_print("Decide next parser action as :yyshift")
124
+
125
+ next_state = action
126
+ parser_action = :yyshift
127
+ next
128
+ else
129
+ # Reduce
130
+ debug_print("Decide next parser action as :yyreduce")
131
+
132
+ rule = -action
133
+ parser_action = :yyreduce
134
+ next
135
+ end
136
+ when :yyshift
137
+ # Precondition: `next_state` is set
138
+ debug_print("Entering :yyshift")
139
+ raise "next_state is not set" unless next_state
140
+
141
+ yytoken = SYM_EMPTY
142
+ state = next_state
143
+ next_state = nil
144
+ parser_action = :push_state
145
+ next
146
+ when :yydefault
147
+ debug_print("Entering :yydefault")
148
+
149
+ rule = yydefact[state]
150
+ if rule == 0
151
+ parser_action = :syntax_error
152
+ next
153
+ end
154
+
155
+ parser_action = :yyreduce
156
+ next
157
+ when :yyreduce
158
+ # Precondition: `rule`, used for reduce, is set
159
+ debug_print("Entering :yyreduce")
160
+ raise "rule is not set" unless rule
161
+
162
+ rhs_length = yyr2[rule]
163
+ lhs_nterm = yyr1[rule]
164
+ lhs_nterm_id = lhs_nterm - YYNTOKENS
165
+
166
+ text = "Execute action for Rule (#{rule}) "
167
+ case rule
168
+ when 1
169
+ text << "$accept: program \"end of file\""
170
+ when 2
171
+ text << "program: ε"
172
+ when 3
173
+ text << "program: expr LF"
174
+ when 4
175
+ text << "expr: NUM"
176
+ when 5
177
+ text << "expr: expr '+' expr"
178
+ when 6
179
+ text << "expr: expr '*' expr"
180
+ when 7
181
+ text << "expr: '(' expr ')'"
182
+ end
183
+ debug_print(text)
184
+
185
+ debug_print("Pop #{rhs_length} elements")
186
+ debug_print("Stack before pop: #{stack}")
187
+ stack.pop(rhs_length)
188
+ debug_print("Stack after pop: #{stack}")
189
+ state = stack[-1]
190
+
191
+ # "Shift" LHS nonterminal
192
+ offset = yypgoto[lhs_nterm_id]
193
+ if offset == YYPACT_NINF
194
+ state = yydefgoto[lhs_nterm_id]
195
+ else
196
+ idx = offset + state
197
+ if idx < 0 || YYLAST < idx
198
+ state = yydefgoto[lhs_nterm_id]
199
+ elsif yycheck[idx] != state
200
+ state = yydefgoto[lhs_nterm_id]
201
+ else
202
+ state = yytable[idx]
203
+ end
204
+ end
205
+
206
+ rule = nil
207
+ parser_action = :push_state
208
+ next
209
+ else
210
+ raise "Unknown parser_action: #{parser_action}"
211
+ end
212
+ end
213
+ end
214
+
215
+ private
216
+
217
+ def debug_print(str)
218
+ if @debug
219
+ $stderr.puts str
220
+ end
221
+ end
222
+
223
+ def yytable
224
+ YYTABLE
225
+ end
226
+
227
+ def yycheck
228
+ YYCHECK
229
+ end
230
+
231
+ def yypact
232
+ YYPACT
233
+ end
234
+
235
+ def yypgoto
236
+ YYPGOTO
237
+ end
238
+
239
+ def yydefact
240
+ YYDEFACT
241
+ end
242
+
243
+ def yydefgoto
244
+ YYDEFGOTO
245
+ end
246
+
247
+ def yyr1
248
+ YYR1
249
+ end
250
+
251
+ def yyr2
252
+ YYR2
253
+ end
254
+ end
255
+
256
+ class Lexer
257
+ def initialize(tokens)
258
+ @tokens = tokens
259
+ @index = 0
260
+ end
261
+
262
+ def next_token
263
+ if @tokens.length > @index
264
+ token = @tokens[@index]
265
+ @index += 1
266
+ return token
267
+ else
268
+ return Parser::SYM_EOF
269
+ end
270
+ end
271
+ end
272
+
273
+ lexer = Lexer.new([
274
+ # 1 + 2 + 3 LF
275
+ Parser::SYM_NUM,
276
+ Parser::SYM_PLUS,
277
+ Parser::SYM_NUM,
278
+ Parser::SYM_PLUS,
279
+ Parser::SYM_NUM,
280
+ Parser::SYM_LF,
281
+ ])
282
+ Parser.new(debug: true).parse(lexer)
data/lib/lrama/bitmap.rb CHANGED
@@ -13,7 +13,7 @@ module Lrama
13
13
  end
14
14
 
15
15
  def self.to_array(int)
16
- a = []
16
+ a = [] #: Array[Integer]
17
17
  i = 0
18
18
 
19
19
  while int > 0 do
data/lib/lrama/context.rb CHANGED
@@ -405,7 +405,7 @@ module Lrama
405
405
  @check = []
406
406
  # Key is froms_and_tos, value is index position
407
407
  pushed = {}
408
- userd_res = {}
408
+ used_res = {}
409
409
  lowzero = 0
410
410
  high = 0
411
411
 
@@ -430,7 +430,7 @@ module Lrama
430
430
  end
431
431
  end
432
432
 
433
- if ok && userd_res[res]
433
+ if ok && used_res[res]
434
434
  ok = false
435
435
  end
436
436
 
@@ -458,7 +458,7 @@ module Lrama
458
458
 
459
459
  @base[state_id] = res
460
460
  pushed[froms_and_tos] = res
461
- userd_res[res] = true
461
+ used_res[res] = true
462
462
  end
463
463
 
464
464
  @yylast = high
@@ -18,7 +18,7 @@ module Lrama
18
18
  alias :inspect :to_s
19
19
 
20
20
  def render_strings_for_report
21
- result = []
21
+ result = [] #: Array[String]
22
22
  _render_for_report(self, 0, result, 0)
23
23
  result.map(&:rstrip)
24
24
  end
@@ -44,18 +44,19 @@ module Lrama
44
44
  str << "#{item.next_sym.display_name}"
45
45
  length = _render_for_report(derivation.left, len, strings, index + 1)
46
46
  # I want String#ljust!
47
- str << " " * (length - str.length)
47
+ str << " " * (length - str.length) if length > str.length
48
48
  else
49
49
  str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} "
50
50
  return str.length
51
51
  end
52
52
 
53
53
  if derivation.right&.left
54
- length = _render_for_report(derivation.right.left, str.length, strings, index + 1)
55
- str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
54
+ left = derivation.right&.left #: Derivation
55
+ length = _render_for_report(left, str.length, strings, index + 1)
56
+ str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore
56
57
  str << " " * (length - str.length) if length > str.length
57
58
  elsif item.next_next_sym
58
- str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
59
+ str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} " # steep:ignore
59
60
  end
60
61
 
61
62
  return str.length
@@ -38,9 +38,10 @@ module Lrama
38
38
  private
39
39
 
40
40
  def _derivations(paths)
41
- derivation = nil
41
+ derivation = nil #: Derivation
42
42
  current = :production
43
- lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
43
+ last_path = paths.last #: Path
44
+ lookahead_sym = last_path.to.item.end_of_rule? ? @conflict_symbol : nil
44
45
 
45
46
  paths.reverse_each do |path|
46
47
  item = path.to.item
@@ -57,12 +58,14 @@ module Lrama
57
58
  when ProductionPath
58
59
  derivation = Derivation.new(item, derivation)
59
60
  current = :production
61
+ else
62
+ raise "Unexpected. #{path}"
60
63
  end
61
64
 
62
65
  if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
63
66
  state_item = @counterexamples.transitions[[path.to, item.next_sym]]
64
67
  derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
65
- derivation.right = derivation2
68
+ derivation.right = derivation2 # steep:ignore
66
69
  lookahead_sym = nil
67
70
  end
68
71
 
@@ -89,7 +92,7 @@ module Lrama
89
92
  end
90
93
 
91
94
  def find_derivation_for_symbol(state_item, sym)
92
- queue = []
95
+ queue = [] #: Array[Array[StateItem]]
93
96
  queue << [state_item]
94
97
 
95
98
  while (sis = queue.shift)
@@ -20,6 +20,10 @@ module Lrama
20
20
  "#<Path(#{type})>"
21
21
  end
22
22
  alias :inspect :to_s
23
+
24
+ def type
25
+ raise NotImplementedError
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -32,8 +32,10 @@ module Lrama
32
32
  conflict_state.conflicts.flat_map do |conflict|
33
33
  case conflict.type
34
34
  when :shift_reduce
35
+ # @type var conflict: State::ShiftReduceConflict
35
36
  shift_reduce_example(conflict_state, conflict)
36
37
  when :reduce_reduce
38
+ # @type var conflict: State::ReduceReduceConflict
37
39
  reduce_reduce_examples(conflict_state, conflict)
38
40
  end
39
41
  end.compact
@@ -48,7 +50,7 @@ module Lrama
48
50
  @reverse_transitions = {}
49
51
 
50
52
  @states.states.each do |src_state|
51
- trans = {}
53
+ trans = {} #: Hash[Grammar::Symbol, State]
52
54
 
53
55
  src_state.transitions.each do |shift, next_state|
54
56
  trans[shift.next_sym] = next_state
@@ -66,6 +68,7 @@ module Lrama
66
68
 
67
69
  @transitions[[src_state_item, sym]] = dest_state_item
68
70
 
71
+ # @type var key: [StateItem, Grammar::Symbol]
69
72
  key = [dest_state_item, sym]
70
73
  @reverse_transitions[key] ||= Set.new
71
74
  @reverse_transitions[key] << src_state_item
@@ -82,7 +85,7 @@ module Lrama
82
85
 
83
86
  @states.states.each do |state|
84
87
  # LHS => Set(Item)
85
- h = {}
88
+ h = {} #: Hash[Grammar::Symbol, Set[States::Item]]
86
89
 
87
90
  state.closure.each do |item|
88
91
  sym = item.lhs
@@ -97,6 +100,7 @@ module Lrama
97
100
 
98
101
  sym = item.next_sym
99
102
  state_item = StateItem.new(state, item)
103
+ # @type var key: [State, Grammar::Symbol]
100
104
  key = [state, sym]
101
105
 
102
106
  @productions[state_item] = h[sym]
@@ -109,6 +113,7 @@ module Lrama
109
113
 
110
114
  def shift_reduce_example(conflict_state, conflict)
111
115
  conflict_symbol = conflict.symbols.first
116
+ # @type var shift_conflict_item: ::Lrama::States::Item
112
117
  shift_conflict_item = conflict_state.items.find { |item| item.next_sym == conflict_symbol }
113
118
  path2 = shortest_path(conflict_state, conflict.reduce.item, conflict_symbol)
114
119
  path1 = find_shift_conflict_shortest_path(path2, conflict_state, shift_conflict_item)
@@ -153,12 +158,14 @@ module Lrama
153
158
  prev_state_item = prev_path&.to
154
159
 
155
160
  if target_state_item == state_item || target_state_item.item.start_item?
156
- result.concat(reversed_reduce_path[_j..-1].map(&:to))
161
+ result.concat(
162
+ reversed_reduce_path[_j..-1] #: Array[StartPath|TransitionPath|ProductionPath]
163
+ .map(&:to))
157
164
  break
158
165
  end
159
166
 
160
167
  if target_state_item.item.beginning_of_rule?
161
- queue = []
168
+ queue = [] #: Array[Array[StateItem]]
162
169
  queue << [target_state_item]
163
170
 
164
171
  # Find reverse production
@@ -174,15 +181,17 @@ module Lrama
174
181
  end
175
182
 
176
183
  if si.item.beginning_of_rule?
184
+ # @type var key: [State, Grammar::Symbol]
177
185
  key = [si.state, si.item.lhs]
178
186
  @reverse_productions[key].each do |item|
179
187
  state_item = StateItem.new(si.state, item)
180
188
  queue << (sis + [state_item])
181
189
  end
182
190
  else
191
+ # @type var key: [StateItem, Grammar::Symbol]
183
192
  key = [si, si.item.previous_sym]
184
193
  @reverse_transitions[key].each do |prev_target_state_item|
185
- next if prev_target_state_item.state != prev_state_item.state
194
+ next if prev_target_state_item.state != prev_state_item&.state
186
195
  sis.shift
187
196
  result.concat(sis)
188
197
  result << prev_target_state_item
@@ -195,9 +204,10 @@ module Lrama
195
204
  end
196
205
  else
197
206
  # Find reverse transition
207
+ # @type var key: [StateItem, Grammar::Symbol]
198
208
  key = [target_state_item, target_state_item.item.previous_sym]
199
209
  @reverse_transitions[key].each do |prev_target_state_item|
200
- next if prev_target_state_item.state != prev_state_item.state
210
+ next if prev_target_state_item.state != prev_state_item&.state
201
211
  result << prev_target_state_item
202
212
  target_state_item = prev_target_state_item
203
213
  i = j
@@ -224,9 +234,9 @@ module Lrama
224
234
 
225
235
  def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
226
236
  # queue: is an array of [Triple, [Path]]
227
- queue = []
228
- visited = {}
229
- start_state = @states.states.first
237
+ queue = [] #: Array[[Triple, Array[StartPath|TransitionPath|ProductionPath]]]
238
+ visited = {} #: Hash[Triple, true]
239
+ start_state = @states.states.first #: Lrama::State
230
240
  raise "BUG: Start state should be just one kernel." if start_state.kernels.count != 1
231
241
 
232
242
  start = Triple.new(start_state, start_state.kernels.first, Set.new([@states.eof_symbol]))