lrama 0.7.0 → 0.7.1

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 (260) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/codespell.yaml +1 -1
  4. data/.github/workflows/gh-pages.yml +5 -6
  5. data/.github/workflows/test.yaml +25 -14
  6. data/Gemfile +4 -3
  7. data/NEWS.md +370 -35
  8. data/README.md +7 -88
  9. data/Rakefile +3 -2
  10. data/Steepfile +11 -5
  11. data/doc/Index.md +1 -1
  12. data/doc/development/compressed_state_table/parser.rb +2 -0
  13. data/doc/development/profiling.md +44 -0
  14. data/exe/lrama +1 -1
  15. data/lib/lrama/bitmap.rb +18 -5
  16. data/lib/lrama/command.rb +95 -43
  17. data/lib/lrama/context.rb +22 -24
  18. data/lib/lrama/counterexamples/derivation.rb +14 -4
  19. data/lib/lrama/counterexamples/example.rb +47 -22
  20. data/lib/lrama/counterexamples/node.rb +30 -0
  21. data/lib/lrama/counterexamples/path.rb +12 -14
  22. data/lib/lrama/counterexamples/state_item.rb +24 -1
  23. data/lib/lrama/counterexamples/triple.rb +27 -9
  24. data/lib/lrama/counterexamples.rb +216 -88
  25. data/lib/lrama/diagram.rb +77 -0
  26. data/lib/lrama/digraph.rb +28 -7
  27. data/lib/lrama/erb.rb +29 -0
  28. data/lib/lrama/grammar/auxiliary.rb +6 -1
  29. data/lib/lrama/grammar/binding.rb +37 -25
  30. data/lib/lrama/grammar/code/destructor_code.rb +11 -0
  31. data/lib/lrama/grammar/code/initial_action_code.rb +3 -0
  32. data/lib/lrama/grammar/code/no_reference_code.rb +3 -0
  33. data/lib/lrama/grammar/code/printer_code.rb +11 -0
  34. data/lib/lrama/grammar/code/rule_action.rb +17 -0
  35. data/lib/lrama/grammar/code.rb +16 -1
  36. data/lib/lrama/grammar/counter.rb +10 -0
  37. data/lib/lrama/grammar/destructor.rb +14 -1
  38. data/lib/lrama/grammar/error_token.rb +14 -1
  39. data/lib/lrama/grammar/inline/resolver.rb +80 -0
  40. data/lib/lrama/grammar/inline.rb +3 -0
  41. data/lib/lrama/grammar/{parameterizing_rule → parameterized}/resolver.rb +19 -8
  42. data/lib/lrama/grammar/{parameterizing_rule → parameterized}/rhs.rb +7 -2
  43. data/lib/lrama/grammar/parameterized/rule.rb +36 -0
  44. data/lib/lrama/grammar/parameterized.rb +5 -0
  45. data/lib/lrama/grammar/percent_code.rb +12 -1
  46. data/lib/lrama/grammar/precedence.rb +43 -1
  47. data/lib/lrama/grammar/printer.rb +9 -0
  48. data/lib/lrama/grammar/reference.rb +13 -0
  49. data/lib/lrama/grammar/rule.rb +61 -1
  50. data/lib/lrama/grammar/rule_builder.rb +84 -69
  51. data/lib/lrama/grammar/stdlib.y +68 -48
  52. data/lib/lrama/grammar/symbol.rb +63 -19
  53. data/lib/lrama/grammar/symbols/resolver.rb +64 -3
  54. data/lib/lrama/grammar/type.rb +13 -1
  55. data/lib/lrama/grammar/union.rb +12 -1
  56. data/lib/lrama/grammar.rb +231 -35
  57. data/lib/lrama/lexer/location.rb +25 -8
  58. data/lib/lrama/lexer/token/base.rb +73 -0
  59. data/lib/lrama/lexer/token/char.rb +15 -2
  60. data/lib/lrama/lexer/token/empty.rb +14 -0
  61. data/lib/lrama/lexer/token/ident.rb +2 -2
  62. data/lib/lrama/lexer/token/instantiate_rule.rb +4 -4
  63. data/lib/lrama/lexer/token/int.rb +14 -0
  64. data/lib/lrama/lexer/token/str.rb +11 -0
  65. data/lib/lrama/lexer/token/tag.rb +2 -2
  66. data/lib/lrama/lexer/token/token.rb +11 -0
  67. data/lib/lrama/lexer/token/user_code.rb +63 -37
  68. data/lib/lrama/lexer/token.rb +6 -56
  69. data/lib/lrama/lexer.rb +51 -23
  70. data/lib/lrama/logger.rb +12 -2
  71. data/lib/lrama/option_parser.rb +63 -9
  72. data/lib/lrama/options.rb +25 -7
  73. data/lib/lrama/output.rb +4 -11
  74. data/lib/lrama/parser.rb +854 -723
  75. data/lib/lrama/reporter/conflicts.rb +44 -0
  76. data/lib/lrama/reporter/grammar.rb +39 -0
  77. data/lib/lrama/reporter/precedences.rb +54 -0
  78. data/lib/lrama/reporter/profile/call_stack.rb +45 -0
  79. data/lib/lrama/reporter/profile/memory.rb +44 -0
  80. data/lib/lrama/reporter/profile.rb +4 -0
  81. data/lib/lrama/reporter/rules.rb +43 -0
  82. data/lib/lrama/reporter/states.rb +387 -0
  83. data/lib/lrama/reporter/terms.rb +44 -0
  84. data/lib/lrama/reporter.rb +39 -0
  85. data/lib/lrama/state/action/goto.rb +33 -0
  86. data/lib/lrama/state/action/reduce.rb +71 -0
  87. data/lib/lrama/state/action/shift.rb +39 -0
  88. data/lib/lrama/state/action.rb +5 -0
  89. data/lib/lrama/state/inadequacy_annotation.rb +140 -0
  90. data/lib/lrama/{states → state}/item.rb +33 -4
  91. data/lib/lrama/state/reduce_reduce_conflict.rb +14 -1
  92. data/lib/lrama/state/resolved_conflict.rb +38 -4
  93. data/lib/lrama/state/shift_reduce_conflict.rb +14 -1
  94. data/lib/lrama/state.rb +301 -200
  95. data/lib/lrama/states.rb +447 -175
  96. data/lib/lrama/tracer/actions.rb +22 -0
  97. data/lib/lrama/tracer/closure.rb +30 -0
  98. data/lib/lrama/tracer/duration.rb +38 -0
  99. data/lib/lrama/tracer/only_explicit_rules.rb +24 -0
  100. data/lib/lrama/tracer/rules.rb +23 -0
  101. data/lib/lrama/tracer/state.rb +33 -0
  102. data/lib/lrama/tracer.rb +51 -0
  103. data/lib/lrama/version.rb +2 -1
  104. data/lib/lrama/warnings/conflicts.rb +27 -0
  105. data/lib/lrama/warnings/implicit_empty.rb +29 -0
  106. data/lib/lrama/warnings/name_conflicts.rb +63 -0
  107. data/lib/lrama/warnings/redefined_rules.rb +23 -0
  108. data/lib/lrama/warnings/required.rb +23 -0
  109. data/lib/lrama/warnings/useless_precedence.rb +25 -0
  110. data/lib/lrama/warnings.rb +33 -0
  111. data/lib/lrama.rb +5 -5
  112. data/parser.y +495 -404
  113. data/rbs_collection.lock.yaml +27 -3
  114. data/rbs_collection.yaml +2 -0
  115. data/sig/generated/lrama/bitmap.rbs +12 -4
  116. data/sig/generated/lrama/counterexamples/derivation.rbs +36 -0
  117. data/sig/generated/lrama/counterexamples/example.rbs +58 -0
  118. data/sig/generated/lrama/counterexamples/node.rbs +18 -0
  119. data/sig/generated/lrama/counterexamples/path.rbs +23 -0
  120. data/sig/generated/lrama/counterexamples/state_item.rbs +19 -0
  121. data/sig/generated/lrama/counterexamples/triple.rbs +32 -0
  122. data/sig/generated/lrama/counterexamples.rbs +98 -0
  123. data/sig/generated/lrama/diagram.rbs +34 -0
  124. data/sig/generated/lrama/digraph.rbs +26 -6
  125. data/sig/generated/lrama/erb.rbs +14 -0
  126. data/sig/generated/lrama/grammar/auxiliary.rbs +16 -0
  127. data/sig/generated/lrama/grammar/binding.rbs +18 -12
  128. data/sig/generated/lrama/grammar/code/destructor_code.rbs +26 -0
  129. data/sig/{lrama → generated/lrama}/grammar/code/initial_action_code.rbs +6 -0
  130. data/sig/{lrama → generated/lrama}/grammar/code/no_reference_code.rbs +6 -0
  131. data/sig/generated/lrama/grammar/code/printer_code.rbs +26 -0
  132. data/sig/generated/lrama/grammar/code/rule_action.rbs +63 -0
  133. data/sig/generated/lrama/grammar/code.rbs +38 -0
  134. data/sig/{lrama → generated/lrama}/grammar/counter.rbs +4 -0
  135. data/sig/generated/lrama/grammar/destructor.rbs +19 -0
  136. data/sig/generated/lrama/grammar/error_token.rbs +19 -0
  137. data/sig/generated/lrama/grammar/inline/resolver.rbs +26 -0
  138. data/sig/generated/lrama/grammar/parameterized/resolver.rbs +42 -0
  139. data/sig/generated/lrama/grammar/parameterized/rhs.rbs +21 -0
  140. data/sig/generated/lrama/grammar/parameterized/rule.rbs +28 -0
  141. data/sig/{lrama → generated/lrama}/grammar/percent_code.rbs +8 -0
  142. data/sig/generated/lrama/grammar/precedence.rbs +45 -0
  143. data/sig/{lrama/grammar/error_token.rbs → generated/lrama/grammar/printer.rbs} +8 -3
  144. data/sig/generated/lrama/grammar/reference.rbs +31 -0
  145. data/sig/generated/lrama/grammar/rule.rbs +83 -0
  146. data/sig/generated/lrama/grammar/rule_builder.rbs +91 -0
  147. data/sig/generated/lrama/grammar/symbol.rbs +89 -0
  148. data/sig/generated/lrama/grammar/symbols/resolver.rbs +131 -0
  149. data/sig/generated/lrama/grammar/type.rbs +21 -0
  150. data/sig/generated/lrama/grammar/union.rbs +17 -0
  151. data/sig/generated/lrama/grammar.rbs +289 -0
  152. data/sig/generated/lrama/lexer/location.rbs +12 -3
  153. data/sig/generated/lrama/lexer/token/base.rbs +53 -0
  154. data/sig/generated/lrama/lexer/token/char.rbs +9 -2
  155. data/sig/generated/lrama/lexer/token/empty.rbs +11 -0
  156. data/sig/generated/lrama/lexer/token/ident.rbs +2 -2
  157. data/sig/generated/lrama/lexer/token/instantiate_rule.rbs +5 -5
  158. data/sig/generated/lrama/lexer/token/int.rbs +13 -0
  159. data/sig/generated/lrama/lexer/token/str.rbs +10 -0
  160. data/sig/generated/lrama/lexer/token/tag.rbs +2 -2
  161. data/sig/generated/lrama/lexer/token/token.rbs +10 -0
  162. data/sig/generated/lrama/lexer/token/user_code.rbs +2 -2
  163. data/sig/generated/lrama/lexer/token.rbs +1 -39
  164. data/sig/generated/lrama/lexer.rbs +54 -0
  165. data/sig/generated/lrama/logger.rbs +6 -0
  166. data/sig/generated/lrama/option_parser.rbs +52 -0
  167. data/sig/{lrama → generated/lrama}/options.rbs +27 -3
  168. data/sig/generated/lrama/reporter/conflicts.rbs +18 -0
  169. data/sig/generated/lrama/reporter/grammar.rbs +13 -0
  170. data/sig/generated/lrama/reporter/precedences.rbs +15 -0
  171. data/sig/generated/lrama/reporter/profile/call_stack.rbs +19 -0
  172. data/sig/generated/lrama/reporter/profile/memory.rbs +19 -0
  173. data/sig/generated/lrama/reporter/rules.rbs +13 -0
  174. data/sig/generated/lrama/reporter/states.rbs +69 -0
  175. data/sig/generated/lrama/reporter/terms.rbs +13 -0
  176. data/sig/generated/lrama/reporter.rbs +13 -0
  177. data/sig/generated/lrama/state/action/goto.rbs +28 -0
  178. data/sig/generated/lrama/state/action/reduce.rbs +49 -0
  179. data/sig/generated/lrama/state/action/shift.rbs +33 -0
  180. data/sig/generated/lrama/state/inadequacy_annotation.rbs +45 -0
  181. data/sig/generated/lrama/state/item.rbs +75 -0
  182. data/sig/generated/lrama/state/reduce_reduce_conflict.rbs +19 -0
  183. data/sig/generated/lrama/state/resolved_conflict.rbs +38 -0
  184. data/sig/generated/lrama/state/shift_reduce_conflict.rbs +19 -0
  185. data/sig/generated/lrama/state.rbs +231 -0
  186. data/sig/generated/lrama/states.rbs +215 -0
  187. data/sig/generated/lrama/tracer/actions.rbs +13 -0
  188. data/sig/generated/lrama/tracer/closure.rbs +13 -0
  189. data/sig/generated/lrama/tracer/duration.rbs +18 -0
  190. data/sig/generated/lrama/tracer/only_explicit_rules.rbs +13 -0
  191. data/sig/generated/lrama/tracer/rules.rbs +13 -0
  192. data/sig/generated/lrama/tracer/state.rbs +16 -0
  193. data/sig/generated/lrama/tracer.rbs +23 -0
  194. data/sig/generated/lrama/version.rbs +5 -0
  195. data/sig/generated/lrama/warnings/conflicts.rbs +13 -0
  196. data/sig/generated/lrama/warnings/implicit_empty.rbs +17 -0
  197. data/sig/generated/lrama/warnings/name_conflicts.rbs +31 -0
  198. data/sig/generated/lrama/warnings/redefined_rules.rbs +13 -0
  199. data/sig/generated/lrama/warnings/required.rbs +13 -0
  200. data/sig/generated/lrama/warnings/useless_precedence.rbs +13 -0
  201. data/sig/generated/lrama/warnings.rbs +11 -0
  202. data/sig/railroad_diagrams/railroad_diagrams.rbs +16 -0
  203. data/template/bison/_yacc.h +8 -0
  204. data/template/diagram/diagram.html +102 -0
  205. metadata +126 -66
  206. data/lib/lrama/counterexamples/production_path.rb +0 -19
  207. data/lib/lrama/counterexamples/start_path.rb +0 -23
  208. data/lib/lrama/counterexamples/transition_path.rb +0 -19
  209. data/lib/lrama/diagnostics.rb +0 -36
  210. data/lib/lrama/grammar/parameterizing_rule/rule.rb +0 -24
  211. data/lib/lrama/grammar/parameterizing_rule.rb +0 -5
  212. data/lib/lrama/grammar_validator.rb +0 -37
  213. data/lib/lrama/report/duration.rb +0 -27
  214. data/lib/lrama/report/profile.rb +0 -16
  215. data/lib/lrama/report.rb +0 -4
  216. data/lib/lrama/state/reduce.rb +0 -37
  217. data/lib/lrama/state/shift.rb +0 -15
  218. data/lib/lrama/states_reporter.rb +0 -362
  219. data/lib/lrama/trace_reporter.rb +0 -45
  220. data/sig/generated/lrama/trace_reporter.rbs +0 -25
  221. data/sig/lrama/counterexamples/derivation.rbs +0 -33
  222. data/sig/lrama/counterexamples/example.rbs +0 -45
  223. data/sig/lrama/counterexamples/path.rbs +0 -21
  224. data/sig/lrama/counterexamples/production_path.rbs +0 -11
  225. data/sig/lrama/counterexamples/start_path.rbs +0 -13
  226. data/sig/lrama/counterexamples/state_item.rbs +0 -10
  227. data/sig/lrama/counterexamples/transition_path.rbs +0 -11
  228. data/sig/lrama/counterexamples/triple.rbs +0 -20
  229. data/sig/lrama/counterexamples.rbs +0 -29
  230. data/sig/lrama/grammar/auxiliary.rbs +0 -10
  231. data/sig/lrama/grammar/code/destructor_code.rbs +0 -14
  232. data/sig/lrama/grammar/code/printer_code.rbs +0 -14
  233. data/sig/lrama/grammar/code/rule_action.rbs +0 -19
  234. data/sig/lrama/grammar/code.rbs +0 -24
  235. data/sig/lrama/grammar/destructor.rbs +0 -13
  236. data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +0 -24
  237. data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +0 -14
  238. data/sig/lrama/grammar/parameterizing_rule/rule.rbs +0 -16
  239. data/sig/lrama/grammar/parameterizing_rule.rbs +0 -6
  240. data/sig/lrama/grammar/precedence.rbs +0 -13
  241. data/sig/lrama/grammar/printer.rbs +0 -13
  242. data/sig/lrama/grammar/reference.rbs +0 -22
  243. data/sig/lrama/grammar/rule.rbs +0 -45
  244. data/sig/lrama/grammar/rule_builder.rbs +0 -47
  245. data/sig/lrama/grammar/symbol.rbs +0 -38
  246. data/sig/lrama/grammar/symbols/resolver.rbs +0 -60
  247. data/sig/lrama/grammar/type.rbs +0 -11
  248. data/sig/lrama/grammar/union.rbs +0 -12
  249. data/sig/lrama/grammar.rbs +0 -108
  250. data/sig/lrama/report/duration.rbs +0 -11
  251. data/sig/lrama/report/profile.rbs +0 -7
  252. data/sig/lrama/state/reduce.rbs +0 -20
  253. data/sig/lrama/state/reduce_reduce_conflict.rbs +0 -13
  254. data/sig/lrama/state/resolved_conflict.rbs +0 -14
  255. data/sig/lrama/state/shift.rbs +0 -14
  256. data/sig/lrama/state/shift_reduce_conflict.rbs +0 -13
  257. data/sig/lrama/state.rbs +0 -79
  258. data/sig/lrama/states/item.rbs +0 -30
  259. data/sig/lrama/states.rbs +0 -101
  260. data/sig/lrama/warning.rbs +0 -16
data/lib/lrama/states.rb CHANGED
@@ -1,8 +1,9 @@
1
+ # rbs_inline: enabled
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "forwardable"
4
- require_relative "report/duration"
5
- require_relative "states/item"
5
+ require_relative "tracer/duration"
6
+ require_relative "state/item"
6
7
 
7
8
  module Lrama
8
9
  # States is passed to a template file
@@ -10,17 +11,42 @@ module Lrama
10
11
  # "Efficient Computation of LALR(1) Look-Ahead Sets"
11
12
  # https://dl.acm.org/doi/pdf/10.1145/69622.357187
12
13
  class States
14
+ # TODO: rbs-inline 0.11.0 doesn't support instance variables.
15
+ # Move these type declarations above instance variable definitions, once it's supported.
16
+ # see: https://github.com/soutaro/rbs-inline/pull/149
17
+ #
18
+ # @rbs!
19
+ # type state_id = Integer
20
+ # type rule_id = Integer
21
+ #
22
+ # include Grammar::_DelegatedMethods
23
+ #
24
+ # @grammar: Grammar
25
+ # @tracer: Tracer
26
+ # @states: Array[State]
27
+ # @direct_read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
28
+ # @reads_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
29
+ # @read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
30
+ # @includes_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
31
+ # @lookback_relation: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
32
+ # @follow_sets: Hash[State::Action::Goto, Bitmap::bitmap]
33
+ # @la: Hash[state_id, Hash[rule_id, Bitmap::bitmap]]
34
+
13
35
  extend Forwardable
14
- include Lrama::Report::Duration
36
+ include Lrama::Tracer::Duration
15
37
 
16
- def_delegators "@grammar", :symbols, :terms, :nterms, :rules,
17
- :accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!
38
+ def_delegators "@grammar", :symbols, :terms, :nterms, :rules, :precedences,
39
+ :accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!, :ielr_defined?
18
40
 
19
- attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
41
+ attr_reader :states #: Array[State]
42
+ attr_reader :reads_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
43
+ attr_reader :includes_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
44
+ attr_reader :lookback_relation #: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
20
45
 
21
- def initialize(grammar, trace_state: false)
46
+ # @rbs (Grammar grammar, Tracer tracer) -> void
47
+ def initialize(grammar, tracer)
22
48
  @grammar = grammar
23
- @trace_state = trace_state
49
+ @tracer = tracer
24
50
 
25
51
  @states = []
26
52
 
@@ -28,7 +54,7 @@ module Lrama
28
54
  # where p is state, A is nterm, t is term.
29
55
  #
30
56
  # `@direct_read_sets` is a hash whose
31
- # key is [state.id, nterm.token_id],
57
+ # key is goto,
32
58
  # value is bitmap of term.
33
59
  @direct_read_sets = {}
34
60
 
@@ -37,14 +63,14 @@ module Lrama
37
63
  # where p, r are state, A, C are nterm.
38
64
  #
39
65
  # `@reads_relation` is a hash whose
40
- # key is [state.id, nterm.token_id],
41
- # value is array of [state.id, nterm.token_id].
66
+ # key is goto,
67
+ # value is array of goto.
42
68
  @reads_relation = {}
43
69
 
44
70
  # `Read(p, A) =s DR(p, A) ∪ ∪{Read(r, C) | (p, A) reads (r, C)}`
45
71
  #
46
72
  # `@read_sets` is a hash whose
47
- # key is [state.id, nterm.token_id],
73
+ # key is goto,
48
74
  # value is bitmap of term.
49
75
  @read_sets = {}
50
76
 
@@ -52,112 +78,163 @@ module Lrama
52
78
  # where p, p' are state, A, B are nterm, β, γ is sequence of symbol.
53
79
  #
54
80
  # `@includes_relation` is a hash whose
55
- # key is [state.id, nterm.token_id],
56
- # value is array of [state.id, nterm.token_id].
81
+ # key is goto,
82
+ # value is array of goto.
57
83
  @includes_relation = {}
58
84
 
59
85
  # `(q, A -> ω) lookback (p, A) iff p -(ω)-> q`
60
86
  # where p, q are state, A -> ω is rule, A is nterm, ω is sequence of symbol.
61
87
  #
62
- # `@lookback_relation` is a hash whose
63
- # key is [state.id, rule.id],
64
- # value is array of [state.id, nterm.token_id].
88
+ # `@lookback_relation` is a two-stage hash whose
89
+ # first key is state_id,
90
+ # second key is rule_id,
91
+ # value is array of goto.
65
92
  @lookback_relation = {}
66
93
 
67
94
  # `Follow(p, A) =s Read(p, A) ∪ ∪{Follow(p', B) | (p, A) includes (p', B)}`
68
95
  #
69
96
  # `@follow_sets` is a hash whose
70
- # key is [state.id, rule.id],
97
+ # key is goto,
71
98
  # value is bitmap of term.
72
99
  @follow_sets = {}
73
100
 
74
101
  # `LA(q, A -> ω) = ∪{Follow(p, A) | (q, A -> ω) lookback (p, A)`
75
102
  #
76
- # `@la` is a hash whose
77
- # key is [state.id, rule.id],
103
+ # `@la` is a two-stage hash whose
104
+ # first key is state_id,
105
+ # second key is rule_id,
78
106
  # value is bitmap of term.
79
107
  @la = {}
80
108
  end
81
109
 
110
+ # @rbs () -> void
82
111
  def compute
83
- # Look Ahead Sets
84
112
  report_duration(:compute_lr0_states) { compute_lr0_states }
85
- report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
86
- report_duration(:compute_reads_relation) { compute_reads_relation }
87
- report_duration(:compute_read_sets) { compute_read_sets }
88
- report_duration(:compute_includes_relation) { compute_includes_relation }
89
- report_duration(:compute_lookback_relation) { compute_lookback_relation }
90
- report_duration(:compute_follow_sets) { compute_follow_sets }
113
+
114
+ # Look Ahead Sets
91
115
  report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
92
116
 
93
117
  # Conflicts
94
- report_duration(:compute_conflicts) { compute_conflicts }
118
+ report_duration(:compute_conflicts) { compute_conflicts(:lalr) }
95
119
 
96
120
  report_duration(:compute_default_reduction) { compute_default_reduction }
97
121
  end
98
122
 
123
+ # @rbs () -> void
99
124
  def compute_ielr
125
+ # Preparation
126
+ report_duration(:clear_conflicts) { clear_conflicts }
127
+ # Phase 1
128
+ report_duration(:compute_predecessors) { compute_predecessors }
129
+ report_duration(:compute_follow_kernel_items) { compute_follow_kernel_items }
130
+ report_duration(:compute_always_follows) { compute_always_follows }
131
+ report_duration(:compute_goto_follows) { compute_goto_follows }
132
+ # Phase 2
133
+ report_duration(:compute_inadequacy_annotations) { compute_inadequacy_annotations }
134
+ # Phase 3
100
135
  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 }
136
+ # Phase 4
137
+ report_duration(:clear_look_ahead_sets) { clear_look_ahead_sets }
107
138
  report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
108
- report_duration(:compute_conflicts) { compute_conflicts }
109
-
139
+ # Phase 5
140
+ report_duration(:compute_conflicts) { compute_conflicts(:ielr) }
110
141
  report_duration(:compute_default_reduction) { compute_default_reduction }
111
142
  end
112
143
 
113
- def reporter
114
- StatesReporter.new(self)
115
- end
116
-
144
+ # @rbs () -> Integer
117
145
  def states_count
118
146
  @states.count
119
147
  end
120
148
 
149
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
121
150
  def direct_read_sets
122
- @direct_read_sets.transform_values do |v|
151
+ @_direct_read_sets ||= @direct_read_sets.transform_values do |v|
123
152
  bitmap_to_terms(v)
124
153
  end
125
154
  end
126
155
 
156
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
127
157
  def read_sets
128
- @read_sets.transform_values do |v|
158
+ @_read_sets ||= @read_sets.transform_values do |v|
129
159
  bitmap_to_terms(v)
130
160
  end
131
161
  end
132
162
 
163
+ # @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
133
164
  def follow_sets
134
- @follow_sets.transform_values do |v|
165
+ @_follow_sets ||= @follow_sets.transform_values do |v|
135
166
  bitmap_to_terms(v)
136
167
  end
137
168
  end
138
169
 
170
+ # @rbs () -> Hash[state_id, Hash[rule_id, Array[Grammar::Symbol]]]
139
171
  def la
140
- @la.transform_values do |v|
141
- bitmap_to_terms(v)
172
+ @_la ||= @la.transform_values do |second_hash|
173
+ second_hash.transform_values do |v|
174
+ bitmap_to_terms(v)
175
+ end
142
176
  end
143
177
  end
144
178
 
179
+ # @rbs () -> Integer
145
180
  def sr_conflicts_count
146
181
  @sr_conflicts_count ||= @states.flat_map(&:sr_conflicts).count
147
182
  end
148
183
 
184
+ # @rbs () -> Integer
149
185
  def rr_conflicts_count
150
186
  @rr_conflicts_count ||= @states.flat_map(&:rr_conflicts).count
151
187
  end
152
188
 
153
- private
189
+ # @rbs (Logger logger) -> void
190
+ def validate!(logger)
191
+ validate_conflicts_within_threshold!(logger)
192
+ end
154
193
 
155
- def trace_state
156
- if @trace_state
157
- yield STDERR
194
+ def compute_la_sources_for_conflicted_states
195
+ reflexive = {}
196
+ @states.each do |state|
197
+ state.nterm_transitions.each do |goto|
198
+ reflexive[goto] = [goto]
199
+ end
200
+ end
201
+
202
+ # compute_read_sets
203
+ read_sets = Digraph.new(nterm_transitions, @reads_relation, reflexive).compute
204
+ # compute_follow_sets
205
+ follow_sets = Digraph.new(nterm_transitions, @includes_relation, read_sets).compute
206
+
207
+ @states.select(&:has_conflicts?).each do |state|
208
+ lookback_relation_on_state = @lookback_relation[state.id]
209
+ next unless lookback_relation_on_state
210
+ rules.each do |rule|
211
+ ary = lookback_relation_on_state[rule.id]
212
+ next unless ary
213
+
214
+ sources = {}
215
+
216
+ ary.each do |goto|
217
+ source = follow_sets[goto]
218
+
219
+ next unless source
220
+
221
+ source.each do |goto2|
222
+ tokens = direct_read_sets[goto2]
223
+ tokens.each do |token|
224
+ sources[token] ||= []
225
+ sources[token] |= [goto2]
226
+ end
227
+ end
228
+ end
229
+
230
+ state.set_look_ahead_sources(rule, sources)
231
+ end
158
232
  end
159
233
  end
160
234
 
235
+ private
236
+
237
+ # @rbs (Grammar::Symbol accessing_symbol, Array[State::Item] kernels, Hash[Array[State::Item], State] states_created) -> [State, bool]
161
238
  def create_state(accessing_symbol, kernels, states_created)
162
239
  # A item can appear in some states,
163
240
  # so need to use `kernels` (not `kernels.first`) as a key.
@@ -204,27 +281,25 @@ module Lrama
204
281
  return [state, true]
205
282
  end
206
283
 
284
+ # @rbs (State state) -> void
207
285
  def setup_state(state)
208
286
  # closure
209
287
  closure = []
210
- visited = {}
211
288
  queued = {}
212
289
  items = state.kernels.dup
213
290
 
214
291
  items.each do |item|
215
- queued[item] = true
292
+ queued[item.rule_id] = true if item.position == 0
216
293
  end
217
294
 
218
295
  while (item = items.shift) do
219
- visited[item] = true
220
-
221
296
  if (sym = item.next_sym) && sym.nterm?
222
297
  @grammar.find_rules_by_symbol!(sym).each do |rule|
223
- i = Item.new(rule: rule, position: 0)
224
- next if queued[i]
298
+ next if queued[rule.id]
299
+ i = State::Item.new(rule: rule, position: 0)
225
300
  closure << i
226
301
  items << i
227
- queued[i] = true
302
+ queued[i.rule_id] = true
228
303
  end
229
304
  end
230
305
  end
@@ -232,119 +307,107 @@ module Lrama
232
307
  state.closure = closure.sort_by {|i| i.rule.id }
233
308
 
234
309
  # Trace
235
- trace_state do |out|
236
- out << "Closure: input\n"
237
- state.kernels.each do |item|
238
- out << " #{item.display_rest}\n"
239
- end
240
- out << "\n\n"
241
- out << "Closure: output\n"
242
- state.items.each do |item|
243
- out << " #{item.display_rest}\n"
244
- end
245
- out << "\n\n"
246
- end
310
+ @tracer.trace_closure(state)
247
311
 
248
312
  # shift & reduce
249
- state.compute_shifts_reduces
313
+ state.compute_transitions_and_reduces
250
314
  end
251
315
 
316
+ # @rbs (Array[State] states, State state) -> void
252
317
  def enqueue_state(states, state)
253
318
  # Trace
254
- previous = state.kernels.first.previous_sym
255
- trace_state do |out|
256
- out << sprintf("state_list_append (state = %d, symbol = %d (%s))\n",
257
- @states.count, previous.number, previous.display_name)
258
- end
319
+ @tracer.trace_state_list_append(@states.count, state)
259
320
 
260
321
  states << state
261
322
  end
262
323
 
324
+ # @rbs () -> void
263
325
  def compute_lr0_states
264
326
  # State queue
265
327
  states = []
266
328
  states_created = {}
267
329
 
268
- state, _ = create_state(symbols.first, [Item.new(rule: @grammar.rules.first, position: 0)], states_created)
330
+ state, _ = create_state(symbols.first, [State::Item.new(rule: @grammar.rules.first, position: 0)], states_created)
269
331
  enqueue_state(states, state)
270
332
 
271
333
  while (state = states.shift) do
272
334
  # Trace
273
- #
274
- # Bison 3.8.2 renders "(reached by "end-of-input")" for State 0 but
275
- # I think it is not correct...
276
- previous = state.kernels.first.previous_sym
277
- trace_state do |out|
278
- out << "Processing state #{state.id} (reached by #{previous.display_name})\n"
279
- end
335
+ @tracer.trace_state(state)
280
336
 
281
337
  setup_state(state)
282
338
 
283
- state.shifts.each do |shift|
284
- new_state, created = create_state(shift.next_sym, shift.next_items, states_created)
285
- state.set_items_to_state(shift.next_items, new_state)
286
- if created
287
- enqueue_state(states, new_state)
288
- new_state.append_predecessor(state)
289
- end
339
+ # `State#transitions` can not be used here
340
+ # because `items_to_state` of the `state` is not set yet.
341
+ state._transitions.each do |next_sym, to_items|
342
+ new_state, created = create_state(next_sym, to_items, states_created)
343
+ state.set_items_to_state(to_items, new_state)
344
+ state.set_lane_items(next_sym, new_state)
345
+ enqueue_state(states, new_state) if created
290
346
  end
291
347
  end
292
348
  end
293
349
 
350
+ # @rbs () -> Array[State::Action::Goto]
294
351
  def nterm_transitions
295
352
  a = []
296
353
 
297
354
  @states.each do |state|
298
- state.nterm_transitions.each do |shift, next_state|
299
- nterm = shift.next_sym
300
- a << [state, nterm, next_state]
355
+ state.nterm_transitions.each do |goto|
356
+ a << goto
301
357
  end
302
358
  end
303
359
 
304
360
  a
305
361
  end
306
362
 
363
+ # @rbs () -> void
364
+ def compute_look_ahead_sets
365
+ report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
366
+ report_duration(:compute_reads_relation) { compute_reads_relation }
367
+ report_duration(:compute_read_sets) { compute_read_sets }
368
+ report_duration(:compute_includes_relation) { compute_includes_relation }
369
+ report_duration(:compute_lookback_relation) { compute_lookback_relation }
370
+ report_duration(:compute_follow_sets) { compute_follow_sets }
371
+ report_duration(:compute_la) { compute_la }
372
+ end
373
+
374
+ # @rbs () -> void
307
375
  def compute_direct_read_sets
308
376
  @states.each do |state|
309
- state.nterm_transitions.each do |shift, next_state|
310
- nterm = shift.next_sym
311
-
312
- ary = next_state.term_transitions.map do |shift, _|
377
+ state.nterm_transitions.each do |goto|
378
+ ary = goto.to_state.term_transitions.map do |shift|
313
379
  shift.next_sym.number
314
380
  end
315
381
 
316
- key = [state.id, nterm.token_id]
317
- @direct_read_sets[key] = Bitmap.from_array(ary)
382
+ @direct_read_sets[goto] = Bitmap.from_array(ary)
318
383
  end
319
384
  end
320
385
  end
321
386
 
387
+ # @rbs () -> void
322
388
  def compute_reads_relation
323
389
  @states.each do |state|
324
- state.nterm_transitions.each do |shift, next_state|
325
- nterm = shift.next_sym
326
- next_state.nterm_transitions.each do |shift2, _next_state2|
327
- nterm2 = shift2.next_sym
390
+ state.nterm_transitions.each do |goto|
391
+ goto.to_state.nterm_transitions.each do |goto2|
392
+ nterm2 = goto2.next_sym
328
393
  if nterm2.nullable
329
- key = [state.id, nterm.token_id]
330
- @reads_relation[key] ||= []
331
- @reads_relation[key] << [next_state.id, nterm2.token_id]
394
+ @reads_relation[goto] ||= []
395
+ @reads_relation[goto] << goto2
332
396
  end
333
397
  end
334
398
  end
335
399
  end
336
400
  end
337
401
 
402
+ # @rbs () -> void
338
403
  def compute_read_sets
339
- sets = nterm_transitions.map do |state, nterm, next_state|
340
- [state.id, nterm.token_id]
341
- end
342
-
343
- @read_sets = Digraph.new(sets, @reads_relation, @direct_read_sets).compute
404
+ @read_sets = Digraph.new(nterm_transitions, @reads_relation, @direct_read_sets).compute
344
405
  end
345
406
 
346
407
  # Execute transition of state by symbols
347
408
  # then return final state.
409
+ #
410
+ # @rbs (State state, Array[Grammar::Symbol] symbols) -> State
348
411
  def transition(state, symbols)
349
412
  symbols.each do |sym|
350
413
  state = state.transition(sym)
@@ -353,10 +416,11 @@ module Lrama
353
416
  state
354
417
  end
355
418
 
419
+ # @rbs () -> void
356
420
  def compute_includes_relation
357
421
  @states.each do |state|
358
- state.nterm_transitions.each do |shift, next_state|
359
- nterm = shift.next_sym
422
+ state.nterm_transitions.each do |goto|
423
+ nterm = goto.next_sym
360
424
  @grammar.find_rules_by_symbol!(nterm).each do |rule|
361
425
  i = rule.rhs.count - 1
362
426
 
@@ -366,10 +430,12 @@ module Lrama
366
430
  break if sym.term?
367
431
  state2 = transition(state, rule.rhs[0...i])
368
432
  # p' = state, B = nterm, p = state2, A = sym
369
- key = [state2.id, sym.token_id]
433
+ key = state2.nterm_transitions.find do |goto2|
434
+ goto2.next_sym.token_id == sym.token_id
435
+ end || (raise "Goto by #{sym.name} on state #{state2.id} is not found")
370
436
  # TODO: need to omit if state == state2 ?
371
437
  @includes_relation[key] ||= []
372
- @includes_relation[key] << [state.id, nterm.token_id]
438
+ @includes_relation[key] << goto
373
439
  break unless sym.nullable
374
440
  i -= 1
375
441
  end
@@ -378,45 +444,46 @@ module Lrama
378
444
  end
379
445
  end
380
446
 
447
+ # @rbs () -> void
381
448
  def compute_lookback_relation
382
449
  @states.each do |state|
383
- state.nterm_transitions.each do |shift, next_state|
384
- nterm = shift.next_sym
450
+ state.nterm_transitions.each do |goto|
451
+ nterm = goto.next_sym
385
452
  @grammar.find_rules_by_symbol!(nterm).each do |rule|
386
453
  state2 = transition(state, rule.rhs)
387
454
  # p = state, A = nterm, q = state2, A -> ω = rule
388
- key = [state2.id, rule.id]
389
- @lookback_relation[key] ||= []
390
- @lookback_relation[key] << [state.id, nterm.token_id]
455
+ @lookback_relation[state2.id] ||= {}
456
+ @lookback_relation[state2.id][rule.id] ||= []
457
+ @lookback_relation[state2.id][rule.id] << goto
391
458
  end
392
459
  end
393
460
  end
394
461
  end
395
462
 
463
+ # @rbs () -> void
396
464
  def compute_follow_sets
397
- sets = nterm_transitions.map do |state, nterm, next_state|
398
- [state.id, nterm.token_id]
399
- end
400
-
401
- @follow_sets = Digraph.new(sets, @includes_relation, @read_sets).compute
465
+ @follow_sets = Digraph.new(nterm_transitions, @includes_relation, @read_sets).compute
402
466
  end
403
467
 
404
- def compute_look_ahead_sets
468
+ # @rbs () -> void
469
+ def compute_la
405
470
  @states.each do |state|
471
+ lookback_relation_on_state = @lookback_relation[state.id]
472
+ next unless lookback_relation_on_state
406
473
  rules.each do |rule|
407
- ary = @lookback_relation[[state.id, rule.id]]
474
+ ary = lookback_relation_on_state[rule.id]
408
475
  next unless ary
409
476
 
410
- ary.each do |state2_id, nterm_token_id|
477
+ ary.each do |goto|
411
478
  # q = state, A -> ω = rule, p = state2, A = nterm
412
- follows = @follow_sets[[state2_id, nterm_token_id]]
479
+ follows = @follow_sets[goto]
413
480
 
414
481
  next if follows == 0
415
482
 
416
- key = [state.id, rule.id]
417
- @la[key] ||= 0
418
- look_ahead = @la[key] | follows
419
- @la[key] |= look_ahead
483
+ @la[state.id] ||= {}
484
+ @la[state.id][rule.id] ||= 0
485
+ look_ahead = @la[state.id][rule.id] | follows
486
+ @la[state.id][rule.id] |= look_ahead
420
487
 
421
488
  # No risk of conflict when
422
489
  # * the state only has single reduce
@@ -429,6 +496,7 @@ module Lrama
429
496
  end
430
497
  end
431
498
 
499
+ # @rbs (Bitmap::bitmap bit) -> Array[Grammar::Symbol]
432
500
  def bitmap_to_terms(bit)
433
501
  ary = Bitmap.to_array(bit)
434
502
  ary.map do |i|
@@ -436,14 +504,16 @@ module Lrama
436
504
  end
437
505
  end
438
506
 
439
- def compute_conflicts
440
- compute_shift_reduce_conflicts
507
+ # @rbs () -> void
508
+ def compute_conflicts(lr_type)
509
+ compute_shift_reduce_conflicts(lr_type)
441
510
  compute_reduce_reduce_conflicts
442
511
  end
443
512
 
444
- def compute_shift_reduce_conflicts
513
+ # @rbs () -> void
514
+ def compute_shift_reduce_conflicts(lr_type)
445
515
  states.each do |state|
446
- state.shifts.each do |shift|
516
+ state.term_transitions.each do |shift|
447
517
  state.reduces.each do |reduce|
448
518
  sym = shift.next_sym
449
519
 
@@ -463,43 +533,57 @@ module Lrama
463
533
  case
464
534
  when shift_prec < reduce_prec
465
535
  # Reduce is selected
466
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :reduce)
536
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: false)
537
+ state.resolved_conflicts << resolved_conflict
467
538
  shift.not_selected = true
539
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
468
540
  next
469
541
  when shift_prec > reduce_prec
470
542
  # Shift is selected
471
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift)
543
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: false)
544
+ state.resolved_conflicts << resolved_conflict
472
545
  reduce.add_not_selected_symbol(sym)
546
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
473
547
  next
474
548
  end
475
549
 
476
550
  # shift_prec == reduce_prec, then check associativity
477
551
  case sym.precedence.type
478
552
  when :precedence
553
+ # Can not resolve the conflict
554
+ #
479
555
  # %precedence only specifies precedence and not specify associativity
480
556
  # then a conflict is unresolved if precedence is same.
481
557
  state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
482
558
  next
483
559
  when :right
484
560
  # Shift is selected
485
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift, same_prec: true)
561
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: true)
562
+ state.resolved_conflicts << resolved_conflict
486
563
  reduce.add_not_selected_symbol(sym)
564
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
487
565
  next
488
566
  when :left
489
567
  # Reduce is selected
490
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :reduce, same_prec: true)
568
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: true)
569
+ state.resolved_conflicts << resolved_conflict
491
570
  shift.not_selected = true
571
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
492
572
  next
493
573
  when :nonassoc
494
- # Can not resolve
574
+ # The conflict is resolved
495
575
  #
496
- # nonassoc creates "run-time" error, precedence creates "compile-time" error.
497
- # Then omit both the shift and reduce.
576
+ # %nonassoc creates "run-time" error by removing both shift and reduce from
577
+ # the state. This makes the state to get syntax error if the conflicted token appears.
578
+ # On the other hand, %precedence creates "compile-time" error by keeping both
579
+ # shift and reduce on the state. This makes the state to be conflicted on the token.
498
580
  #
499
581
  # https://www.gnu.org/software/bison/manual/html_node/Using-Precedence.html
500
- state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :error)
582
+ resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :error, resolved_by_precedence: false)
583
+ state.resolved_conflicts << resolved_conflict
501
584
  shift.not_selected = true
502
585
  reduce.add_not_selected_symbol(sym)
586
+ mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
503
587
  else
504
588
  raise "Unknown precedence type. #{sym}"
505
589
  end
@@ -508,35 +592,41 @@ module Lrama
508
592
  end
509
593
  end
510
594
 
595
+ # @rbs (Grammar::Precedence shift_prec, Grammar::Precedence reduce_prec, State::ResolvedConflict resolved_conflict) -> void
596
+ def mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
597
+ case lr_type
598
+ when :lalr
599
+ shift_prec.mark_used_by_lalr(resolved_conflict)
600
+ reduce_prec.mark_used_by_lalr(resolved_conflict)
601
+ when :ielr
602
+ shift_prec.mark_used_by_ielr(resolved_conflict)
603
+ reduce_prec.mark_used_by_ielr(resolved_conflict)
604
+ end
605
+ end
606
+
607
+ # @rbs () -> void
511
608
  def compute_reduce_reduce_conflicts
512
609
  states.each do |state|
513
- count = state.reduces.count
514
-
515
- (0...count).each do |i|
516
- reduce1 = state.reduces[i]
517
- next if reduce1.look_ahead.nil?
610
+ state.reduces.combination(2) do |reduce1, reduce2|
611
+ next if reduce1.look_ahead.nil? || reduce2.look_ahead.nil?
518
612
 
519
- ((i+1)...count).each do |j|
520
- reduce2 = state.reduces[j]
521
- next if reduce2.look_ahead.nil?
613
+ intersection = reduce1.look_ahead & reduce2.look_ahead
522
614
 
523
- intersection = reduce1.look_ahead & reduce2.look_ahead
524
-
525
- unless intersection.empty?
526
- state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
527
- end
615
+ unless intersection.empty?
616
+ state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
528
617
  end
529
618
  end
530
619
  end
531
620
  end
532
621
 
622
+ # @rbs () -> void
533
623
  def compute_default_reduction
534
624
  states.each do |state|
535
625
  next if state.reduces.empty?
536
626
  # Do not set, if conflict exist
537
627
  next unless state.conflicts.empty?
538
628
  # Do not set, if shift with `error` exists.
539
- next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol)
629
+ next if state.term_transitions.map {|shift| shift.next_sym }.include?(@grammar.error_symbol)
540
630
 
541
631
  state.default_reduction_rule = state.reduces.map do |r|
542
632
  [r.rule, r.rule.id, (r.look_ahead || []).count]
@@ -546,35 +636,171 @@ module Lrama
546
636
  end
547
637
  end
548
638
 
639
+ # @rbs () -> void
640
+ def clear_conflicts
641
+ states.each(&:clear_conflicts)
642
+ end
643
+
644
+ # Definition 3.15 (Predecessors)
645
+ #
646
+ # @rbs () -> void
647
+ def compute_predecessors
648
+ @states.each do |state|
649
+ state.transitions.each do |transition|
650
+ transition.to_state.append_predecessor(state)
651
+ end
652
+ end
653
+ end
654
+
655
+ # Definition 3.16 (follow_kernel_items)
656
+ #
657
+ # @rbs () -> void
658
+ def compute_follow_kernel_items
659
+ set = nterm_transitions
660
+ relation = compute_goto_internal_relation
661
+ base_function = compute_goto_bitmaps
662
+ Digraph.new(set, relation, base_function).compute.each do |goto, follow_kernel_items|
663
+ state = goto.from_state
664
+ state.follow_kernel_items[goto] = state.kernels.map {|kernel|
665
+ [kernel, Bitmap.to_bool_array(follow_kernel_items, state.kernels.count)]
666
+ }.to_h
667
+ end
668
+ end
669
+
670
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
671
+ def compute_goto_internal_relation
672
+ relations = {}
673
+
674
+ @states.each do |state|
675
+ state.nterm_transitions.each do |goto|
676
+ relations[goto] = state.internal_dependencies(goto)
677
+ end
678
+ end
679
+
680
+ relations
681
+ end
682
+
683
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
684
+ def compute_goto_bitmaps
685
+ nterm_transitions.map {|goto|
686
+ bools = goto.from_state.kernels.map.with_index {|kernel, i| i if kernel.next_sym == goto.next_sym && kernel.symbols_after_transition.all?(&:nullable) }.compact
687
+ [goto, Bitmap.from_array(bools)]
688
+ }.to_h
689
+ end
690
+
691
+ # Definition 3.20 (always_follows, one closure)
692
+ #
693
+ # @rbs () -> void
694
+ def compute_always_follows
695
+ set = nterm_transitions
696
+ relation = compute_goto_successor_or_internal_relation
697
+ base_function = compute_transition_bitmaps
698
+ Digraph.new(set, relation, base_function).compute.each do |goto, always_follows_bitmap|
699
+ goto.from_state.always_follows[goto] = bitmap_to_terms(always_follows_bitmap)
700
+ end
701
+ end
702
+
703
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
704
+ def compute_goto_successor_or_internal_relation
705
+ relations = {}
706
+
707
+ @states.each do |state|
708
+ state.nterm_transitions.each do |goto|
709
+ relations[goto] = state.successor_dependencies(goto) + state.internal_dependencies(goto)
710
+ end
711
+ end
712
+
713
+ relations
714
+ end
715
+
716
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
717
+ def compute_transition_bitmaps
718
+ nterm_transitions.map {|goto|
719
+ [goto, Bitmap.from_array(goto.to_state.term_transitions.map {|shift| shift.next_sym.number })]
720
+ }.to_h
721
+ end
722
+
723
+ # Definition 3.24 (goto_follows, via always_follows)
724
+ #
725
+ # @rbs () -> void
726
+ def compute_goto_follows
727
+ set = nterm_transitions
728
+ relation = compute_goto_internal_or_predecessor_dependencies
729
+ base_function = compute_always_follows_bitmaps
730
+ Digraph.new(set, relation, base_function).compute.each do |goto, goto_follows_bitmap|
731
+ goto.from_state.goto_follows[goto] = bitmap_to_terms(goto_follows_bitmap)
732
+ end
733
+ end
734
+
735
+ # @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
736
+ def compute_goto_internal_or_predecessor_dependencies
737
+ relations = {}
738
+
739
+ @states.each do |state|
740
+ state.nterm_transitions.each do |goto|
741
+ relations[goto] = state.internal_dependencies(goto) + state.predecessor_dependencies(goto)
742
+ end
743
+ end
744
+
745
+ relations
746
+ end
747
+
748
+ # @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
749
+ def compute_always_follows_bitmaps
750
+ nterm_transitions.map {|goto|
751
+ [goto, Bitmap.from_array(goto.from_state.always_follows[goto].map(&:number))]
752
+ }.to_h
753
+ end
754
+
755
+ # @rbs () -> void
549
756
  def split_states
550
757
  @states.each do |state|
551
- state.transitions.each do |shift, next_state|
552
- compute_state(state, shift, next_state)
758
+ state.transitions.each do |transition|
759
+ compute_state(state, transition, transition.to_state)
553
760
  end
554
761
  end
555
762
  end
556
763
 
764
+ # @rbs () -> void
765
+ def compute_inadequacy_annotations
766
+ @states.each do |state|
767
+ state.annotate_manifestation
768
+ end
769
+
770
+ queue = @states.reject {|state| state.annotation_list.empty? }
771
+
772
+ while (curr = queue.shift) do
773
+ curr.predecessors.each do |pred|
774
+ cache = pred.annotation_list.dup
775
+ curr.annotate_predecessor(pred)
776
+ queue << pred if cache != pred.annotation_list && !queue.include?(pred)
777
+ end
778
+ end
779
+ end
780
+
781
+ # @rbs (State state, State::lookahead_set filtered_lookaheads) -> void
557
782
  def merge_lookaheads(state, filtered_lookaheads)
558
783
  return if state.kernels.all? {|item| (filtered_lookaheads[item] - state.item_lookahead_set[item]).empty? }
559
784
 
560
785
  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)
786
+ state.transitions.each do |transition|
787
+ next if transition.to_state.lookaheads_recomputed
788
+ compute_state(state, transition, transition.to_state)
564
789
  end
565
790
  end
566
791
 
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) }
792
+ # @rbs (State state, State::Action::Shift | State::Action::Goto transition, State next_state) -> void
793
+ def compute_state(state, transition, next_state)
794
+ propagating_lookaheads = state.propagate_lookaheads(next_state)
795
+ s = next_state.ielr_isocores.find {|st| st.is_compatible?(propagating_lookaheads) }
570
796
 
571
797
  if s.nil?
572
- s = next_state.ielr_isocores.last
798
+ s = next_state.lalr_isocore
573
799
  new_state = State.new(@states.count, s.accessing_symbol, s.kernels)
574
800
  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)
801
+ new_state.compute_transitions_and_reduces
802
+ s.transitions.each do |transition|
803
+ new_state.set_items_to_state(transition.to_items, transition.to_state)
578
804
  end
579
805
  @states << new_state
580
806
  new_state.lalr_isocore = s
@@ -582,14 +808,60 @@ module Lrama
582
808
  s.ielr_isocores.each do |st|
583
809
  st.ielr_isocores = s.ielr_isocores
584
810
  end
585
- new_state.item_lookahead_set = filtered_lookaheads
586
- state.update_transition(shift, new_state)
811
+ new_state.lookaheads_recomputed = true
812
+ new_state.item_lookahead_set = propagating_lookaheads
813
+ state.update_transition(transition, new_state)
587
814
  elsif(!s.lookaheads_recomputed)
588
- s.item_lookahead_set = filtered_lookaheads
815
+ s.lookaheads_recomputed = true
816
+ s.item_lookahead_set = propagating_lookaheads
589
817
  else
590
- state.update_transition(shift, s)
591
- merge_lookaheads(s, filtered_lookaheads)
818
+ merge_lookaheads(s, propagating_lookaheads)
819
+ state.update_transition(transition, s) if state.items_to_state[transition.to_items].id != s.id
592
820
  end
593
821
  end
822
+
823
+ # @rbs (Logger logger) -> void
824
+ def validate_conflicts_within_threshold!(logger)
825
+ exit false unless conflicts_within_threshold?(logger)
826
+ end
827
+
828
+ # @rbs (Logger logger) -> bool
829
+ def conflicts_within_threshold?(logger)
830
+ return true unless @grammar.expect
831
+
832
+ [sr_conflicts_within_threshold?(logger), rr_conflicts_within_threshold?(logger)].all?
833
+ end
834
+
835
+ # @rbs (Logger logger) -> bool
836
+ def sr_conflicts_within_threshold?(logger)
837
+ return true if @grammar.expect == sr_conflicts_count
838
+
839
+ logger.error("shift/reduce conflicts: #{sr_conflicts_count} found, #{@grammar.expect} expected")
840
+ false
841
+ end
842
+
843
+ # @rbs (Logger logger) -> bool
844
+ def rr_conflicts_within_threshold?(logger, expected: 0)
845
+ return true if expected == rr_conflicts_count
846
+
847
+ logger.error("reduce/reduce conflicts: #{rr_conflicts_count} found, #{expected} expected")
848
+ false
849
+ end
850
+
851
+ # @rbs () -> void
852
+ def clear_look_ahead_sets
853
+ @direct_read_sets.clear
854
+ @reads_relation.clear
855
+ @read_sets.clear
856
+ @includes_relation.clear
857
+ @lookback_relation.clear
858
+ @follow_sets.clear
859
+ @la.clear
860
+
861
+ @_direct_read_sets = nil
862
+ @_read_sets = nil
863
+ @_follow_sets = nil
864
+ @_la = nil
865
+ end
594
866
  end
595
867
  end