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
@@ -57,7 +57,7 @@ module Ibex
57
57
 
58
58
  offsets = line_offsets
59
59
  tokens = Object.const_get(:Ripper).__send__(:lex, lexable_source)
60
- # @type var tokens: Array[[[Integer, Integer], Symbol, String, untyped]]
60
+ # @type var tokens: Array[[[Integer, Integer], Symbol, String, Object?]]
61
61
  tokens.filter_map do |position, type, _token, _state|
62
62
  next unless type == :on_ident
63
63
 
@@ -17,7 +17,7 @@ module Ibex
17
17
  @generated_action_abi = generated_action_abi || GeneratedActionABI::Cache.new
18
18
  end
19
19
 
20
- # @rbs (IR::Production production, Hash[Symbol, untyped] step, Integer index) -> String
20
+ # @rbs (IR::Production production, IR::action_composition_step step, Integer index) -> String
21
21
  def composed_fragment_method_source(production, step, index)
22
22
  source = "private def #{composed_fragment_name(production, index)}" \
23
23
  "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location); "
@@ -97,7 +97,7 @@ module Ibex
97
97
 
98
98
  require "ripper"
99
99
  tokens = Object.const_get(:Ripper).__send__(:lex, source)
100
- # @type var tokens: Array[[[Integer, Integer], Symbol, String, untyped]]
100
+ # @type var tokens: Array[GeneratedActionABI::ripper_token]
101
101
  tokens.any? { |_position, event, _token, _state| event == :on_heredoc_beg }
102
102
  end
103
103
 
@@ -149,12 +149,11 @@ module Ibex
149
149
  end
150
150
  end
151
151
 
152
- # @rbs (Hash[Symbol, untyped] step) -> String
152
+ # @rbs (IR::action_composition_step step) -> String
153
153
  def composed_semantic_code(step)
154
154
  maximum = [step.fetch(:inputs).length, step.fetch(:context_length)].max
155
- ActionLocations.new(
156
- step.fetch(:code), maximum: maximum, location: step.fetch(:loc)
157
- ).rewrite
155
+ code = step.fetch(:code) #: String
156
+ ActionLocations.new(code, maximum: maximum, location: step.fetch(:loc)).rewrite
158
157
  end
159
158
 
160
159
  # @rbs (String source, Array[IR::named_ref] named_refs) -> void
@@ -49,7 +49,8 @@ module Ibex
49
49
  def append_value_printers(lines)
50
50
  @grammar.value_printers.each do |printer|
51
51
  symbol = @grammar.symbol(printer[:symbol]) || raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
52
- append_method(lines, printer[:loc], @method_source.value_printer_method_source(symbol.id, printer))
52
+ location = printer.fetch(:loc) #: IR::location
53
+ append_method(lines, location, @method_source.value_printer_method_source(symbol.id, printer))
53
54
  end
54
55
  end
55
56
 
@@ -83,7 +84,7 @@ module Ibex
83
84
 
84
85
  # @rbs (Array[String] lines, IR::Production production) -> void
85
86
  def append_action(lines, production)
86
- location = production.action&.location || production.origin.fetch(:loc)
87
+ location = production.action&.location || production.origin.fetch(:loc) #: IR::location
87
88
  append_method(lines, location, @method_source.compiled_action_method_source(production))
88
89
  end
89
90
 
@@ -134,17 +134,18 @@ module Ibex
134
134
  @automaton, state, conflict,
135
135
  max_tokens: @max_tokens, max_configurations: @max_configurations
136
136
  )
137
- result = search.call
137
+ outcome = search.call
138
+ result = outcome[:result]
138
139
  {
139
140
  state: state.id,
140
141
  type: conflict.fetch(:type).to_s,
141
142
  token: conflict.fetch(:symbol),
142
- result: result ? "ambiguous" : "not_found",
143
+ result: outcome[:status] == :found ? "ambiguous" : "not_found",
143
144
  sentence: result ? symbol_names(result.fetch(:sentence_ids)) : [],
144
145
  lookahead_index: result&.fetch(:lookahead_index),
145
146
  interpretations: result ? result.fetch(:interpretations) : [],
146
- explored_configurations: search.explored,
147
- configuration_budget_exhausted: search.exhausted?
147
+ explored_configurations: outcome.fetch(:explored),
148
+ configuration_budget_exhausted: outcome.fetch(:exhausted)
148
149
  }
149
150
  end
150
151
 
@@ -15,8 +15,20 @@ module Ibex
15
15
  # type explain_entry = {
16
16
  # state: IR::AutomatonState,
17
17
  # conflict: IR::conflict,
18
- # example: IR::counterexample
18
+ # example: LALR::search_counterexample
19
19
  # }
20
+ #
21
+ # type explain_token = { name: String, display_name: String?, label: String, ?query: String }
22
+ # type explain_alternative = { kind: String, ?state: Integer, ?production: Integer }
23
+ # type explain_search = {
24
+ # status: String, explored: Integer, exhausted: bool, bounds: Hash[Symbol, Integer]
25
+ # }
26
+ # type explain_tree_node = {
27
+ # ?symbol: explain_token, ?token: explain_token, ?production: Integer, ?children: Array[explain_tree]
28
+ # }
29
+ # type explain_tree = untyped
30
+ # type explain_interpretation = Hash[Symbol, untyped]
31
+ # type string_value = String | Integer | Symbol
20
32
 
21
33
  # Renders a selected conflict explanation from Automaton IR and counterexamples.
22
34
  # rubocop:disable Metrics/ClassLength -- inline contracts and two stable output formats stay near selection policy.
@@ -39,42 +51,50 @@ module Ibex
39
51
  @entries = select_entries
40
52
  end
41
53
 
42
- # @rbs () -> Hash[Symbol, untyped]
54
+ # @rbs () -> Hash[Symbol, Object?]
43
55
  def to_h
44
- unifying = @entries.count { |entry| entry.fetch(:example).fetch(:unifying) }
56
+ entries = @entries #: Array[explain_entry]
57
+ automaton = @automaton #: IR::Automaton
58
+ unifying = entries.count { |entry| entry.fetch(:example).fetch(:unifying) }
59
+ inconclusive = entries.count { |entry| entry.fetch(:example).fetch(:inconclusive) }
45
60
  {
46
61
  ibex_explain: "conflicts",
47
62
  schema_version: SCHEMA_VERSION,
48
- algorithm: @automaton.algorithm,
63
+ algorithm: automaton.algorithm,
49
64
  selectors: {
50
65
  state: @state_selector,
51
66
  token: @token_selector && token_reference(@token_selector, query: @token_query)
52
67
  },
53
68
  search: { max_tokens: @max_tokens, max_configurations: @max_configurations },
54
69
  summary: {
55
- matched_conflicts: @entries.length,
70
+ matched_conflicts: entries.length,
56
71
  unifying_counterexamples: unifying,
57
- nonunifying_witnesses: @entries.length - unifying
72
+ nonunifying_witnesses: entries.length - unifying - inconclusive,
73
+ inconclusive_searches: inconclusive
58
74
  },
59
- conflicts: @entries.map { |entry| conflict_document(entry) }
75
+ conflicts: entries.map { |entry| conflict_document(entry) }
60
76
  }
61
77
  end
62
78
 
63
79
  # @rbs () -> String
64
80
  def render_text
81
+ automaton = @automaton #: IR::Automaton
82
+ entries = @entries #: Array[explain_entry]
83
+ state_selector = @state_selector #: Integer?
84
+ token_selector = @token_selector #: IR::GrammarSymbol?
65
85
  lines = [
66
86
  "Ibex conflict explanation v#{SCHEMA_VERSION}",
67
- "Algorithm: #{@automaton.algorithm}",
68
- "State selector: #{@state_selector || 'all'}",
69
- "Token selector: #{@token_selector ? token_label(@token_selector, query: @token_query) : 'all'}",
87
+ "Algorithm: #{automaton.algorithm}",
88
+ "State selector: #{state_selector || 'all'}",
89
+ "Token selector: #{token_selector ? token_label(token_selector, query: @token_query) : 'all'}",
70
90
  "Search budget: #{@max_tokens} tokens, #{@max_configurations} configurations",
71
- "Matched conflicts: #{@entries.length}",
91
+ "Matched conflicts: #{entries.length}",
72
92
  ""
73
93
  ]
74
- if @entries.empty?
94
+ if entries.empty?
75
95
  lines << "No conflicts matched the selectors."
76
96
  else
77
- @entries.each_with_index { |entry, index| append_conflict(lines, entry, index + 1) }
97
+ entries.each_with_index { |entry, index| append_conflict(lines, entry, index + 1) }
78
98
  end
79
99
  "#{lines.join("\n")}\n"
80
100
  end
@@ -85,10 +105,11 @@ module Ibex
85
105
  def resolve_token(query)
86
106
  return unless query
87
107
 
88
- canonical = @grammar.terminals.find { |symbol| symbol.name == query }
108
+ grammar = @grammar #: IR::Grammar
109
+ canonical = grammar.terminals.find { |symbol| symbol.name == query }
89
110
  return canonical if canonical
90
111
 
91
- displayed = @grammar.terminals.select { |symbol| symbol.display_name == query }
112
+ displayed = grammar.terminals.select { |symbol| symbol.display_name == query }
92
113
  return displayed.first if displayed.one?
93
114
 
94
115
  if displayed.length > 1
@@ -102,10 +123,12 @@ module Ibex
102
123
 
103
124
  # @rbs () -> void
104
125
  def validate_state!
105
- return unless @state_selector
106
- return if @state_selector >= 0 && @automaton.states.any? { |state| state.id == @state_selector }
126
+ state_selector = @state_selector #: Integer?
127
+ automaton = @automaton #: IR::Automaton
128
+ return unless state_selector
129
+ return if state_selector >= 0 && automaton.states.any? { |state| state.id == state_selector }
107
130
 
108
- raise Ibex::Error, "(cli):1:1: unknown automaton state #{@state_selector}"
131
+ raise Ibex::Error, "(cli):1:1: unknown automaton state #{state_selector}"
109
132
  end
110
133
 
111
134
  # @rbs () -> Array[explain_entry]
@@ -113,8 +136,9 @@ module Ibex
113
136
  selections = selected_conflicts
114
137
  return [] if selections.empty?
115
138
 
139
+ automaton = @automaton #: IR::Automaton
116
140
  counterexamples = LALR::Counterexample.new(
117
- @automaton, max_tokens: @max_tokens, max_configurations: @max_configurations
141
+ automaton, max_tokens: @max_tokens, max_configurations: @max_configurations
118
142
  )
119
143
  selections.map do |selection|
120
144
  state = selection.fetch(:state)
@@ -128,17 +152,20 @@ module Ibex
128
152
 
129
153
  # @rbs () -> Array[explain_selection]
130
154
  def selected_conflicts
131
- @automaton.states.flat_map do |state|
155
+ automaton = @automaton #: IR::Automaton
156
+ state_selector = @state_selector #: Integer?
157
+ token_selector = @token_selector #: IR::GrammarSymbol?
158
+ automaton.states.flat_map do |state|
132
159
  state.conflicts.each_with_index.filter_map do |conflict, conflict_index|
133
- next if @state_selector && state.id != @state_selector
134
- next if @token_selector && conflict[:symbol] != @token_selector.name
160
+ next if state_selector && state.id != state_selector
161
+ next if token_selector && conflict[:symbol] != token_selector.name
135
162
 
136
163
  { state: state, conflict: conflict, conflict_index: conflict_index }
137
164
  end
138
165
  end
139
166
  end
140
167
 
141
- # @rbs (explain_entry entry) -> Hash[Symbol, untyped]
168
+ # @rbs (explain_entry entry) -> Hash[Symbol, Object?]
142
169
  def conflict_document(entry)
143
170
  state = entry.fetch(:state)
144
171
  conflict = entry.fetch(:conflict)
@@ -150,69 +177,97 @@ module Ibex
150
177
  alternatives: conflict_alternatives(conflict),
151
178
  resolution: string_values(conflict.fetch(:resolution)),
152
179
  witness: {
153
- kind: example.fetch(:unifying) ? "unifying_counterexample" : "nonunifying_witness",
180
+ kind: witness_kind(example),
154
181
  sentence: example.fetch(:sentence).map { |name| symbol_reference(name) },
155
182
  lookahead_index: example.fetch(:lookahead_index),
156
183
  symbol_path: example.fetch(:symbol_path).map { |name| symbol_reference(name) },
184
+ search: search_document(example.fetch(:search)),
157
185
  interpretations: example.fetch(:interpretations).map { |item| interpretation_document(item) }
158
186
  }
159
- } #: Hash[Symbol, untyped]
187
+ } #: Hash[Symbol, Object?]
160
188
  document[:midrule_origins] = conflict[:midrule_origins] if conflict[:midrule_origins]
161
189
  document
162
190
  end
163
191
 
164
- # @rbs (IR::conflict conflict) -> Array[Hash[Symbol, untyped]]
192
+ # @rbs (LALR::search_counterexample example) -> String
193
+ def witness_kind(example)
194
+ return "unifying_counterexample" if example.fetch(:unifying)
195
+ return "inconclusive" if example.fetch(:inconclusive)
196
+
197
+ "nonunifying_witness"
198
+ end
199
+
200
+ # @rbs (LALR::search_outcome outcome) -> explain_search
201
+ def search_document(outcome)
202
+ {
203
+ status: outcome.fetch(:status).to_s,
204
+ explored: outcome.fetch(:explored),
205
+ exhausted: outcome.fetch(:exhausted),
206
+ bounds: outcome.fetch(:bounds)
207
+ }
208
+ end
209
+
210
+ # @rbs (IR::conflict conflict) -> Array[explain_alternative]
165
211
  def conflict_alternatives(conflict)
166
212
  case conflict[:type]
167
213
  when :shift_reduce
168
- [{ kind: "shift", state: conflict.fetch(:shift_to) },
169
- { kind: "reduce", production: conflict.fetch(:reduce) }]
214
+ shift = { kind: "shift", state: conflict.fetch(:shift_to) } # @type var shift: explain_alternative
215
+ reduce = { kind: "reduce", production: conflict.fetch(:reduce) } # @type var reduce: explain_alternative
216
+ [shift, reduce]
170
217
  when :reduce_reduce
171
218
  reduce_reduce = conflict #: IR::reduce_reduce_conflict
172
- reduce_reduce[:reductions].map { |production| { kind: "reduce", production: production } }
219
+ reduce_reduce[:reductions].map do |production|
220
+ { kind: "reduce", production: production }
221
+ end #: Array[explain_alternative]
173
222
  else
174
223
  []
175
224
  end
176
225
  end
177
226
 
178
- # @rbs (IR::interpretation interpretation) -> Hash[Symbol, untyped]
227
+ # @rbs (IR::interpretation interpretation) -> explain_interpretation
179
228
  def interpretation_document(interpretation)
180
- value = { kind: interpretation.fetch(:kind).to_s,
181
- tree: tree_document(interpretation.fetch(:tree)) } #: Hash[Symbol, untyped]
229
+ kind = interpretation.fetch(:kind) #: Symbol
230
+ tree = interpretation.fetch(:tree) #: explain_tree
231
+ value = { kind: kind.to_s,
232
+ tree: tree_document(tree) } # @type var value: explain_interpretation
182
233
  value[:state] = interpretation[:state] if interpretation.key?(:state)
183
234
  value[:production] = interpretation[:production] if interpretation.key?(:production)
184
235
  value
185
236
  end
186
237
 
187
- # @rbs (untyped tree) -> untyped
238
+ # @rbs (explain_tree tree) -> explain_tree
188
239
  def tree_document(tree)
189
240
  return symbol_reference(tree.to_s) unless tree.is_a?(Hash)
190
241
 
191
- value = {} #: Hash[Symbol, untyped]
192
- value[:symbol] = symbol_reference(tree[:symbol]) if tree[:symbol]
193
- value[:token] = symbol_reference(tree[:token]) if tree[:token]
194
- value[:production] = tree[:production] if tree[:production]
195
- value[:children] = tree[:children].map { |child| tree_document(child) } if tree[:children]
242
+ node = tree #: explain_tree_node
243
+ value = {} # @type var value: explain_tree_node
244
+ value[:symbol] = symbol_reference(node[:symbol].to_s) if node[:symbol]
245
+ value[:token] = symbol_reference(node[:token].to_s) if node[:token]
246
+ value[:production] = node[:production] if node[:production]
247
+ value[:children] = node[:children].map { |child| tree_document(child) } if node[:children]
196
248
  value
197
249
  end
198
250
 
199
- # @rbs (Hash[Symbol, untyped] value) -> Hash[Symbol, untyped]
251
+ # @rbs (Hash[Symbol, string_value] value) -> Hash[Symbol, string_value]
200
252
  def string_values(value)
201
- value.transform_values { |item| item.is_a?(Symbol) ? item.to_s : item }
253
+ values = value #: Hash[Symbol, string_value]
254
+ values.transform_values { |item| item.is_a?(Symbol) ? item.to_s : item }
202
255
  end
203
256
 
204
- # @rbs (String name) -> Hash[Symbol, untyped]
257
+ # @rbs (String name) -> explain_token
205
258
  def symbol_reference(name)
206
- symbol = @grammar.symbol(name)
259
+ grammar = @grammar #: IR::Grammar
260
+ symbol = grammar.symbol(name)
207
261
  return { name: name, display_name: nil, label: name } unless symbol
208
262
 
209
263
  token_reference(symbol)
210
264
  end
211
265
 
212
- # @rbs (IR::GrammarSymbol symbol, ?query: String?) -> Hash[Symbol, untyped]
266
+ # @rbs (IR::GrammarSymbol symbol, ?query: String?) -> explain_token
213
267
  def token_reference(symbol, query: nil)
268
+ labels = @labels #: Hash[Integer, String]
214
269
  value = { name: symbol.name, display_name: symbol.display_name,
215
- label: @labels.fetch(symbol.id, symbol.name) } #: Hash[Symbol, untyped]
270
+ label: labels.fetch(symbol.id, symbol.name) } # @type var value: explain_token
216
271
  value[:query] = query if query
217
272
  value
218
273
  end
@@ -222,14 +277,18 @@ module Ibex
222
277
  state = entry.fetch(:state)
223
278
  conflict = entry.fetch(:conflict)
224
279
  example = entry.fetch(:example)
225
- token = @grammar.symbol(conflict.fetch(:symbol))
280
+ grammar = @grammar #: IR::Grammar
281
+ token = grammar.symbol(conflict.fetch(:symbol))
226
282
  token_text = token ? token_label(token) : conflict.fetch(:symbol)
227
283
  type = conflict.fetch(:type).to_s.tr("_", "/")
228
284
  lines << "Conflict #{number}: state #{state.id}, #{type}, token #{token_text}"
229
285
  append_midrule_origins(lines, conflict)
230
286
  append_witness_steps(lines, state, conflict, example)
231
287
  append_interpretations(lines, example)
232
- unless example.fetch(:unifying)
288
+ if example.fetch(:inconclusive)
289
+ search = example.fetch(:search)
290
+ lines << " Search exhausted after #{search.fetch(:explored)} configurations; classification is inconclusive."
291
+ elsif !example.fetch(:unifying)
233
292
  lines << " The search found no shared sentence within the configured budget; this witness is deterministic."
234
293
  end
235
294
  lines << ""
@@ -246,12 +305,16 @@ module Ibex
246
305
  end
247
306
 
248
307
  # @rbs (Array[String] lines, IR::AutomatonState state, IR::conflict conflict,
249
- # IR::counterexample example) -> void
308
+ # LALR::search_counterexample example) -> void
250
309
  def append_witness_steps(lines, state, conflict, example)
251
310
  lines << " 1. Reach state #{state.id} with the witness prefix."
252
311
  sentence = example.fetch(:sentence).map { |name| display_name(name) }
253
312
  sentence.insert(example.fetch(:lookahead_index), "•")
254
- kind = example.fetch(:unifying) ? "Unifying counterexample" : "Nonunifying reachability witness"
313
+ kind = case witness_kind(example)
314
+ when "unifying_counterexample" then "Unifying counterexample"
315
+ when "inconclusive" then "Inconclusive reachability witness"
316
+ else "Nonunifying reachability witness"
317
+ end
255
318
  lines << " #{kind}: #{sentence.join(' ')}"
256
319
  lines << " 2. The lookahead permits these competing actions:"
257
320
  conflict_alternatives(conflict).each { |alternative| lines << " - #{alternative_text(alternative)}" }
@@ -259,7 +322,7 @@ module Ibex
259
322
  lines << " 3. Resolution: #{resolution.fetch(:by)} chose #{resolution.fetch(:chose)}."
260
323
  end
261
324
 
262
- # @rbs (Array[String] lines, IR::counterexample example) -> void
325
+ # @rbs (Array[String] lines, LALR::search_counterexample example) -> void
263
326
  def append_interpretations(lines, example)
264
327
  lines << " Competing derivations:"
265
328
  example.fetch(:interpretations).each_with_index do |interpretation, index|
@@ -268,24 +331,25 @@ module Ibex
268
331
  end
269
332
  end
270
333
 
271
- # @rbs (Hash[Symbol, untyped] alternative) -> String
334
+ # @rbs (explain_alternative alternative) -> String
272
335
  def alternative_text(alternative)
273
336
  return "shift to state #{alternative.fetch(:state)}" if alternative.fetch(:kind) == "shift"
274
337
 
275
338
  "reduce by production #{alternative.fetch(:production)}"
276
339
  end
277
340
 
278
- # @rbs (Array[String] lines, untyped tree, String prefix, String connector) -> void
341
+ # @rbs (Array[String] lines, explain_tree tree, String prefix, String connector) -> void
279
342
  def append_tree(lines, tree, prefix, connector)
280
343
  unless tree.is_a?(Hash)
281
344
  lines << "#{prefix}#{connector}#{display_name(tree.to_s)}"
282
345
  return
283
346
  end
284
347
 
285
- name = tree[:symbol] || tree[:token]
286
- production = tree[:production] ? " (production #{tree[:production]})" : ""
348
+ node = tree #: explain_tree_node
349
+ name = node[:symbol] || node[:token]
350
+ production = node[:production] ? " (production #{node[:production]})" : ""
287
351
  lines << "#{prefix}#{connector}#{display_name(name.to_s)}#{production}"
288
- children = tree.fetch(:children, [])
352
+ children = node.fetch(:children, [])
289
353
  continuation = { "" => "", "|- " => "| " }.fetch(connector, " ")
290
354
  child_prefix = "#{prefix}#{continuation}"
291
355
  children.each_with_index do |child, index|
@@ -305,7 +369,11 @@ module Ibex
305
369
  end
306
370
 
307
371
  # @rbs (String name) -> String
308
- def display_name(name) = @grammar.symbol(name)&.then { |symbol| @labels.fetch(symbol.id, symbol.name) } || name
372
+ def display_name(name)
373
+ grammar = @grammar #: IR::Grammar
374
+ labels = @labels #: Hash[Integer, String]
375
+ grammar.symbol(name)&.then { |symbol| labels.fetch(symbol.id, symbol.name) } || name
376
+ end
309
377
  end
310
378
  # rubocop:enable Metrics/ClassLength
311
379
  end
@@ -9,6 +9,10 @@ module Ibex
9
9
  # action's declared inputs.
10
10
  # rubocop:disable Metrics/ModuleLength -- ABI proof and source rewriting must evolve together.
11
11
  module GeneratedActionABI
12
+ # @rbs!
13
+ # type ripper_token = [[Integer, Integer], Symbol, String, Integer]
14
+ # type sexp_value = Symbol | String | Integer | nil | Array[sexp_value]
15
+
12
16
  LEGACY_PARAMETERS = %w[
13
17
  _values
14
18
  _ibex_locations
@@ -148,6 +152,7 @@ module Ibex
148
152
  assignment = /\Aresult\s*=\s*(.*)\z/m.match(body)
149
153
  body = (assignment[1] || "").strip if assignment
150
154
  return false if body.empty? || body.match?(/(?<![=!<>])=(?!=|>)/)
155
+ return true unless body.match?(/\bval\b/)
151
156
 
152
157
  without_reads = body.gsub(/\bval\[\s*\d+\s*\]/, "")
153
158
  without_reads != body && !without_reads.match?(/\bval\b/)
@@ -188,7 +193,7 @@ module Ibex
188
193
  end
189
194
  private_class_method :simple_indexed_positional_action_source
190
195
 
191
- # @rbs (Array[untyped] tokens, Array[String] parameters) -> String?
196
+ # @rbs (Array[ripper_token] tokens, Array[String] parameters) -> String?
192
197
  def rewrite_positional_values(tokens, parameters)
193
198
  result = [] #: Array[String]
194
199
  index = 0
@@ -219,7 +224,7 @@ module Ibex
219
224
  end
220
225
  private_class_method :rewrite_positional_values
221
226
 
222
- # @rbs (Array[untyped] tokens, Integer index, Array[String] parameters) -> [String, Integer]?
227
+ # @rbs (Array[ripper_token] tokens, Integer index, Array[String] parameters) -> [String, Integer]?
223
228
  def positional_value_reference(tokens, index, parameters)
224
229
  return nil if receiver_before_value?(tokens, index)
225
230
 
@@ -234,7 +239,7 @@ module Ibex
234
239
  end
235
240
  private_class_method :positional_value_reference
236
241
 
237
- # @rbs (Array[untyped] tokens, Integer index) -> bool
242
+ # @rbs (Array[ripper_token] tokens, Integer index) -> bool
238
243
  def receiver_before_value?(tokens, index)
239
244
  previous = tokens.first(index).reverse.find do |entry|
240
245
  !%i[on_sp on_nl on_ignored_nl on_comment].include?(entry[1])
@@ -257,7 +262,7 @@ module Ibex
257
262
  end
258
263
  private_class_method :references_legacy_parameter?
259
264
 
260
- # @rbs (untyped node, ?untyped parent, ?Integer? child_index) -> bool
265
+ # @rbs (sexp_value node, ?sexp_value parent, ?Integer? child_index) -> bool
261
266
  def read_only_value_references?(node, parent = nil, child_index = nil)
262
267
  return true unless node.is_a?(Array)
263
268
  return safe_value_reference?(parent, child_index) if value_reference?(node)
@@ -274,7 +279,7 @@ module Ibex
274
279
  end
275
280
  private_class_method :value_reference?
276
281
 
277
- # @rbs (untyped parent, Integer? child_index) -> bool
282
+ # @rbs (sexp_value? parent, Integer? child_index) -> bool
278
283
  def safe_value_reference?(parent, child_index)
279
284
  return false unless parent.is_a?(Array)
280
285
 
@@ -8,6 +8,9 @@ module Ibex
8
8
  # Generates an RBS declaration for the public surface of a generated parser.
9
9
  # rubocop:disable Metrics/ClassLength -- one generator owns the complete parser signature.
10
10
  class RBS
11
+ # @rbs!
12
+ # type syntax_definition = { name: String, kind: Integer, fields: Hash[String, CSTMetadata::field_slot] }
13
+
11
14
  # @rbs @automaton: IR::Automaton
12
15
  # @rbs @grammar: IR::Grammar
13
16
  # @rbs @superclass: String
@@ -64,11 +67,11 @@ module Ibex
64
67
  lines.push(" end", "")
65
68
  end
66
69
 
67
- # @rbs () -> Hash[String, Hash[Symbol, untyped]]
70
+ # @rbs () -> Hash[String, syntax_definition]
68
71
  def syntax_node_definitions
69
72
  metadata = CSTMetadata.new(@grammar).build
70
73
  slots = metadata.fetch(:slots)
71
- definitions = {} #: Hash[String, Hash[Symbol, untyped]]
74
+ definitions = {} #: Hash[String, syntax_definition]
72
75
  @grammar.productions.each do |production|
73
76
  node = production.node
74
77
  next unless node
@@ -77,12 +80,13 @@ module Ibex
77
80
  name = node.fetch(:name)
78
81
  previous = definitions[name]
79
82
  fields = previous ? merge_syntax_fields(previous.fetch(:fields), slot.fetch(:fields)) : slot.fetch(:fields)
80
- definitions[name] = { name: name, kind: slot.fetch(:node_kind), fields: fields }.freeze
83
+ definition = { name: name, kind: slot.fetch(:node_kind), fields: fields }.freeze #: syntax_definition
84
+ definitions[name] = definition
81
85
  end
82
86
  definitions
83
87
  end
84
88
 
85
- # @rbs (Hash[String, untyped] left, Hash[String, untyped] right) -> Hash[String, untyped]
89
+ # @rbs (Hash[String, CSTMetadata::field_slot] left, Hash[String, CSTMetadata::field_slot] right) -> Hash[String, CSTMetadata::field_slot]
86
90
  def merge_syntax_fields(left, right)
87
91
  left.to_h do |name, left_slot|
88
92
  right_slot = right.fetch(name)
@@ -94,7 +98,7 @@ module Ibex
94
98
  end.freeze
95
99
  end
96
100
 
97
- # @rbs (Array[String] lines, Hash[Symbol, untyped] definition) -> void
101
+ # @rbs (Array[String] lines, syntax_definition definition) -> void
98
102
  def append_syntax_node_contract(lines, definition)
99
103
  name = definition.fetch(:name)
100
104
  fields = definition.fetch(:fields)
@@ -122,17 +126,21 @@ module Ibex
122
126
  types.one? ? types.fetch(0) : "(#{types.join(' | ')})"
123
127
  end
124
128
 
125
- # @rbs (Array[String] lines, Hash[String, untyped] fields) -> void
129
+ # @rbs (Array[String] lines, Hash[String, CSTMetadata::field_slot] fields) -> void
126
130
  def append_repetition_contracts(lines, fields)
127
131
  repeated = fields.select { |_field, slot| slot.is_a?(Hash) && slot[:extraction] }
128
132
  element = "Enumerator[Ibex::Runtime::CST::SyntaxNode | Ibex::Runtime::CST::SyntaxToken, void]"
129
133
  repeated.each do |field, slot|
134
+ next unless slot.is_a?(Hash)
135
+
130
136
  lines << " def each_#{field}_element: () -> #{element}"
131
137
  lines << " def each_#{field}_separator: () -> #{element}" if slot.fetch(:extraction) == :separated_list
132
138
  end
133
139
  return unless repeated.one?
134
140
 
135
141
  _field, slot = repeated.first
142
+ return unless slot.is_a?(Hash)
143
+
136
144
  lines << " def each_element: () -> #{element}"
137
145
  lines << " def each_separator: () -> #{element}" if slot.fetch(:extraction) == :separated_list
138
146
  end
@@ -320,7 +328,7 @@ module Ibex
320
328
  end
321
329
  end
322
330
 
323
- # @rbs (IR::Production production, Hash[Symbol, untyped] plan, Integer slot, Integer step_index) -> String
331
+ # @rbs (IR::Production production, IR::action_composition_plan plan, Integer slot, Integer step_index) -> String
324
332
  def composition_slot_type(production, plan, slot, step_index)
325
333
  physical = plan.fetch(:physical)
326
334
  return semantic_type(production.rhs.fetch(slot)) if slot < physical