ibex 0.2.0 → 0.4.0

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 (461) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -272
  3. data/docs/architecture.md +187 -35
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +3 -4
  12. data/docs/cst.md +24 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +274 -0
  40. data/docs/development.md +196 -2
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +2 -1
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1617 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +54 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +184 -13
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/impact.md +101 -0
  56. data/docs/ja/bison-import.md +51 -0
  57. data/docs/ja/stable-api.md +53 -0
  58. data/docs/lexer-construction-profile.md +109 -0
  59. data/docs/lexer-migration.md +5 -0
  60. data/docs/maturity.md +129 -0
  61. data/docs/project-site-strategy.md +54 -0
  62. data/docs/racc-migration-evidence.md +45 -0
  63. data/docs/racc-migration.md +11 -0
  64. data/docs/release-readiness.md +126 -68
  65. data/docs/repair-semantics.md +123 -0
  66. data/docs/runtime-abi-evolution.md +310 -0
  67. data/docs/stability.md +145 -34
  68. data/docs/status.md +43 -0
  69. data/docs/syntax-sessions.md +183 -0
  70. data/docs/table-artifact.md +125 -0
  71. data/docs/test-interactions.md +219 -0
  72. data/docs/verification-report.md +137 -0
  73. data/docs/verifier-trust-boundary.md +199 -0
  74. data/docs/workloads.md +132 -0
  75. data/lib/ibex/analysis/digraph.rb +128 -0
  76. data/lib/ibex/analysis/sets.rb +14 -0
  77. data/lib/ibex/analysis.rb +1 -0
  78. data/lib/ibex/bison_import/importer.rb +516 -0
  79. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  80. data/lib/ibex/bison_import.rb +200 -0
  81. data/lib/ibex/bounded_subprocess.rb +171 -0
  82. data/lib/ibex/cli/ambiguity.rb +14 -5
  83. data/lib/ibex/cli/analysis.rb +134 -0
  84. data/lib/ibex/cli/bison_import.rb +121 -0
  85. data/lib/ibex/cli/config.rb +128 -0
  86. data/lib/ibex/cli/diagnostics.rb +31 -11
  87. data/lib/ibex/cli/documentation.rb +11 -8
  88. data/lib/ibex/cli/equiv.rb +169 -0
  89. data/lib/ibex/cli/error_messages.rb +11 -4
  90. data/lib/ibex/cli/explain.rb +14 -5
  91. data/lib/ibex/cli/fix.rb +203 -0
  92. data/lib/ibex/cli/formatting.rb +11 -10
  93. data/lib/ibex/cli/fuzz.rb +200 -0
  94. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  95. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  96. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  97. data/lib/ibex/cli/grammar_tests.rb +32 -14
  98. data/lib/ibex/cli/impact.rb +393 -0
  99. data/lib/ibex/cli/ir_tools.rb +5 -61
  100. data/lib/ibex/cli/outputs.rb +60 -33
  101. data/lib/ibex/cli/reduce.rb +202 -0
  102. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  103. data/lib/ibex/cli/samples.rb +49 -23
  104. data/lib/ibex/cli/verify.rb +116 -0
  105. data/lib/ibex/cli/watch.rb +6 -5
  106. data/lib/ibex/cli.rb +362 -56
  107. data/lib/ibex/codegen/action_locations.rb +1 -1
  108. data/lib/ibex/codegen/action_method_source.rb +5 -6
  109. data/lib/ibex/codegen/action_source.rb +3 -2
  110. data/lib/ibex/codegen/ambiguity.rb +5 -4
  111. data/lib/ibex/codegen/explain.rb +123 -55
  112. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  113. data/lib/ibex/codegen/rbs.rb +15 -7
  114. data/lib/ibex/codegen/report.rb +25 -13
  115. data/lib/ibex/codegen/ruby.rb +28 -64
  116. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  117. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  118. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  119. data/lib/ibex/configuration/explanation.rb +421 -0
  120. data/lib/ibex/configuration/inspector.rb +232 -0
  121. data/lib/ibex/configuration.rb +580 -0
  122. data/lib/ibex/coverage/collector.rb +21 -11
  123. data/lib/ibex/coverage/event_stream.rb +13 -7
  124. data/lib/ibex/coverage/report.rb +26 -18
  125. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  126. data/lib/ibex/delta_reducer.rb +99 -0
  127. data/lib/ibex/diff.rb +141 -0
  128. data/lib/ibex/equiv/machine.rb +135 -0
  129. data/lib/ibex/equiv.rb +373 -0
  130. data/lib/ibex/fix.rb +557 -0
  131. data/lib/ibex/frontend/ast.rb +22 -2
  132. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  133. data/lib/ibex/frontend/diagnostic.rb +1 -1
  134. data/lib/ibex/frontend/formatter.rb +72 -26
  135. data/lib/ibex/frontend/generated_parser.rb +147 -117
  136. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  137. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  138. data/lib/ibex/frontend/generation.rb +1 -1
  139. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  140. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  141. data/lib/ibex/frontend/regenerator.rb +1 -0
  142. data/lib/ibex/frontend/resolution.rb +2 -1
  143. data/lib/ibex/frontend/resolver.rb +1 -1
  144. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  145. data/lib/ibex/frontend/source_cursor.rb +2 -2
  146. data/lib/ibex/frontend/source_span.rb +9 -1
  147. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  148. data/lib/ibex/frontend/token_adapter.rb +10 -0
  149. data/lib/ibex/frontend.rb +1 -0
  150. data/lib/ibex/fuzz.rb +219 -0
  151. data/lib/ibex/generation_input.rb +1 -1
  152. data/lib/ibex/generation_manifest.rb +36 -25
  153. data/lib/ibex/generation_transaction.rb +1 -1
  154. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  155. data/lib/ibex/generation_transaction_validation.rb +2 -2
  156. data/lib/ibex/grammar_tests.rb +1 -1
  157. data/lib/ibex/impact/action_impact.rb +148 -0
  158. data/lib/ibex/impact/automaton_impact.rb +57 -0
  159. data/lib/ibex/impact/coverage_impact.rb +53 -0
  160. data/lib/ibex/impact/graph.rb +132 -0
  161. data/lib/ibex/impact/propagation.rb +147 -0
  162. data/lib/ibex/impact/report.rb +273 -0
  163. data/lib/ibex/impact/seeds.rb +69 -0
  164. data/lib/ibex/impact/severity.rb +139 -0
  165. data/lib/ibex/impact.rb +16 -0
  166. data/lib/ibex/ir/automaton_ir.rb +61 -19
  167. data/lib/ibex/ir/grammar_ir.rb +76 -45
  168. data/lib/ibex/ir/lexer_ir.rb +5 -5
  169. data/lib/ibex/ir/parser_contract.rb +135 -0
  170. data/lib/ibex/ir/serialize.rb +203 -76
  171. data/lib/ibex/ir/validator/automaton.rb +64 -34
  172. data/lib/ibex/ir/validator/base.rb +51 -33
  173. data/lib/ibex/ir/validator/grammar.rb +113 -83
  174. data/lib/ibex/ir/validator/lexer.rb +2 -2
  175. data/lib/ibex/ir/validator.rb +2 -1
  176. data/lib/ibex/ir.rb +16 -3
  177. data/lib/ibex/lalr/build_metrics.rb +50 -2
  178. data/lib/ibex/lalr/builder.rb +191 -56
  179. data/lib/ibex/lalr/conflict_search.rb +15 -4
  180. data/lib/ibex/lalr/counterexample.rb +19 -14
  181. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  182. data/lib/ibex/lalr/goto_follows.rb +229 -0
  183. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  184. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  185. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  186. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  187. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  188. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  189. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  190. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  191. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  192. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  193. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  194. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  195. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  196. data/lib/ibex/lalr.rb +52 -1
  197. data/lib/ibex/location.rb +3 -3
  198. data/lib/ibex/lsp/document_handlers.rb +9 -7
  199. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  200. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  201. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  202. data/lib/ibex/lsp/position_codec.rb +6 -2
  203. data/lib/ibex/lsp/request_handlers.rb +3 -2
  204. data/lib/ibex/lsp/request_support.rb +14 -7
  205. data/lib/ibex/lsp/server.rb +13 -11
  206. data/lib/ibex/lsp/symbol_index.rb +13 -13
  207. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  208. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  209. data/lib/ibex/lsp/transport.rb +13 -3
  210. data/lib/ibex/lsp/workspace.rb +5 -4
  211. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  212. data/lib/ibex/lsp.rb +1 -0
  213. data/lib/ibex/messages/en.yml +28 -0
  214. data/lib/ibex/messages/ja.yml +28 -0
  215. data/lib/ibex/messages.rb +68 -0
  216. data/lib/ibex/metrics.rb +175 -0
  217. data/lib/ibex/normalize/declarations.rb +2 -0
  218. data/lib/ibex/normalize/diagnostics.rb +63 -38
  219. data/lib/ibex/normalize/expander.rb +5 -4
  220. data/lib/ibex/normalize/expression.rb +8 -6
  221. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  222. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  223. data/lib/ibex/normalize/lexer.rb +3 -3
  224. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  225. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  226. data/lib/ibex/normalize/parameters.rb +31 -4
  227. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  228. data/lib/ibex/normalize.rb +10 -20
  229. data/lib/ibex/racc_migration/report.rb +6 -3
  230. data/lib/ibex/rake_task.rb +1 -1
  231. data/lib/ibex/samples.rb +43 -13
  232. data/lib/ibex/table_artifact/builder.rb +266 -0
  233. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  234. data/lib/ibex/table_artifact/document.rb +39 -0
  235. data/lib/ibex/table_artifact/executor.rb +187 -0
  236. data/lib/ibex/table_artifact/serializer.rb +57 -0
  237. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  238. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  239. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  240. data/lib/ibex/table_artifact/validator.rb +253 -0
  241. data/lib/ibex/table_artifact.rb +88 -0
  242. data/lib/ibex/table_simulation/result.rb +6 -2
  243. data/lib/ibex/table_simulation/step.rb +3 -1
  244. data/lib/ibex/tables.rb +14 -0
  245. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  246. data/lib/ibex/verification_report/builder.rb +159 -0
  247. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  248. data/lib/ibex/verification_report/logical_path.rb +68 -0
  249. data/lib/ibex/verification_report/validator.rb +329 -0
  250. data/lib/ibex/verification_report.rb +69 -0
  251. data/lib/ibex/verify/action_correspondence.rb +138 -0
  252. data/lib/ibex/verify/language_witness.rb +295 -0
  253. data/lib/ibex/verify/reference_collection.rb +190 -0
  254. data/lib/ibex/verify/result.rb +73 -0
  255. data/lib/ibex/verify/verifier.rb +598 -0
  256. data/lib/ibex/verify.rb +15 -0
  257. data/lib/ibex/version.rb +1 -1
  258. data/lib/ibex/watch/runner.rb +10 -1
  259. data/lib/ibex/watch/source_snapshot.rb +13 -8
  260. data/lib/ibex.rb +11 -0
  261. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  262. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  263. data/schema/bison-import-v1.schema.json +106 -0
  264. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  265. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  266. data/schema/construction-profile-v1.schema.json +779 -0
  267. data/schema/diff-v1.schema.json +41 -0
  268. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  269. data/schema/equiv-v1.schema.json +64 -0
  270. data/schema/error-ux-review-v1.schema.json +609 -0
  271. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  272. data/schema/error-ux-round2-v1.schema.json +519 -0
  273. data/schema/explain-v1.schema.json +63 -1
  274. data/schema/fix-v1.schema.json +64 -0
  275. data/schema/fix-v2.schema.json +66 -0
  276. data/schema/fix-v3.schema.json +101 -0
  277. data/schema/fuzz-regression-v1.schema.json +79 -0
  278. data/schema/fuzz-v1.schema.json +114 -0
  279. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  280. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  281. data/schema/grammar-ir.schema.json +271 -0
  282. data/schema/ielr-benchmark-v1.schema.json +85 -0
  283. data/schema/impact-v1.schema.json +208 -0
  284. data/schema/lexer-profile-v1.schema.json +491 -0
  285. data/schema/metrics-v1.schema.json +60 -0
  286. data/schema/reduce-v1.schema.json +22 -0
  287. data/schema/reduce-v2.schema.json +63 -0
  288. data/schema/table-artifact-v1.schema.json +377 -0
  289. data/schema/verification-report-v1.schema.json +222 -0
  290. data/schema/verify-v1.schema.json +42 -0
  291. data/sig/ibex/analysis/digraph.rbs +19 -0
  292. data/sig/ibex/analysis/sets.rbs +10 -0
  293. data/sig/ibex/bison_import/importer.rbs +140 -0
  294. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  295. data/sig/ibex/bison_import.rbs +95 -0
  296. data/sig/ibex/bounded_subprocess.rbs +76 -0
  297. data/sig/ibex/cli/ambiguity.rbs +6 -0
  298. data/sig/ibex/cli/analysis.rbs +43 -0
  299. data/sig/ibex/cli/bison_import.rbs +32 -0
  300. data/sig/ibex/cli/config.rbs +35 -0
  301. data/sig/ibex/cli/diagnostics.rbs +16 -3
  302. data/sig/ibex/cli/documentation.rbs +5 -1
  303. data/sig/ibex/cli/equiv.rbs +49 -0
  304. data/sig/ibex/cli/error_messages.rbs +6 -0
  305. data/sig/ibex/cli/explain.rbs +6 -0
  306. data/sig/ibex/cli/fix.rbs +53 -0
  307. data/sig/ibex/cli/formatting.rbs +5 -1
  308. data/sig/ibex/cli/fuzz.rbs +47 -0
  309. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  310. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  311. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  312. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  313. data/sig/ibex/cli/impact.rbs +95 -0
  314. data/sig/ibex/cli/ir_tools.rbs +7 -19
  315. data/sig/ibex/cli/outputs.rbs +9 -3
  316. data/sig/ibex/cli/reduce.rbs +60 -0
  317. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  318. data/sig/ibex/cli/samples.rbs +8 -0
  319. data/sig/ibex/cli/verify.rbs +28 -0
  320. data/sig/ibex/cli/watch.rbs +2 -2
  321. data/sig/ibex/cli.rbs +79 -5
  322. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  323. data/sig/ibex/codegen/explain.rbs +45 -25
  324. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  325. data/sig/ibex/codegen/rbs.rbs +12 -10
  326. data/sig/ibex/codegen/report.rbs +12 -12
  327. data/sig/ibex/codegen/ruby.rbs +18 -15
  328. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  329. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  330. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  331. data/sig/ibex/configuration/explanation.rbs +195 -0
  332. data/sig/ibex/configuration/inspector.rbs +53 -0
  333. data/sig/ibex/configuration.rbs +242 -0
  334. data/sig/ibex/coverage/collector.rbs +16 -14
  335. data/sig/ibex/coverage/event_stream.rbs +12 -10
  336. data/sig/ibex/coverage/report.rbs +20 -18
  337. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  338. data/sig/ibex/delta_reducer.rbs +38 -0
  339. data/sig/ibex/diff.rbs +47 -0
  340. data/sig/ibex/equiv/machine.rbs +54 -0
  341. data/sig/ibex/equiv.rbs +129 -0
  342. data/sig/ibex/fix.rbs +138 -0
  343. data/sig/ibex/frontend/ast.rbs +33 -7
  344. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  345. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  346. data/sig/ibex/frontend/formatter.rbs +38 -30
  347. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  348. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  349. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  350. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  351. data/sig/ibex/frontend/resolution.rbs +3 -2
  352. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  353. data/sig/ibex/frontend/source_span.rbs +5 -2
  354. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  355. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  356. data/sig/ibex/fuzz.rbs +71 -0
  357. data/sig/ibex/generation_input.rbs +2 -2
  358. data/sig/ibex/generation_manifest.rbs +35 -32
  359. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  360. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  361. data/sig/ibex/grammar_tests.rbs +2 -2
  362. data/sig/ibex/impact/action_impact.rbs +58 -0
  363. data/sig/ibex/impact/automaton_impact.rbs +37 -0
  364. data/sig/ibex/impact/coverage_impact.rbs +28 -0
  365. data/sig/ibex/impact/graph.rbs +67 -0
  366. data/sig/ibex/impact/propagation.rbs +56 -0
  367. data/sig/ibex/impact/report.rbs +107 -0
  368. data/sig/ibex/impact/seeds.rbs +36 -0
  369. data/sig/ibex/impact/severity.rbs +55 -0
  370. data/sig/ibex/impact.rbs +6 -0
  371. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  372. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  373. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  374. data/sig/ibex/ir/parser_contract.rbs +69 -0
  375. data/sig/ibex/ir/serialize.rbs +63 -28
  376. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  377. data/sig/ibex/ir/validator/base.rbs +35 -31
  378. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  379. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  380. data/sig/ibex/ir.rbs +9 -3
  381. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  382. data/sig/ibex/lalr/builder.rbs +75 -24
  383. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  384. data/sig/ibex/lalr/counterexample.rbs +17 -14
  385. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  386. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  387. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  388. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  389. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  390. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  391. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  392. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  393. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  394. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  395. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  396. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  397. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  398. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  399. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  400. data/sig/ibex/lalr.rbs +11 -1
  401. data/sig/ibex/location.rbs +6 -6
  402. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  403. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  404. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  405. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  406. data/sig/ibex/lsp/position_codec.rbs +8 -4
  407. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  408. data/sig/ibex/lsp/request_support.rbs +8 -8
  409. data/sig/ibex/lsp/server.rbs +16 -16
  410. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  411. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  412. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  413. data/sig/ibex/lsp/transport.rbs +18 -6
  414. data/sig/ibex/lsp/workspace.rbs +3 -2
  415. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  416. data/sig/ibex/messages.rbs +26 -0
  417. data/sig/ibex/metrics.rbs +50 -0
  418. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  419. data/sig/ibex/normalize/expander.rbs +2 -2
  420. data/sig/ibex/normalize/expression.rbs +10 -8
  421. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  422. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  423. data/sig/ibex/normalize/lexer.rbs +4 -4
  424. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  425. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  426. data/sig/ibex/normalize/parameters.rbs +13 -8
  427. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  428. data/sig/ibex/normalize.rbs +11 -5
  429. data/sig/ibex/racc_migration/report.rbs +8 -6
  430. data/sig/ibex/rake_task.rbs +1 -1
  431. data/sig/ibex/samples.rbs +13 -4
  432. data/sig/ibex/table_artifact/builder.rbs +93 -0
  433. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  434. data/sig/ibex/table_artifact/document.rbs +27 -0
  435. data/sig/ibex/table_artifact/executor.rbs +66 -0
  436. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  437. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  438. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  439. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  440. data/sig/ibex/table_artifact/validator.rbs +66 -0
  441. data/sig/ibex/table_artifact.rbs +32 -0
  442. data/sig/ibex/table_simulation/result.rbs +8 -4
  443. data/sig/ibex/table_simulation/step.rbs +4 -2
  444. data/sig/ibex/tables.rbs +10 -9
  445. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  446. data/sig/ibex/verification_report/builder.rbs +53 -0
  447. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  448. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  449. data/sig/ibex/verification_report/validator.rbs +114 -0
  450. data/sig/ibex/verification_report.rbs +44 -0
  451. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  452. data/sig/ibex/verify/language_witness.rbs +112 -0
  453. data/sig/ibex/verify/reference_collection.rbs +63 -0
  454. data/sig/ibex/verify/result.rbs +52 -0
  455. data/sig/ibex/verify/verifier.rbs +170 -0
  456. data/sig/ibex/verify.rbs +6 -0
  457. data/sig/ibex/watch/runner.rbs +12 -2
  458. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  459. metadata +254 -12
  460. data/lib/ibex/ir/migration.rb +0 -120
  461. data/sig/ibex/ir/migration.rbs +0 -34
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require "set"
7
+ require_relative "bits"
8
+ require_relative "inadequacy"
9
+ require_relative "item_lookaheads"
10
+ require_relative "split_stability"
11
+
12
+ # The methods follow the paper's matrix definitions directly.
13
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
14
+
15
+ module Ibex
16
+ module LALR
17
+ module IELR
18
+ # Finds grammar-relative inadequacies and traces their possible
19
+ # manifestations through predecessor states.
20
+ class Annotator
21
+ attr_reader :annotation_lists #: Array[Array[Annotation]]
22
+ attr_reader :inadequacies #: Array[Array[Inadequacy]]
23
+ attr_reader :item_lookaheads #: ItemLookaheads
24
+ attr_reader :split_stable_discarded #: Integer
25
+
26
+ # @rbs (IR::Grammar grammar, Array[core_set] states, transitions transitions,
27
+ # Array[packed_items] items, GotoFollows goto_follows, ?resolver: ConflictResolver?) -> void
28
+ def initialize(grammar, states, transitions, items, goto_follows, resolver: nil)
29
+ @grammar = grammar
30
+ @states = states
31
+ @transitions = transitions
32
+ @items = items
33
+ @goto_follows = goto_follows
34
+ @resolver = resolver || ConflictResolver.new(grammar)
35
+ @kernel_cores = states.map { |state| kernel_items(state) }
36
+ @item_lookaheads = ItemLookaheads.new(
37
+ grammar, goto_follows, @kernel_cores, goto_follows.predecessors,
38
+ start_states: (0...grammar.starts.length).to_a
39
+ )
40
+ @annotation_lists = Array.new(states.length) { [] }
41
+ @keys = Array.new(states.length) { Set.new }
42
+ @inadequacies = Array.new(states.length) { [] }
43
+ @next_id = 0
44
+ @split_stable_discarded = 0
45
+ end
46
+
47
+ # @rbs () -> Array[Array[Annotation]]
48
+ def build
49
+ @states.each_index do |state_id|
50
+ @inadequacies[state_id] = build_inadequacies(state_id)
51
+ @inadequacies.fetch(state_id).each do |inadequacy|
52
+ register?(state_id, annotate_manifestation(state_id, inadequacy))
53
+ end
54
+ end
55
+ worklist = @annotation_lists.each_with_index.flat_map do |annotations, state_id|
56
+ annotations.map { |annotation| [state_id, annotation] }
57
+ end
58
+ cursor = 0
59
+ while cursor < worklist.length
60
+ state_id, annotation = worklist.fetch(cursor)
61
+ cursor += 1
62
+ @goto_follows.predecessors.fetch(state_id).each do |previous|
63
+ derived = annotate_predecessor(previous, state_id, annotation)
64
+ worklist << [previous, derived] if register?(previous, derived)
65
+ end
66
+ end
67
+ @annotation_lists
68
+ end
69
+
70
+ private
71
+
72
+ # @rbs (Integer state_id) -> Array[Inadequacy]
73
+ def build_inadequacies(state_id)
74
+ @grammar.terminals.filter_map do |terminal|
75
+ contributions = contributions_for(state_id, terminal.id)
76
+ next if contributions.length < 2
77
+
78
+ inadequacy = Inadequacy.new(state: state_id, token: terminal.id, contributions: contributions, id: @next_id)
79
+ @next_id += 1
80
+ inadequacy
81
+ end
82
+ end
83
+
84
+ # @rbs (Integer state_id, Integer token_id) -> Array[[Symbol, Integer?]]
85
+ def contributions_for(state_id, token_id)
86
+ reductions = @items.fetch(state_id).filter_map do |(production_id, dot), lookaheads|
87
+ next unless dot == rhs_for(production_id).length && lookaheads.include?(token_id)
88
+
89
+ production_id
90
+ end.sort
91
+ contributions = reductions.select(&:negative?).map { |production_id| [:accept, production_id] }
92
+ symbol = @grammar.symbol_by_id(token_id)
93
+ contributions << [:shift, nil] if symbol&.terminal? && @transitions.fetch(state_id).key?(token_id)
94
+ contributions.concat(reductions.reject(&:negative?).map { |production_id| [:reduce, production_id] })
95
+ contributions
96
+ end
97
+
98
+ # @rbs (Integer state_id, Inadequacy inadequacy) -> Annotation
99
+ def annotate_manifestation(state_id, inadequacy)
100
+ matrix = inadequacy.contributions.map do |kind, production_id|
101
+ next nil if kind == :shift
102
+
103
+ rhs = rhs_for(production_id)
104
+ if rhs.empty?
105
+ compute_lhs_contributions(state_id, lhs_for(production_id), inadequacy.token)
106
+ else
107
+ completed_kernel_mask(state_id, production_id, rhs.length)
108
+ end
109
+ end
110
+ Annotation.new(inadequacy: inadequacy, matrix: matrix)
111
+ end
112
+
113
+ # @rbs (Integer state_id, Integer successor_id, Annotation annotation) -> Annotation
114
+ def annotate_predecessor(state_id, successor_id, annotation)
115
+ token = annotation.inadequacy.token
116
+ cores = @kernel_cores.fetch(successor_id)
117
+ matrix = annotation.matrix.map do |row|
118
+ next nil if row.nil?
119
+ next nil if always_via_lhs?(state_id, cores, row, token)
120
+
121
+ project_row(state_id, cores, row, token)
122
+ end
123
+ Annotation.new(inadequacy: annotation.inadequacy, matrix: matrix)
124
+ end
125
+
126
+ # @rbs (Integer state_id, Array[item_core], Integer, Integer) -> bool
127
+ def always_via_lhs?(state_id, cores, row, token)
128
+ Bits.each_set_bit(row).any? do |index|
129
+ production_id, dot = cores.fetch(index)
130
+ next false unless dot == 1
131
+
132
+ compute_lhs_contributions(state_id, lhs_for(production_id), token).nil?
133
+ end
134
+ end
135
+
136
+ # @rbs (Integer state_id, Array[item_core], Integer, Integer) -> Integer
137
+ def project_row(state_id, cores, row, token)
138
+ Bits.each_set_bit(row).reduce(0) do |mask, index|
139
+ production_id, dot = cores.fetch(index)
140
+ if dot > 1
141
+ previous = kernel_index_of(state_id, production_id, dot - 1)
142
+ next mask unless previous && item_lookaheads.fetch(state_id, previous).anybits?(1 << token)
143
+
144
+ mask | (1 << previous)
145
+ else
146
+ lhs_mask = compute_lhs_contributions(state_id, lhs_for(production_id), token)
147
+ mask | lhs_mask.to_i
148
+ end
149
+ end
150
+ end
151
+
152
+ # @rbs (Integer state_id, Integer production_id, Integer length) -> Integer
153
+ def completed_kernel_mask(state_id, production_id, length)
154
+ index = kernel_index_of(state_id, production_id, length)
155
+ index ? (1 << index) : 0
156
+ end
157
+
158
+ # @rbs (Integer state_id, Integer lhs_id, Integer token_id) -> Integer?
159
+ def compute_lhs_contributions(state_id, lhs_id, token_id)
160
+ goto_id = @goto_follows.goto_for(state_id, lhs_id)
161
+ raise Ibex::Error, "missing goto for #{lhs_id} from #{state_id}" unless goto_id
162
+ return nil if @goto_follows.always_follows.fetch(goto_id).anybits?(1 << token_id)
163
+
164
+ mask = 0
165
+ Bits.each_set_bit(@goto_follows.follow_kernel_items.fetch(goto_id)) do |index|
166
+ mask |= 1 << index if @item_lookaheads.fetch(state_id, index).anybits?(1 << token_id)
167
+ end
168
+ mask
169
+ end
170
+
171
+ # @rbs (Integer state_id, Annotation annotation) -> bool
172
+ def register?(state_id, annotation)
173
+ if SplitStability.split_stable?(annotation, @resolver)
174
+ @split_stable_discarded += 1
175
+ return false
176
+ end
177
+
178
+ key = annotation.key
179
+ return false unless @keys.fetch(state_id).add?(key)
180
+
181
+ @annotation_lists.fetch(state_id) << annotation
182
+ true
183
+ end
184
+
185
+ # @rbs (Integer state_id, Integer production_id) -> Integer
186
+ def lhs_for(production_id)
187
+ return @grammar.symbol(@grammar.starts.fetch(-production_id - 1)).id if production_id.negative?
188
+
189
+ @grammar.productions.fetch(production_id).lhs
190
+ end
191
+
192
+ # @rbs (Integer production_id) -> Array[Integer]
193
+ def rhs_for(production_id)
194
+ return [lhs_for(production_id)] if production_id.negative?
195
+
196
+ @grammar.productions.fetch(production_id).rhs
197
+ end
198
+
199
+ # @rbs (core_set items) -> Array[item_core]
200
+ def kernel_items(items)
201
+ items.select { |production_id, dot| production_id.negative? || dot.positive? }.to_a.sort
202
+ end
203
+
204
+ # @rbs (Integer state_id, Integer production_id, Integer dot) -> Integer?
205
+ def kernel_index_of(state_id, production_id, dot)
206
+ @kernel_cores.fetch(state_id).index([production_id, dot])
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+ # steep:ignore:end
213
+
214
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ module Ibex
7
+ module LALR
8
+ module IELR
9
+ module Bits
10
+ module_function
11
+
12
+ # @rbs (Integer bits) { (Integer) -> void } -> void
13
+ # @rbs (Integer bits) -> Enumerator[Integer, void]
14
+ def each_set_bit(bits)
15
+ return enum_for(:each_set_bit, bits) unless block_given?
16
+
17
+ index = 0
18
+ while bits.positive?
19
+ yield index if bits.odd?
20
+ bits >>= 1
21
+ index += 1
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ # steep:ignore:end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ module Ibex
7
+ module LALR
8
+ module IELR
9
+ # @rbs skip
10
+ Inadequacy = Struct.new(:state, :token, :contributions, :id, keyword_init: true) do
11
+ def initialize(state:, token:, contributions:, id:)
12
+ super(state: state, token: token, contributions: contributions.freeze, id: id)
13
+ freeze
14
+ end
15
+ end
16
+
17
+ # @rbs skip
18
+ Annotation = Struct.new(:inadequacy, :matrix, keyword_init: true) do
19
+ def initialize(inadequacy:, matrix:)
20
+ super(inadequacy: inadequacy, matrix: matrix.freeze)
21
+ freeze
22
+ end
23
+
24
+ def key
25
+ [inadequacy.id, matrix]
26
+ end
27
+ end
28
+
29
+ # @rbs!
30
+ # type contribution = [Symbol, Integer?]
31
+ # class Inadequacy < Struct[Integer | Array[contribution]]
32
+ # attr_accessor state: Integer
33
+ # attr_accessor token: Integer
34
+ # attr_accessor contributions: Array[contribution]
35
+ # attr_accessor id: Integer
36
+ # def self.new: (state: Integer, token: Integer, contributions: Array[contribution], id: Integer) -> instance
37
+ # end
38
+ # class Annotation < Struct[Inadequacy | Array[Integer?]]
39
+ # attr_accessor inadequacy: Inadequacy
40
+ # attr_accessor matrix: Array[Integer?]
41
+ # def self.new: (inadequacy: Inadequacy, matrix: Array[Integer?]) -> instance
42
+ # def key: () -> [Integer, Array[Integer?]]
43
+ # end
44
+ end
45
+ end
46
+ end
47
+ # steep:ignore:end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require_relative "bits"
7
+
8
+ module Ibex
9
+ module LALR
10
+ module IELR
11
+ # Lazily derives the lookahead of a kernel item from predecessor states
12
+ # and goto-follow sets. Memoisation is important: predecessor paths can
13
+ # share exponentially many suffixes in a real grammar.
14
+ class ItemLookaheads
15
+ # @rbs @memo: Hash[Integer, Integer]
16
+
17
+ # @rbs (IR::Grammar grammar, GotoFollows goto_follows, Array[Array[item_core]] kernel_cores,
18
+ # Array[Array[Integer]] predecessors, ?start_states: Array[Integer]?) -> void
19
+ def initialize(grammar, goto_follows, kernel_cores, predecessors, start_states: nil)
20
+ @grammar = grammar
21
+ @goto_follows = goto_follows
22
+ @kernel_cores = kernel_cores
23
+ @predecessors = predecessors
24
+ @start_states = start_states || []
25
+ @index = {}
26
+ kernel_cores.each_with_index do |cores, state_id|
27
+ cores.each_with_index { |core, kernel_index| @index[[state_id, core]] = kernel_index }
28
+ end
29
+ @memo = {}
30
+ end
31
+
32
+ # @rbs (Integer state_id, Integer kernel_index) -> Integer
33
+ def fetch(state_id, kernel_index)
34
+ key = [state_id, kernel_index]
35
+ return @memo.fetch(key) if @memo.key?(key)
36
+
37
+ @memo[key] = compute(state_id, kernel_index)
38
+ end
39
+
40
+ # @rbs () -> Integer
41
+ def size
42
+ @memo.length
43
+ end
44
+
45
+ private
46
+
47
+ # @rbs (Integer state_id, Integer kernel_index) -> Integer
48
+ def compute(state_id, kernel_index)
49
+ production_id, dot = @kernel_cores.fetch(state_id).fetch(kernel_index)
50
+ return start_seed(production_id) if production_id.negative? && dot.zero?
51
+ return start_seed(production_id) if production_id.negative? && dot.positive?
52
+ return 0 if dot.zero?
53
+ return goto_follows_for(state_id, production_id) if dot == 1
54
+
55
+ @predecessors.fetch(state_id).reduce(0) do |bits, previous|
56
+ previous_index = @index[[previous, [production_id, dot - 1]]]
57
+ previous_index ? bits | fetch(previous, previous_index) : bits
58
+ end
59
+ end
60
+
61
+ # @rbs (Integer state_id, Integer production_id) -> Integer
62
+ def goto_follows_for(state_id, production_id)
63
+ lhs = @grammar.productions.fetch(production_id).lhs
64
+ @predecessors.fetch(state_id).reduce(0) do |bits, previous|
65
+ goto_id = @goto_follows.goto_for(previous, lhs)
66
+ bits | (goto_id ? @goto_follows.goto_follows.fetch(goto_id) : 0)
67
+ end
68
+ end
69
+
70
+ # @rbs (Integer production_id) -> Integer
71
+ def start_seed(production_id)
72
+ production_id.negative? ? 1 : 0
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ # steep:ignore:end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require_relative "../lr0_collection"
7
+ require_relative "../goto_follows"
8
+ require_relative "../lookahead_propagation"
9
+ require_relative "state_splitter"
10
+
11
+ # The method follows the fixed six-phase pipeline as one transaction.
12
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
+
14
+ module Ibex
15
+ module LALR
16
+ module IELR
17
+ # Coordinates the canonical-free direct IELR phases. The returned
18
+ # profile deliberately reports canonical metrics as unavailable.
19
+ class Pipeline
20
+ # @rbs (IR::Grammar grammar, Analysis::Sets sets, ?starts: Array[String]?, ?profile: bool) -> void
21
+ def initialize(grammar, sets, starts: nil, profile: false)
22
+ @grammar = grammar
23
+ @sets = sets
24
+ @starts = starts || grammar.starts
25
+ @profile = profile
26
+ end
27
+
28
+ # @rbs () -> [Array[packed_items], transitions, LALR::build_collection]
29
+ def build
30
+ states, transitions = LR0Collection.new(@grammar, starts: @starts).build
31
+ seeds = @starts.each_with_index.map do |name, index|
32
+ augmented = -1 - @grammar.starts.index(name)
33
+ [index, [augmented, 0], 0]
34
+ end
35
+ initial_propagation = LookaheadPropagation.new(
36
+ @grammar, @sets, states, transitions, seeds: seeds
37
+ )
38
+ items = initial_propagation.build
39
+ goto_follows = GotoFollows.new(
40
+ @grammar, @sets, states, transitions, @starts.each_index.to_a, start_names: @starts
41
+ )
42
+ splitter = StateSplitter.new(@grammar, states, transitions, items, goto_follows)
43
+ _split_items, split_transitions = splitter.build
44
+ split_states = splitter.states.map { |state| states.fetch(state.lalr_isocore) }
45
+ phase4_items = LookaheadPropagation.new(
46
+ @grammar, @sets, split_states, split_transitions, seeds: seeds
47
+ ).build
48
+ profile = {
49
+ construction_states: phase4_items.length,
50
+ canonical_states: nil,
51
+ strategy: :ielr_direct,
52
+ lr0_states: @profile ? states.length : nil,
53
+ lr0_items: @profile ? states.sum(&:length) : nil,
54
+ canonical_items: nil,
55
+ propagation_edges: @profile ? initial_propagation.propagation_edge_count : nil,
56
+ ielr_initial_partitions: nil,
57
+ ielr_final_partitions: nil,
58
+ ielr_annotations: splitter.annotations.sum(&:length),
59
+ ielr_annotated_states: splitter.annotations.count { |entries| !entries.empty? },
60
+ ielr_inadequacies: splitter.inadequacies.sum(&:length),
61
+ ielr_split_stable_discarded: splitter.split_stable_discarded,
62
+ ielr_lalr_states: states.length,
63
+ ielr_split_states: splitter.split_states,
64
+ ielr_unreachable_removed: 0,
65
+ ielr_remergeable_candidates: nil
66
+ }
67
+ [phase4_items, split_transitions, profile]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ # steep:ignore:end
74
+
75
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require_relative "bits"
7
+
8
+ module Ibex
9
+ module LALR
10
+ module IELR
11
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12
+ module SplitStability
13
+ MAX_ENUMERATED_POTENTIALS = 12
14
+
15
+ module_function
16
+
17
+ # @rbs (Annotation) -> bool
18
+ def simple?(annotation)
19
+ annotation.matrix.all? { |row| row.nil? || row.zero? }
20
+ end
21
+
22
+ # @rbs (Annotation, ConflictResolver) -> bool
23
+ def split_stable?(annotation, resolver)
24
+ return true if simple?(annotation)
25
+
26
+ contributions = annotation.inadequacy.contributions
27
+ kept = contributions.each_index.reject { |index| annotation.matrix[index]&.zero? }
28
+ return true if kept.empty?
29
+
30
+ potential = kept.reject { |index| annotation.matrix[index].nil? }
31
+ return false if potential.length > MAX_ENUMERATED_POTENTIALS
32
+
33
+ base = resolve(resolver, annotation.inadequacy.token, kept.map { |index| contributions[index] })
34
+ subsets(potential).all? do |removed|
35
+ remaining = kept.reject { |index| removed.include?(index) }
36
+ remaining.empty? || resolve(resolver, annotation.inadequacy.token,
37
+ remaining.map { |index| contributions[index] }) == base
38
+ end
39
+ end
40
+
41
+ # @rbs (ConflictResolver, Integer, Array[Object]) -> Object?
42
+ def resolve(resolver, token, contributions)
43
+ actions = contributions.map do |kind, production_id|
44
+ case kind
45
+ when :shift then { type: :shift, state: 0 }
46
+ when :reduce then { type: :reduce, production: production_id }
47
+ when :accept then { type: :accept }
48
+ when :error then { type: :error }
49
+ else raise Ibex::Error, "unknown IELR contribution #{kind.inspect}"
50
+ end
51
+ end
52
+ action, = resolver.resolve(token, actions)
53
+ normalize(action)
54
+ end
55
+
56
+ # @rbs (Object?) -> Object?
57
+ def normalize(action)
58
+ return nil unless action
59
+ return [:shift] if action[:type] == :shift
60
+ return [:reduce, action[:production]] if action[:type] == :reduce
61
+ return [:accept] if action[:type] == :accept
62
+ return [:error] if action[:type] == :error
63
+
64
+ action
65
+ end
66
+
67
+ # @rbs (Array[Integer]) -> Array[Array[Integer]]
68
+ def subsets(values)
69
+ (0...(1 << values.length)).map do |bits|
70
+ values.each_index.filter_map { |index| values.fetch(index) if bits.anybits?(1 << index) }
71
+ end
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
75
+ end
76
+ end
77
+ end
78
+ # steep:ignore:end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module LALR
6
+ module IELR
7
+ # @rbs skip
8
+ SplitState = Struct.new(:core, :transitions, :lalr_isocore, keyword_init: true)
9
+
10
+ # @rbs!
11
+ # class SplitState < Struct[Array[item_core] | Array[[Integer, Integer]] | Integer]
12
+ # attr_accessor core: Array[item_core]
13
+ # attr_accessor transitions: Array[[Integer, Integer]]
14
+ # attr_accessor lalr_isocore: Integer
15
+ # def self.new: (core: Array[item_core], transitions: Array[[Integer, Integer]],
16
+ # lalr_isocore: Integer) -> instance
17
+ # end
18
+ end
19
+ end
20
+ end