ibex 0.2.0 → 0.3.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 (437) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +95 -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 +262 -0
  40. data/docs/development.md +179 -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 +1581 -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/ja/bison-import.md +51 -0
  56. data/docs/ja/stable-api.md +53 -0
  57. data/docs/lexer-construction-profile.md +109 -0
  58. data/docs/lexer-migration.md +5 -0
  59. data/docs/maturity.md +128 -0
  60. data/docs/project-site-strategy.md +54 -0
  61. data/docs/racc-migration-evidence.md +45 -0
  62. data/docs/racc-migration.md +11 -0
  63. data/docs/release-readiness.md +126 -68
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +144 -34
  67. data/docs/status.md +43 -0
  68. data/docs/syntax-sessions.md +183 -0
  69. data/docs/table-artifact.md +125 -0
  70. data/docs/test-interactions.md +219 -0
  71. data/docs/verification-report.md +137 -0
  72. data/docs/verifier-trust-boundary.md +199 -0
  73. data/docs/workloads.md +132 -0
  74. data/lib/ibex/analysis/digraph.rb +128 -0
  75. data/lib/ibex/analysis.rb +1 -0
  76. data/lib/ibex/bison_import/importer.rb +516 -0
  77. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  78. data/lib/ibex/bison_import.rb +200 -0
  79. data/lib/ibex/bounded_subprocess.rb +171 -0
  80. data/lib/ibex/cli/ambiguity.rb +14 -5
  81. data/lib/ibex/cli/analysis.rb +134 -0
  82. data/lib/ibex/cli/bison_import.rb +121 -0
  83. data/lib/ibex/cli/config.rb +128 -0
  84. data/lib/ibex/cli/diagnostics.rb +31 -11
  85. data/lib/ibex/cli/documentation.rb +11 -8
  86. data/lib/ibex/cli/equiv.rb +169 -0
  87. data/lib/ibex/cli/error_messages.rb +11 -4
  88. data/lib/ibex/cli/explain.rb +14 -5
  89. data/lib/ibex/cli/fix.rb +203 -0
  90. data/lib/ibex/cli/formatting.rb +11 -10
  91. data/lib/ibex/cli/fuzz.rb +200 -0
  92. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  93. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  94. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  95. data/lib/ibex/cli/grammar_tests.rb +32 -14
  96. data/lib/ibex/cli/ir_tools.rb +5 -61
  97. data/lib/ibex/cli/outputs.rb +60 -33
  98. data/lib/ibex/cli/reduce.rb +202 -0
  99. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  100. data/lib/ibex/cli/samples.rb +49 -23
  101. data/lib/ibex/cli/verify.rb +116 -0
  102. data/lib/ibex/cli/watch.rb +6 -5
  103. data/lib/ibex/cli.rb +357 -56
  104. data/lib/ibex/codegen/action_locations.rb +1 -1
  105. data/lib/ibex/codegen/action_method_source.rb +5 -6
  106. data/lib/ibex/codegen/action_source.rb +3 -2
  107. data/lib/ibex/codegen/ambiguity.rb +5 -4
  108. data/lib/ibex/codegen/explain.rb +123 -55
  109. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  110. data/lib/ibex/codegen/rbs.rb +15 -7
  111. data/lib/ibex/codegen/report.rb +25 -13
  112. data/lib/ibex/codegen/ruby.rb +28 -64
  113. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  114. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  115. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  116. data/lib/ibex/configuration/explanation.rb +421 -0
  117. data/lib/ibex/configuration/inspector.rb +232 -0
  118. data/lib/ibex/configuration.rb +580 -0
  119. data/lib/ibex/coverage/collector.rb +21 -11
  120. data/lib/ibex/coverage/event_stream.rb +13 -7
  121. data/lib/ibex/coverage/report.rb +26 -18
  122. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  123. data/lib/ibex/delta_reducer.rb +99 -0
  124. data/lib/ibex/diff.rb +140 -0
  125. data/lib/ibex/equiv/machine.rb +135 -0
  126. data/lib/ibex/equiv.rb +373 -0
  127. data/lib/ibex/fix.rb +557 -0
  128. data/lib/ibex/frontend/ast.rb +22 -2
  129. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  130. data/lib/ibex/frontend/diagnostic.rb +1 -1
  131. data/lib/ibex/frontend/formatter.rb +72 -26
  132. data/lib/ibex/frontend/generated_parser.rb +147 -117
  133. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  134. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  135. data/lib/ibex/frontend/generation.rb +1 -1
  136. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  137. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  138. data/lib/ibex/frontend/regenerator.rb +1 -0
  139. data/lib/ibex/frontend/resolution.rb +2 -1
  140. data/lib/ibex/frontend/resolver.rb +1 -1
  141. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  142. data/lib/ibex/frontend/source_cursor.rb +2 -2
  143. data/lib/ibex/frontend/source_span.rb +9 -1
  144. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  145. data/lib/ibex/frontend/token_adapter.rb +10 -0
  146. data/lib/ibex/frontend.rb +1 -0
  147. data/lib/ibex/fuzz.rb +219 -0
  148. data/lib/ibex/generation_input.rb +1 -1
  149. data/lib/ibex/generation_manifest.rb +36 -25
  150. data/lib/ibex/generation_transaction.rb +1 -1
  151. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  152. data/lib/ibex/generation_transaction_validation.rb +2 -2
  153. data/lib/ibex/grammar_tests.rb +1 -1
  154. data/lib/ibex/ir/automaton_ir.rb +61 -19
  155. data/lib/ibex/ir/grammar_ir.rb +76 -45
  156. data/lib/ibex/ir/lexer_ir.rb +5 -5
  157. data/lib/ibex/ir/parser_contract.rb +135 -0
  158. data/lib/ibex/ir/serialize.rb +203 -76
  159. data/lib/ibex/ir/validator/automaton.rb +64 -34
  160. data/lib/ibex/ir/validator/base.rb +51 -33
  161. data/lib/ibex/ir/validator/grammar.rb +113 -83
  162. data/lib/ibex/ir/validator/lexer.rb +2 -2
  163. data/lib/ibex/ir/validator.rb +2 -1
  164. data/lib/ibex/ir.rb +16 -3
  165. data/lib/ibex/lalr/build_metrics.rb +50 -2
  166. data/lib/ibex/lalr/builder.rb +191 -56
  167. data/lib/ibex/lalr/conflict_search.rb +15 -4
  168. data/lib/ibex/lalr/counterexample.rb +19 -14
  169. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  170. data/lib/ibex/lalr/goto_follows.rb +229 -0
  171. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  172. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  173. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  174. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  175. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  176. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  177. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  178. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  179. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  180. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  181. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  182. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  183. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  184. data/lib/ibex/lalr.rb +52 -1
  185. data/lib/ibex/location.rb +3 -3
  186. data/lib/ibex/lsp/document_handlers.rb +9 -7
  187. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  188. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  189. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  190. data/lib/ibex/lsp/position_codec.rb +6 -2
  191. data/lib/ibex/lsp/request_handlers.rb +3 -2
  192. data/lib/ibex/lsp/request_support.rb +14 -7
  193. data/lib/ibex/lsp/server.rb +13 -11
  194. data/lib/ibex/lsp/symbol_index.rb +13 -13
  195. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  196. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  197. data/lib/ibex/lsp/transport.rb +13 -3
  198. data/lib/ibex/lsp/workspace.rb +5 -4
  199. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  200. data/lib/ibex/lsp.rb +1 -0
  201. data/lib/ibex/messages/en.yml +28 -0
  202. data/lib/ibex/messages/ja.yml +28 -0
  203. data/lib/ibex/messages.rb +68 -0
  204. data/lib/ibex/metrics.rb +175 -0
  205. data/lib/ibex/normalize/declarations.rb +2 -0
  206. data/lib/ibex/normalize/diagnostics.rb +63 -38
  207. data/lib/ibex/normalize/expander.rb +5 -4
  208. data/lib/ibex/normalize/expression.rb +8 -6
  209. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  210. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  211. data/lib/ibex/normalize/lexer.rb +3 -3
  212. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  213. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  214. data/lib/ibex/normalize/parameters.rb +31 -4
  215. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  216. data/lib/ibex/normalize.rb +10 -20
  217. data/lib/ibex/racc_migration/report.rb +6 -3
  218. data/lib/ibex/rake_task.rb +1 -1
  219. data/lib/ibex/samples.rb +43 -13
  220. data/lib/ibex/table_artifact/builder.rb +266 -0
  221. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  222. data/lib/ibex/table_artifact/document.rb +39 -0
  223. data/lib/ibex/table_artifact/executor.rb +187 -0
  224. data/lib/ibex/table_artifact/serializer.rb +57 -0
  225. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  226. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  227. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  228. data/lib/ibex/table_artifact/validator.rb +253 -0
  229. data/lib/ibex/table_artifact.rb +88 -0
  230. data/lib/ibex/table_simulation/result.rb +6 -2
  231. data/lib/ibex/table_simulation/step.rb +3 -1
  232. data/lib/ibex/tables.rb +14 -0
  233. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  234. data/lib/ibex/verification_report/builder.rb +159 -0
  235. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  236. data/lib/ibex/verification_report/logical_path.rb +68 -0
  237. data/lib/ibex/verification_report/validator.rb +329 -0
  238. data/lib/ibex/verification_report.rb +69 -0
  239. data/lib/ibex/verify/action_correspondence.rb +138 -0
  240. data/lib/ibex/verify/language_witness.rb +295 -0
  241. data/lib/ibex/verify/reference_collection.rb +190 -0
  242. data/lib/ibex/verify/result.rb +73 -0
  243. data/lib/ibex/verify/verifier.rb +598 -0
  244. data/lib/ibex/verify.rb +15 -0
  245. data/lib/ibex/version.rb +1 -1
  246. data/lib/ibex/watch/runner.rb +10 -1
  247. data/lib/ibex/watch/source_snapshot.rb +13 -8
  248. data/lib/ibex.rb +10 -0
  249. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  250. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  251. data/schema/bison-import-v1.schema.json +106 -0
  252. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  253. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  254. data/schema/construction-profile-v1.schema.json +779 -0
  255. data/schema/diff-v1.schema.json +41 -0
  256. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  257. data/schema/equiv-v1.schema.json +64 -0
  258. data/schema/error-ux-review-v1.schema.json +609 -0
  259. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  260. data/schema/error-ux-round2-v1.schema.json +519 -0
  261. data/schema/explain-v1.schema.json +63 -1
  262. data/schema/fix-v1.schema.json +64 -0
  263. data/schema/fix-v2.schema.json +66 -0
  264. data/schema/fix-v3.schema.json +101 -0
  265. data/schema/fuzz-regression-v1.schema.json +79 -0
  266. data/schema/fuzz-v1.schema.json +114 -0
  267. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  268. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  269. data/schema/grammar-ir.schema.json +271 -0
  270. data/schema/ielr-benchmark-v1.schema.json +85 -0
  271. data/schema/lexer-profile-v1.schema.json +491 -0
  272. data/schema/metrics-v1.schema.json +60 -0
  273. data/schema/reduce-v1.schema.json +22 -0
  274. data/schema/reduce-v2.schema.json +63 -0
  275. data/schema/table-artifact-v1.schema.json +377 -0
  276. data/schema/verification-report-v1.schema.json +222 -0
  277. data/schema/verify-v1.schema.json +42 -0
  278. data/sig/ibex/analysis/digraph.rbs +19 -0
  279. data/sig/ibex/bison_import/importer.rbs +140 -0
  280. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  281. data/sig/ibex/bison_import.rbs +95 -0
  282. data/sig/ibex/bounded_subprocess.rbs +76 -0
  283. data/sig/ibex/cli/ambiguity.rbs +6 -0
  284. data/sig/ibex/cli/analysis.rbs +43 -0
  285. data/sig/ibex/cli/bison_import.rbs +32 -0
  286. data/sig/ibex/cli/config.rbs +35 -0
  287. data/sig/ibex/cli/diagnostics.rbs +16 -3
  288. data/sig/ibex/cli/documentation.rbs +5 -1
  289. data/sig/ibex/cli/equiv.rbs +49 -0
  290. data/sig/ibex/cli/error_messages.rbs +6 -0
  291. data/sig/ibex/cli/explain.rbs +6 -0
  292. data/sig/ibex/cli/fix.rbs +53 -0
  293. data/sig/ibex/cli/formatting.rbs +5 -1
  294. data/sig/ibex/cli/fuzz.rbs +47 -0
  295. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  296. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  297. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  298. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  299. data/sig/ibex/cli/ir_tools.rbs +7 -19
  300. data/sig/ibex/cli/outputs.rbs +9 -3
  301. data/sig/ibex/cli/reduce.rbs +60 -0
  302. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  303. data/sig/ibex/cli/samples.rbs +8 -0
  304. data/sig/ibex/cli/verify.rbs +28 -0
  305. data/sig/ibex/cli/watch.rbs +2 -2
  306. data/sig/ibex/cli.rbs +79 -5
  307. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  308. data/sig/ibex/codegen/explain.rbs +45 -25
  309. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  310. data/sig/ibex/codegen/rbs.rbs +12 -10
  311. data/sig/ibex/codegen/report.rbs +12 -12
  312. data/sig/ibex/codegen/ruby.rbs +18 -15
  313. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  314. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  315. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  316. data/sig/ibex/configuration/explanation.rbs +195 -0
  317. data/sig/ibex/configuration/inspector.rbs +53 -0
  318. data/sig/ibex/configuration.rbs +242 -0
  319. data/sig/ibex/coverage/collector.rbs +16 -14
  320. data/sig/ibex/coverage/event_stream.rbs +12 -10
  321. data/sig/ibex/coverage/report.rbs +20 -18
  322. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  323. data/sig/ibex/delta_reducer.rbs +38 -0
  324. data/sig/ibex/diff.rbs +47 -0
  325. data/sig/ibex/equiv/machine.rbs +54 -0
  326. data/sig/ibex/equiv.rbs +129 -0
  327. data/sig/ibex/fix.rbs +138 -0
  328. data/sig/ibex/frontend/ast.rbs +33 -7
  329. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  330. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  331. data/sig/ibex/frontend/formatter.rbs +38 -30
  332. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  333. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  334. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  335. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  336. data/sig/ibex/frontend/resolution.rbs +3 -2
  337. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  338. data/sig/ibex/frontend/source_span.rbs +5 -2
  339. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  340. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  341. data/sig/ibex/fuzz.rbs +71 -0
  342. data/sig/ibex/generation_input.rbs +2 -2
  343. data/sig/ibex/generation_manifest.rbs +35 -32
  344. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  345. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  346. data/sig/ibex/grammar_tests.rbs +2 -2
  347. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  348. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  349. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  350. data/sig/ibex/ir/parser_contract.rbs +69 -0
  351. data/sig/ibex/ir/serialize.rbs +63 -28
  352. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  353. data/sig/ibex/ir/validator/base.rbs +35 -31
  354. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  355. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  356. data/sig/ibex/ir.rbs +9 -3
  357. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  358. data/sig/ibex/lalr/builder.rbs +75 -24
  359. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  360. data/sig/ibex/lalr/counterexample.rbs +17 -14
  361. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  362. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  363. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  364. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  365. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  366. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  367. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  368. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  369. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  370. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  371. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  372. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  373. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  374. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  375. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  376. data/sig/ibex/lalr.rbs +11 -1
  377. data/sig/ibex/location.rbs +6 -6
  378. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  379. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  380. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  381. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  382. data/sig/ibex/lsp/position_codec.rbs +8 -4
  383. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  384. data/sig/ibex/lsp/request_support.rbs +8 -8
  385. data/sig/ibex/lsp/server.rbs +16 -16
  386. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  387. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  388. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  389. data/sig/ibex/lsp/transport.rbs +18 -6
  390. data/sig/ibex/lsp/workspace.rbs +3 -2
  391. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  392. data/sig/ibex/messages.rbs +26 -0
  393. data/sig/ibex/metrics.rbs +50 -0
  394. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  395. data/sig/ibex/normalize/expander.rbs +2 -2
  396. data/sig/ibex/normalize/expression.rbs +10 -8
  397. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  398. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  399. data/sig/ibex/normalize/lexer.rbs +4 -4
  400. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  401. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  402. data/sig/ibex/normalize/parameters.rbs +13 -8
  403. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  404. data/sig/ibex/normalize.rbs +11 -5
  405. data/sig/ibex/racc_migration/report.rbs +8 -6
  406. data/sig/ibex/rake_task.rbs +1 -1
  407. data/sig/ibex/samples.rbs +13 -4
  408. data/sig/ibex/table_artifact/builder.rbs +93 -0
  409. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  410. data/sig/ibex/table_artifact/document.rbs +27 -0
  411. data/sig/ibex/table_artifact/executor.rbs +66 -0
  412. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  413. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  414. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  415. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  416. data/sig/ibex/table_artifact/validator.rbs +66 -0
  417. data/sig/ibex/table_artifact.rbs +32 -0
  418. data/sig/ibex/table_simulation/result.rbs +8 -4
  419. data/sig/ibex/table_simulation/step.rbs +4 -2
  420. data/sig/ibex/tables.rbs +10 -9
  421. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  422. data/sig/ibex/verification_report/builder.rbs +53 -0
  423. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  424. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  425. data/sig/ibex/verification_report/validator.rbs +114 -0
  426. data/sig/ibex/verification_report.rbs +44 -0
  427. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  428. data/sig/ibex/verify/language_witness.rbs +112 -0
  429. data/sig/ibex/verify/reference_collection.rbs +63 -0
  430. data/sig/ibex/verify/result.rbs +52 -0
  431. data/sig/ibex/verify/verifier.rbs +170 -0
  432. data/sig/ibex/verify.rbs +6 -0
  433. data/sig/ibex/watch/runner.rbs +12 -2
  434. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  435. metadata +232 -12
  436. data/lib/ibex/ir/migration.rb +0 -120
  437. data/sig/ibex/ir/migration.rbs +0 -34
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
-
5
3
  module Ibex
6
4
  # Static grammar diagnostics used by Normalizer.
7
5
  module NormalizeDiagnostics
@@ -22,10 +20,13 @@ module Ibex
22
20
  # @rbs () -> void
23
21
  def validate_symbol_metadata
24
22
  # @type self: Normalizer
25
- { display: @display_name_locations, type: @semantic_type_locations }.each do |label, locations|
23
+ display_locations = @display_name_locations #: Hash[String, IR::location]
24
+ semantic_locations = @semantic_type_locations #: Hash[String, IR::location]
25
+ inline_rule_names = @inline_rule_names #: Set[String]
26
+ { display: display_locations, type: semantic_locations }.each do |label, locations|
26
27
  locations.each do |name, location|
27
28
  fail_hash(location, "#{label} declaration references undefined symbol #{name}") unless
28
- symbol(name) || parameter_template?(name) || (label == :type && @inline_rule_names.include?(name))
29
+ symbol(name) || parameter_template?(name) || (label == :type && inline_rule_names.include?(name))
29
30
  end
30
31
  end
31
32
  end
@@ -33,12 +34,15 @@ module Ibex
33
34
  # @rbs () -> void
34
35
  def warn_duplicate_productions
35
36
  # @type self: Normalizer
37
+ productions = @productions #: Array[IR::Production]
38
+ warnings = @warnings #: Array[IR::grammar_warning]
36
39
  seen = {} #: Hash[[Integer, Array[Integer]], Integer]
37
- @productions.each do |production|
40
+ productions.each do |production|
38
41
  signature = [production.lhs, production.rhs] #: [Integer, Array[Integer]]
39
42
  if seen.key?(signature)
40
- @warnings << { type: :duplicate_production, production: production.id, original: seen[signature],
41
- loc: production.origin[:loc] }
43
+ location = production.origin[:loc] #: IR::location?
44
+ warnings << { type: :duplicate_production, production: production.id, original: seen[signature],
45
+ loc: location }
42
46
  else
43
47
  seen[signature] = production.id
44
48
  end
@@ -48,23 +52,27 @@ module Ibex
48
52
  # @rbs () -> void
49
53
  def warn_unreachable_nonterminals
50
54
  # @type self: Normalizer
55
+ symbols = @symbols #: Array[IR::GrammarSymbol]
56
+ warnings = @warnings #: Array[IR::grammar_warning]
51
57
  reachable = reachable_symbol_ids
52
- @symbols.select(&:nonterminal?).each do |grammar_symbol|
53
- next if reachable.include?(grammar_symbol.id) || grammar_symbol.name.start_with?("$")
58
+ symbols.select(&:nonterminal?).each do |grammar_symbol|
59
+ next if reachable.key?(grammar_symbol.id) || grammar_symbol.name.start_with?("$")
54
60
 
55
- @warnings << { type: :unreachable_nonterminal, symbol: grammar_symbol.name, loc: grammar_symbol.location }
61
+ warnings << { type: :unreachable_nonterminal, symbol: grammar_symbol.name, loc: grammar_symbol.location }
56
62
  end
57
63
  end
58
64
 
59
- # @rbs () -> Set[Integer]
65
+ # @rbs () -> Hash[Integer, true]
60
66
  def reachable_symbol_ids
61
67
  # @type self: Normalizer
62
- starts = @start_names.map { |name| required_symbol(name).id }
63
- reachable = Set.new(starts)
68
+ start_names = @start_names #: Array[String]
69
+ productions = @productions #: Array[IR::Production]
70
+ starts = start_names.map { |name| required_symbol(name).id }
71
+ reachable = starts.to_h { |id| [id, true] } #: Hash[Integer, true]
64
72
  loop do
65
73
  before = reachable.length
66
- @productions.select { |production| reachable.include?(production.lhs) }.each do |production|
67
- production.rhs.each { |id| reachable << id }
74
+ productions.select { |production| reachable.key?(production.lhs) }.each do |production|
75
+ production.rhs.each { |id| reachable[id] = true }
68
76
  end
69
77
  return reachable if reachable.length == before
70
78
  end
@@ -73,66 +81,83 @@ module Ibex
73
81
  # @rbs () -> void
74
82
  def warn_unused_terminals
75
83
  # @type self: Normalizer
76
- used = @productions.flat_map(&:rhs).to_set
77
- @symbols.select(&:terminal?).each do |grammar_symbol|
78
- next if grammar_symbol.reserved || used.include?(grammar_symbol.id) || @precedence.key?(grammar_symbol.name)
79
-
80
- @warnings << { type: :unused_terminal, symbol: grammar_symbol.name, loc: grammar_symbol.location }
84
+ productions = @productions #: Array[IR::Production]
85
+ symbols = @symbols #: Array[IR::GrammarSymbol]
86
+ precedence = @precedence #: Hash[String, IR::precedence]
87
+ warnings = @warnings #: Array[IR::grammar_warning]
88
+ used = productions.flat_map(&:rhs).to_h { |id| [id, true] } #: Hash[Integer, true]
89
+ symbols.select(&:terminal?).each do |grammar_symbol|
90
+ next if grammar_symbol.reserved || used.key?(grammar_symbol.id) || precedence.key?(grammar_symbol.name)
91
+
92
+ warnings << { type: :unused_terminal, symbol: grammar_symbol.name, loc: grammar_symbol.location }
81
93
  end
82
94
  end
83
95
 
84
96
  # @rbs () -> void
85
97
  def warn_unreachable_terminals
86
98
  # @type self: Normalizer
99
+ productions = @productions #: Array[IR::Production]
100
+ declared_tokens = @declared_tokens #: Hash[String, IR::location]
101
+ warnings = @warnings #: Array[IR::grammar_warning]
87
102
  reachable = reachable_symbol_ids
88
- used = @productions.flat_map(&:rhs).to_set
89
- @declared_tokens.each_key do |name|
103
+ used = productions.flat_map(&:rhs).to_h { |id| [id, true] } #: Hash[Integer, true]
104
+ declared_tokens.each_key do |name|
90
105
  grammar_symbol = required_symbol(name)
91
- next unless used.include?(grammar_symbol.id)
92
- next if reachable.include?(grammar_symbol.id)
106
+ next unless used.key?(grammar_symbol.id)
107
+ next if reachable.key?(grammar_symbol.id)
93
108
 
94
- @warnings << { type: :unreachable_terminal, symbol: name, loc: @declared_tokens[name] }
109
+ warnings << { type: :unreachable_terminal, symbol: name, loc: declared_tokens[name] }
95
110
  end
96
111
  end
97
112
 
98
113
  # @rbs () -> void
99
114
  def warn_unused_precedence
100
115
  # @type self: Normalizer
101
- referenced = @productions.each_with_object(Set.new) do |production, symbol_ids|
102
- production.rhs.each { |id| symbol_ids << id }
103
- symbol_ids << production.precedence_override if production.precedence_override
116
+ productions = @productions #: Array[IR::Production]
117
+ precedence = @precedence #: Hash[String, IR::precedence]
118
+ precedence_locations = @precedence_locations #: Hash[String, IR::location]
119
+ warnings = @warnings #: Array[IR::grammar_warning]
120
+ referenced = {} # @type var referenced: Hash[Integer, true]
121
+ productions.each do |production|
122
+ symbol_ids = referenced
123
+ production.rhs.each { |id| symbol_ids[id] = true }
124
+ symbol_ids[production.precedence_override] = true if production.precedence_override
104
125
  end
105
- @precedence.each_key do |name|
126
+ precedence.each_key do |name|
106
127
  grammar_symbol = required_symbol(name)
107
- next if referenced.include?(grammar_symbol.id)
128
+ next if referenced.key?(grammar_symbol.id)
108
129
 
109
- @warnings << { type: :unused_precedence, symbol: name, loc: @precedence_locations[name] }
130
+ warnings << { type: :unused_precedence, symbol: name, loc: precedence_locations[name] }
110
131
  end
111
132
  end
112
133
 
113
134
  # @rbs () -> void
114
135
  def warn_empty_language
115
136
  # @type self: Normalizer
137
+ productions = @productions #: Array[IR::Production]
138
+ start_names = @start_names #: Array[String]
139
+ warnings = @warnings #: Array[IR::grammar_warning]
116
140
  productive = productive_terminal_ids
117
141
  loop do
118
142
  before = productive.length
119
- @productions.each do |production|
120
- productive << production.lhs if production.rhs.all? { |id| productive.include?(id) }
143
+ productions.each do |production|
144
+ productive[production.lhs] = true if production.rhs.all? { |id| productive.key?(id) }
121
145
  end
122
146
  break if productive.length == before
123
147
  end
124
- @start_names.each do |name|
125
- next if productive.include?(required_symbol(name).id)
148
+ start_names.each do |name|
149
+ next if productive.key?(required_symbol(name).id)
126
150
 
127
151
  start_symbol = required_symbol(name)
128
- @warnings << { type: :empty_language, symbol: name, loc: start_symbol.location }
152
+ warnings << { type: :empty_language, symbol: name, loc: start_symbol.location }
129
153
  end
130
154
  end
131
155
 
132
- # @rbs () -> Set[Integer]
156
+ # @rbs () -> Hash[Integer, true]
133
157
  def productive_terminal_ids
134
158
  # @type self: Normalizer
135
- @symbols.select { |grammar_symbol| productive_terminal?(grammar_symbol) }.to_set(&:id)
159
+ symbols = @symbols #: Array[IR::GrammarSymbol]
160
+ symbols.select { |grammar_symbol| productive_terminal?(grammar_symbol) }.to_h { |symbol| [symbol.id, true] }
136
161
  end
137
162
 
138
163
  # @rbs (IR::GrammarSymbol grammar_symbol) -> bool
@@ -192,7 +192,7 @@ module Ibex
192
192
  IR::Action.new(code: code, location: location.to_h)
193
193
  end
194
194
 
195
- # @rbs (Symbol kind, Frontend::AST::item item) -> Hash[Symbol, untyped]
195
+ # @rbs (Symbol kind, Frontend::AST::item item) -> Hash[Symbol, Object?]
196
196
  def synthetic_origin(kind, item)
197
197
  # @type self: Normalizer
198
198
  { kind: :"#{kind}_expansion", expression: NormalizeExpression.render(item), loc: item.loc.to_h }
@@ -210,10 +210,11 @@ module Ibex
210
210
  # Hash[Symbol, untyped] origin, ?String? documentation, ?IR::node_annotation? node) -> void
211
211
  def add_production(lhs_name, rhs_names, action, precedence_name, origin, documentation = nil, node = nil)
212
212
  # @type self: Normalizer
213
- lhs = symbol(lhs_name) || intern(lhs_name, :nonterminal, location: origin[:loc])
214
- rhs = rhs_names.map { |name| symbol(name)&.id || fail_hash(origin[:loc], "undefined symbol #{name}") }
213
+ location = origin[:loc] #: IR::location
214
+ lhs = symbol(lhs_name) || intern(lhs_name, :nonterminal, location: location)
215
+ rhs = rhs_names.map { |name| symbol(name)&.id || fail_hash(location, "undefined symbol #{name}") }
215
216
  precedence = precedence_name && symbol(precedence_name)
216
- fail_hash(origin[:loc], "undefined precedence symbol #{precedence_name}") if precedence_name && !precedence
217
+ fail_hash(location, "undefined precedence symbol #{precedence_name}") if precedence_name && !precedence
217
218
  @productions << IR::Production.new(id: @productions.length, lhs: lhs.id, rhs: rhs, action: action,
218
219
  precedence_override: precedence&.id, origin: origin,
219
220
  documentation: documentation, expansion: resolved_expansion, node: node)
@@ -3,13 +3,15 @@
3
3
  module Ibex
4
4
  # Deterministically renders frontend EBNF items for production origin metadata.
5
5
  module NormalizeExpression
6
+ # @rbs! type pending_item = String | Frontend::AST::item
7
+
6
8
  class << self
7
9
  # @rbs (Frontend::AST::item item) -> String
8
10
  def render(item)
9
- pending = [item] #: Array[untyped]
11
+ pending = [item] #: Array[pending_item]
10
12
  output = [] #: Array[String]
11
13
  until pending.empty?
12
- current = pending.pop
14
+ current = pending.pop || raise(ArgumentError, "expression stack unexpectedly empty")
13
15
  if current.is_a?(String)
14
16
  output << current
15
17
  next
@@ -22,7 +24,7 @@ module Ibex
22
24
 
23
25
  private
24
26
 
25
- # @rbs (Array[untyped] pending, Frontend::AST::item item) -> void
27
+ # @rbs (Array[pending_item] pending, Frontend::AST::item item) -> void
26
28
  def push_render_item(pending, item)
27
29
  case item
28
30
  when Frontend::AST::SymbolReference
@@ -45,7 +47,7 @@ module Ibex
45
47
  end
46
48
  end
47
49
 
48
- # @rbs (Array[untyped] pending, Frontend::AST::ParameterizedReference item) -> void
50
+ # @rbs (Array[pending_item] pending, Frontend::AST::ParameterizedReference item) -> void
49
51
  def push_render_parameterized_reference(pending, item)
50
52
  pending << ":#{item.named_reference}" if item.named_reference
51
53
  pending << ")"
@@ -53,7 +55,7 @@ module Ibex
53
55
  pending.push("(", item.name)
54
56
  end
55
57
 
56
- # @rbs (Array[untyped] pending, Frontend::AST::Group item) -> void
58
+ # @rbs (Array[pending_item] pending, Frontend::AST::Group item) -> void
57
59
  def push_render_group(pending, item)
58
60
  pending << ")"
59
61
  (item.alternatives.length - 1).downto(0) do |index|
@@ -63,7 +65,7 @@ module Ibex
63
65
  pending << "("
64
66
  end
65
67
 
66
- # @rbs (Array[untyped] pending, Array[Frontend::AST::item] items, String separator) -> void
68
+ # @rbs (Array[pending_item] pending, Array[Frontend::AST::item] items, String separator) -> void
67
69
  def push_render_items(pending, items, separator)
68
70
  (items.length - 1).downto(0) do |index|
69
71
  pending << separator if index < items.length - 1
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Builds the single current Grammar IR format for every normalized source.
5
+ module NormalizeGrammarBuilder
6
+ private
7
+
8
+ # @rbs (IR::ParserContract? parser_contract) -> IR::Grammar
9
+ def build_grammar(parser_contract)
10
+ # @type self: Normalizer
11
+ keywords = {
12
+ class_name: @ast.class_name, superclass: @ast.superclass, start: @start_name,
13
+ expect: @expected_conflicts, options: @options, symbols: @symbols,
14
+ mode: @mode, starts: @start_names, expect_rr: @expected_rr_conflicts,
15
+ parser_parameters: @parser_parameters, value_printers: @value_printers.values,
16
+ grammar_tests: @grammar_tests, lexer: normalize_lexer,
17
+ recovery: { sync_tokens: @recovery_sync_tokens, on_error_reduce: @on_error_reduce_groups },
18
+ productions: @productions, user_code: normalized_user_code,
19
+ conversions: @conversions, warnings: @warnings, user_code_chunks: normalized_user_code_chunks,
20
+ source_provenance: { file: @ast.loc.file, root: @resolution&.root_directory, byte_span: nil }
21
+ } #: { class_name: String, superclass: String?, start: String, expect: Integer, options: IR::grammar_options, symbols: Array[IR::GrammarSymbol], productions: Array[IR::Production], user_code: Hash[String, String], conversions: Hash[String, String], warnings: Array[IR::grammar_warning] } # rubocop:disable Layout/LineLength -- inline Steep shape mirrors the normalized builder contract.
22
+
23
+ IR::Grammar.new(**keywords, parser_contract: parser_contract || IR::ParserContract.new) # steep:ignore Ruby::InsufficientKeywordArguments
24
+ end
25
+ end
26
+ end
@@ -1,9 +1,43 @@
1
1
  # frozen_string_literal: true
2
+ # rbs_inline: enabled
2
3
 
3
4
  module Ibex
4
5
  # Deterministically substitutes inline-rule productions before LR construction.
5
6
  # rubocop:disable Metrics/ModuleLength -- expansion, action plans, and id remapping share one invariant.
6
7
  module NormalizeInlineExpansion
8
+ # @rbs!
9
+ # type inline_reference = [:physical | :step, Integer]
10
+ # type inline_step = {
11
+ # kind: :inline | :rule,
12
+ # rule: String?,
13
+ # code: String?,
14
+ # loc: IR::location,
15
+ # named_refs: Array[IR::named_ref],
16
+ # context_length: Integer,
17
+ # inputs: Array[inline_reference],
18
+ # stack_inputs: Array[inline_reference],
19
+ # lookahead: Integer,
20
+ # result_var: bool,
21
+ # result_type: String?
22
+ # }
23
+ # type inline_variant = {
24
+ # rhs: Array[Integer],
25
+ # steps: Array[inline_step],
26
+ # logical_refs: Array[inline_reference],
27
+ # output_ref: inline_reference?,
28
+ # inline_used: bool,
29
+ # inline_rule: String?,
30
+ # precedence_override: Integer?,
31
+ # precedence_contributes: bool,
32
+ # parameter: IR::parameter_expansion?
33
+ # }
34
+ # type inline_frame = {
35
+ # production: IR::Production,
36
+ # symbol_id: Integer?,
37
+ # index: Integer,
38
+ # variant: inline_variant
39
+ # }
40
+
7
41
  private
8
42
 
9
43
  # @rbs () -> void
@@ -33,20 +67,21 @@ module Ibex
33
67
  # The single-definition path reuses its accumulated arrays, so a long
34
68
  # acyclic chain remains linear in the size of its final action plan.
35
69
  # @rbs (IR::Production production, Hash[Integer, Array[IR::Production]] definitions) ->
36
- # Array[Hash[Symbol, untyped]]
70
+ # Array[inline_variant]
37
71
  def expand_inline_production(production, definitions)
38
72
  # @type self: Normalizer
39
- variants = [] #: Array[Hash[Symbol, untyped]]
40
- worklist = [[inline_expansion_frame(production, nil)]] #: Array[Array[Hash[Symbol, untyped]]]
73
+ variants = [] #: Array[inline_variant]
74
+ worklist = [[inline_expansion_frame(production, nil)]] #: Array[Array[inline_frame]]
41
75
  until worklist.empty?
42
76
  frames = worklist.pop || raise(Ibex::Error, "internal inline expansion worklist underflow")
43
- drain_inline_expansion_frames(frames, definitions, worklist, variants, production.origin[:loc])
77
+ location = production.origin[:loc] #: IR::location?
78
+ drain_inline_expansion_frames(frames, definitions, worklist, variants, location)
44
79
  end
45
80
  variants
46
81
  end
47
82
 
48
- # @rbs (Array[Hash[Symbol, untyped]] frames, Hash[Integer, Array[IR::Production]] definitions,
49
- # Array[Array[Hash[Symbol, untyped]]] worklist, Array[Hash[Symbol, untyped]] variants,
83
+ # @rbs (Array[inline_frame] frames, Hash[Integer, Array[IR::Production]] definitions,
84
+ # Array[Array[inline_frame]] worklist, Array[inline_variant] variants,
50
85
  # IR::location? location) -> void
51
86
  def drain_inline_expansion_frames(frames, definitions, worklist, variants, location)
52
87
  loop do
@@ -60,8 +95,8 @@ module Ibex
60
95
  end
61
96
  end
62
97
 
63
- # @rbs (Array[Hash[Symbol, untyped]] frames, Hash[Integer, Array[IR::Production]] definitions,
64
- # Array[Array[Hash[Symbol, untyped]]] worklist, Array[Hash[Symbol, untyped]] variants,
98
+ # @rbs (Array[inline_frame] frames, Hash[Integer, Array[IR::Production]] definitions,
99
+ # Array[Array[inline_frame]] worklist, Array[inline_variant] variants,
65
100
  # IR::location? location) -> bool
66
101
  def advance_inline_expansion_frame?(frames, definitions, worklist, variants, location)
67
102
  frame = frames.fetch(-1)
@@ -85,8 +120,8 @@ module Ibex
85
120
  true
86
121
  end
87
122
 
88
- # @rbs (Array[Hash[Symbol, untyped]] frames, Array[IR::Production] choices, Integer symbol_id,
89
- # Array[Array[Hash[Symbol, untyped]]] worklist) -> void
123
+ # @rbs (Array[inline_frame] frames, Array[IR::Production] choices, Integer symbol_id,
124
+ # Array[Array[inline_frame]] worklist) -> void
90
125
  def schedule_inline_choice_branches(frames, choices, symbol_id, worklist)
91
126
  choices.reverse_each do |choice|
92
127
  branch = clone_inline_expansion_frames(frames)
@@ -95,8 +130,8 @@ module Ibex
95
130
  end
96
131
  end
97
132
 
98
- # @rbs (Array[Hash[Symbol, untyped]] frames, Array[Hash[Symbol, untyped]] variants,
99
- # Array[Array[Hash[Symbol, untyped]]] worklist, IR::location? location) -> bool
133
+ # @rbs (Array[inline_frame] frames, Array[inline_variant] variants,
134
+ # Array[Array[inline_frame]] worklist, IR::location? location) -> bool
100
135
  def complete_inline_expansion_frame?(frames, variants, worklist, location)
101
136
  frame = frames.fetch(-1)
102
137
  current = frame.fetch(:production)
@@ -108,32 +143,34 @@ module Ibex
108
143
  return true
109
144
  end
110
145
 
111
- choice = finish_inline_choice(completed, current, frame.fetch(:symbol_id))
146
+ symbol_id = frame.fetch(:symbol_id) || raise(Ibex::Error, "inline expansion frame is missing its symbol")
147
+ choice = finish_inline_choice(completed, current, symbol_id)
112
148
  parent = frames.fetch(-1)
113
149
  parent[:variant] = combine_inline_variant(parent.fetch(:variant), choice)
114
150
  false
115
151
  end
116
152
 
117
- # @rbs (IR::Production production, Integer? symbol_id) -> Hash[Symbol, untyped]
153
+ # @rbs (IR::Production production, Integer? symbol_id) -> inline_frame
118
154
  def inline_expansion_frame(production, symbol_id)
119
155
  { production: production, symbol_id: symbol_id, index: 0, variant: empty_inline_variant(production) }
120
156
  end
121
157
 
122
- # @rbs (Array[Hash[Symbol, untyped]] frames) -> Array[Hash[Symbol, untyped]]
158
+ # @rbs (Array[inline_frame] frames) -> Array[inline_frame]
123
159
  def clone_inline_expansion_frames(frames)
124
160
  frames.map do |frame|
125
161
  variant = frame.fetch(:variant)
126
- frame.merge(
162
+ cloned = frame.merge(
127
163
  variant: variant.merge(
128
164
  rhs: variant.fetch(:rhs).dup,
129
165
  steps: variant.fetch(:steps).dup,
130
166
  logical_refs: variant.fetch(:logical_refs).dup
131
167
  )
132
168
  )
169
+ cloned #: inline_frame
133
170
  end
134
171
  end
135
172
 
136
- # @rbs (IR::Production production) -> Hash[Symbol, untyped]
173
+ # @rbs (IR::Production production) -> inline_variant
137
174
  def empty_inline_variant(production)
138
175
  {
139
176
  rhs: [],
@@ -148,61 +185,69 @@ module Ibex
148
185
  }
149
186
  end
150
187
 
151
- # @rbs (Hash[Symbol, untyped] variant, Integer symbol_id) -> Hash[Symbol, untyped]
188
+ # @rbs (inline_variant variant, Integer symbol_id) -> inline_variant
152
189
  def append_inline_symbol(variant, symbol_id)
153
190
  # @type self: Normalizer
154
191
  rhs = variant.fetch(:rhs)
155
192
  terminal = @symbols.fetch(symbol_id).terminal?
193
+ reference = [:physical, rhs.length] #: inline_reference
194
+ logical_refs = variant.fetch(:logical_refs) + [reference] #: Array[inline_reference]
156
195
  variant.merge(
157
196
  rhs: rhs + [symbol_id],
158
- logical_refs: variant.fetch(:logical_refs) + [[:physical, rhs.length]],
197
+ logical_refs: logical_refs,
159
198
  precedence_override: terminal ? nil : variant[:precedence_override],
160
199
  precedence_contributes: terminal || variant.fetch(:precedence_contributes)
161
- )
200
+ ) #: inline_variant
162
201
  end
163
202
 
164
- # @rbs (Hash[Symbol, untyped] parent, Hash[Symbol, untyped] child) -> Hash[Symbol, untyped]
203
+ # @rbs (inline_variant parent, inline_variant child) -> inline_variant
165
204
  def combine_inline_variant(parent, child)
166
205
  physical_offset = parent.fetch(:rhs).length
167
206
  step_offset = parent.fetch(:steps).length
168
207
  steps = combined_inline_steps(parent, child, physical_offset, step_offset)
208
+ output_ref = child.fetch(:output_ref) || raise(Ibex::Error, "inline choice has no output reference")
209
+ rhs = append_inline_array(parent.fetch(:rhs), child.fetch(:rhs)) #: Array[Integer]
210
+ combined_steps = append_inline_array(parent.fetch(:steps), steps) #: Array[inline_step]
211
+ logical_refs = parent.fetch(:logical_refs) + [
212
+ remap_inline_reference(output_ref, physical_offset, step_offset)
213
+ ] #: Array[inline_reference]
169
214
  parent.merge(
170
- rhs: append_inline_array(parent.fetch(:rhs), child.fetch(:rhs)),
171
- steps: append_inline_array(parent.fetch(:steps), steps),
172
- logical_refs: parent.fetch(:logical_refs) + [
173
- remap_inline_reference(child.fetch(:output_ref), physical_offset, step_offset)
174
- ],
215
+ rhs: rhs,
216
+ steps: combined_steps,
217
+ logical_refs: logical_refs,
175
218
  inline_used: true,
176
219
  inline_rule: parent[:inline_rule] || child[:inline_rule],
177
220
  precedence_override: combined_inline_precedence(parent, child),
178
221
  precedence_contributes: parent.fetch(:precedence_contributes) ||
179
222
  child.fetch(:precedence_contributes),
180
223
  parameter: parent[:parameter] || child[:parameter]
181
- )
224
+ ) #: inline_variant
182
225
  end
183
226
 
184
- # @rbs (Hash[Symbol, untyped] parent, Hash[Symbol, untyped] child,
185
- # Integer physical_offset, Integer step_offset) -> Array[Hash[Symbol, untyped]]
227
+ # @rbs (inline_variant parent, inline_variant child,
228
+ # Integer physical_offset, Integer step_offset) -> Array[inline_step]
186
229
  def combined_inline_steps(parent, child, physical_offset, step_offset)
187
230
  return child.fetch(:steps) if physical_offset.zero? && step_offset.zero? && parent.fetch(:logical_refs).empty?
188
231
 
189
232
  remap_inline_steps(parent, child, physical_offset, step_offset)
190
233
  end
191
234
 
192
- # @rbs (Array[untyped] left, Array[untyped] right) -> Array[untyped]
235
+ # The helper is shared by homogeneous integer and step arrays; callers
236
+ # assert the concrete element type at each use site.
237
+ # @rbs (Array[Object?] left, Array[Object?] right) -> Array[Object?]
193
238
  def append_inline_array(left, right)
194
239
  left.empty? ? right : left + right
195
240
  end
196
241
 
197
- # @rbs (Hash[Symbol, untyped] parent, Hash[Symbol, untyped] child) -> Integer?
242
+ # @rbs (inline_variant parent, inline_variant child) -> Integer?
198
243
  def combined_inline_precedence(parent, child)
199
244
  return child[:precedence_override] if child.fetch(:precedence_contributes)
200
245
 
201
246
  parent[:precedence_override]
202
247
  end
203
248
 
204
- # @rbs (Hash[Symbol, untyped] parent, Hash[Symbol, untyped] child,
205
- # Integer physical_offset, Integer step_offset) -> Array[Hash[Symbol, untyped]]
249
+ # @rbs (inline_variant parent, inline_variant child,
250
+ # Integer physical_offset, Integer step_offset) -> Array[inline_step]
206
251
  def remap_inline_steps(parent, child, physical_offset, step_offset)
207
252
  child.fetch(:steps).map do |step|
208
253
  inputs = step.fetch(:inputs).map do |reference|
@@ -211,11 +256,12 @@ module Ibex
211
256
  stack_inputs = step.fetch(:stack_inputs).map do |reference|
212
257
  remap_inline_reference(reference, physical_offset, step_offset)
213
258
  end
214
- step.merge(
259
+ remapped = step.merge(
215
260
  inputs: inputs,
216
261
  stack_inputs: parent.fetch(:logical_refs) + stack_inputs,
217
262
  lookahead: step.fetch(:lookahead) + physical_offset
218
263
  )
264
+ remapped #: inline_step
219
265
  end
220
266
  end
221
267
 
@@ -229,17 +275,16 @@ module Ibex
229
275
  [kind, index + (kind == :physical ? physical_offset : step_offset)]
230
276
  end
231
277
 
232
- # @rbs (Hash[Symbol, untyped] variant, IR::Production production) -> Hash[Symbol, untyped]
278
+ # @rbs (inline_variant variant, IR::Production production) -> inline_variant
233
279
  def finish_inline_precedence(variant, production)
234
280
  explicit = production.precedence_override
235
281
  variant.merge(
236
282
  precedence_override: explicit || variant[:precedence_override],
237
283
  precedence_contributes: !explicit.nil? || variant.fetch(:precedence_contributes)
238
- )
284
+ ) #: inline_variant
239
285
  end
240
286
 
241
- # @rbs (Hash[Symbol, untyped] variant, IR::Production production, Integer symbol_id) ->
242
- # Hash[Symbol, untyped]
287
+ # @rbs (inline_variant variant, IR::Production production, Integer symbol_id) -> inline_variant
243
288
  def finish_inline_choice(variant, production, symbol_id)
244
289
  steps = variant.fetch(:steps)
245
290
  rule = @inline_rule_by_symbol.fetch(symbol_id)
@@ -250,18 +295,20 @@ module Ibex
250
295
  output_ref: [:step, steps.length - 1],
251
296
  inline_used: true,
252
297
  inline_rule: rule
253
- )
298
+ ) #: inline_variant
254
299
  end
255
300
 
256
- # @rbs (IR::Production production, Array[Array[Symbol | Integer]] inputs, Integer lookahead,
257
- # Symbol kind, String? rule) -> Hash[Symbol, untyped]
301
+ # @rbs (IR::Production production, Array[inline_reference] inputs, Integer lookahead,
302
+ # :inline | :rule kind, String? rule) -> inline_step
258
303
  def inline_action_step(production, inputs, lookahead, kind, rule)
259
304
  action = production.action
305
+ location = action&.location || production.origin.fetch(:loc)
306
+ typed_location = location #: IR::location
260
307
  {
261
308
  kind: kind,
262
309
  rule: rule,
263
310
  code: action&.code,
264
- loc: action&.location || production.origin.fetch(:loc),
311
+ loc: typed_location,
265
312
  named_refs: action&.named_refs || [],
266
313
  context_length: action&.context_length || 0,
267
314
  inputs: inputs,
@@ -272,7 +319,7 @@ module Ibex
272
319
  }
273
320
  end
274
321
 
275
- # @rbs (IR::Production production, Hash[Symbol, untyped] variant, Integer id) -> IR::Production
322
+ # @rbs (IR::Production production, inline_variant variant, Integer id) -> IR::Production
276
323
  def composed_inline_production(production, variant, id)
277
324
  steps = variant.fetch(:steps)
278
325
  caller = inline_action_step(
@@ -288,9 +335,11 @@ module Ibex
288
335
  )
289
336
  end
290
337
 
291
- # @rbs (IR::Production production, Integer physical_length, Array[Hash[Symbol, untyped]]) -> IR::Action
338
+ # @rbs (IR::Production production, Integer physical_length, Array[inline_step]) -> IR::Action
292
339
  def composed_inline_action(production, physical_length, steps)
293
340
  action = production.action
341
+ location = action&.location || production.origin.fetch(:loc)
342
+ typed_location = location #: IR::location
294
343
  fragments = steps.map do |step|
295
344
  { kind: step.fetch(:kind), source: inline_source_provenance(step.fetch(:loc)) }
296
345
  end
@@ -302,12 +351,12 @@ module Ibex
302
351
  } #: IR::action_composition
303
352
  IR::Action.new(
304
353
  code: action&.code || inline_implicit_code(production.rhs.length),
305
- location: action&.location || production.origin.fetch(:loc),
354
+ location: typed_location,
306
355
  composition: composition
307
356
  )
308
357
  end
309
358
 
310
- # @rbs (Hash[Symbol, untyped] step, Integer physical_length) -> Hash[Symbol, untyped]
359
+ # @rbs (inline_step step, Integer physical_length) -> IR::action_composition_step
311
360
  def composition_plan_step(step, physical_length)
312
361
  {
313
362
  kind: step.fetch(:kind),
@@ -345,12 +394,13 @@ module Ibex
345
394
  { file: location[:file], root: @resolution&.root_directory, byte_span: nil }
346
395
  end
347
396
 
348
- # @rbs (IR::Production production, Hash[Symbol, untyped] variant) -> IR::production_expansion
397
+ # @rbs (IR::Production production, inline_variant variant) -> IR::production_expansion
349
398
  def inline_production_expansion(production, variant)
350
399
  existing = production.expansion
400
+ inline_rule = variant.fetch(:inline_rule) || raise(Ibex::Error, "inline expansion has no rule")
351
401
  {
352
402
  parameter: existing&.dig(:parameter) || variant[:parameter],
353
- inline: { rule: variant.fetch(:inline_rule) },
403
+ inline: { rule: inline_rule },
354
404
  include_chain: existing&.dig(:include_chain) || []
355
405
  }
356
406
  end
@@ -367,7 +417,8 @@ module Ibex
367
417
  # @rbs (IR::Production production) -> void
368
418
  def charge_inline_expansion!(production)
369
419
  @inline_expansion_count += 1
370
- enforce_inline_choice_limit!(@inline_expansion_count, production.origin[:loc])
420
+ location = production.origin[:loc] #: IR::location?
421
+ enforce_inline_choice_limit!(@inline_expansion_count, location)
371
422
  end
372
423
 
373
424
  # @rbs (Integer count, IR::location? location) -> void