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,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rbs_inline: enabled
2
3
 
3
4
  require "set"
4
5
 
@@ -11,10 +12,12 @@ module Ibex
11
12
 
12
13
  ALGORITHMS = %i[slr lalr ielr lr1].freeze #: Array[Symbol]
13
14
  LALR_STRATEGIES = %i[direct canonical_merge].freeze #: Array[Symbol]
15
+ IELR_STRATEGIES = %i[direct partition].freeze #: Array[Symbol]
14
16
 
15
17
  # @rbs @grammar: IR::Grammar
16
18
  # @rbs @algorithm: Symbol
17
19
  # @rbs @lalr_strategy: Symbol
20
+ # @rbs @ielr_strategy: Symbol
18
21
  # @rbs @sets: Analysis::Sets
19
22
  # @rbs @productions_by_lhs: Hash[Integer, Array[IR::Production]]
20
23
  # @rbs @resolver: ConflictResolver
@@ -22,6 +25,8 @@ module Ibex
22
25
  # @rbs @start_names: Array[String]
23
26
  # @rbs @entry_isolation: bool
24
27
  # @rbs @attribute_entries: bool
28
+ # @rbs @profile: bool
29
+ # @rbs @remove_unreachable: bool
25
30
  # @rbs @canonical_suffix_lookahead_cache: Hash[Integer, Hash[Integer, Hash[Integer, Array[Integer]]]]
26
31
  # @rbs @canonical_item_cache: Hash[Integer, Array[Array[lr_item?]?]]?
27
32
  # @rbs @canonical_key_radices: [Integer, Integer, Integer]?
@@ -29,19 +34,26 @@ module Ibex
29
34
  attr_reader :metrics #: BuildMetrics?
30
35
 
31
36
  # @rbs (IR::Grammar grammar, ?algorithm: Symbol | String, ?lalr_strategy: Symbol | String,
32
- # ?entry_isolation: bool, ?starts: Array[String]?, ?attribute_entries: bool) -> void
37
+ # ?ielr_strategy: Symbol | String,
38
+ # ?entry_isolation: bool, ?starts: Array[String]?, ?attribute_entries: bool, ?profile: bool,
39
+ # ?remove_unreachable: bool) -> void
33
40
  def initialize(grammar, algorithm: :lalr, lalr_strategy: :direct, entry_isolation: false,
34
- starts: nil, attribute_entries: true)
41
+ ielr_strategy: :partition, starts: nil, attribute_entries: true, profile: false,
42
+ remove_unreachable: false)
35
43
  unless ALGORITHMS.include?(algorithm.to_sym)
36
44
  raise ArgumentError, "unknown parser algorithm #{algorithm.inspect}"
37
45
  end
38
46
  unless LALR_STRATEGIES.include?(lalr_strategy.to_sym)
39
47
  raise ArgumentError, "unknown LALR construction strategy #{lalr_strategy.inspect}"
40
48
  end
49
+ unless IELR_STRATEGIES.include?(ielr_strategy.to_sym)
50
+ raise ArgumentError, "unknown IELR construction strategy #{ielr_strategy.inspect}"
51
+ end
41
52
 
42
53
  @grammar = grammar
43
54
  @algorithm = algorithm.to_sym
44
55
  @lalr_strategy = lalr_strategy.to_sym
56
+ @ielr_strategy = ielr_strategy.to_sym
45
57
  @sets = Analysis::Sets.new(grammar)
46
58
  @productions_by_lhs = grammar.productions.group_by(&:lhs)
47
59
  @resolver = ConflictResolver.new(grammar)
@@ -56,31 +68,43 @@ module Ibex
56
68
 
57
69
  @entry_isolation = entry_isolation
58
70
  @attribute_entries = attribute_entries
71
+ @profile = profile
72
+ @remove_unreachable = remove_unreachable
59
73
  end
60
74
 
61
75
  # @rbs () -> IR::Automaton
62
76
  def build
63
77
  return build_isolated_automaton if @entry_isolation && @start_names.length > 1
64
78
 
65
- merged_items, merged_transitions, construction_states, canonical_states, strategy = automaton_collection
79
+ merged_items, merged_transitions, collection = automaton_collection
66
80
  states = build_states(merged_items, merged_transitions)
67
81
  states = OnErrorReductions.apply(@grammar, states)
68
82
  states = DefaultReductions.apply(states, terminal_ids: @grammar.terminals.map(&:id))
69
83
  entry_states = entry_states_for(merged_items)
84
+ if @remove_unreachable
85
+ states, mapping = UnreachableStates.remove(states, entry_states.values.uniq)
86
+ entry_states = entry_states.transform_values { |state_id| mapping.fetch(state_id) }
87
+ collection[:ielr_unreachable_removed] = mapping.length - states.length if collection.respond_to?(:[]=)
88
+ end
70
89
  states = attribute_entry_conflicts(states, entry_states) if @attribute_entries && @start_names.length > 1
71
90
  summary = conflict_summary(states)
72
- @metrics = BuildMetrics.new(
73
- construction_states: construction_states,
74
- canonical_states: canonical_states,
75
- final_states: states.length,
76
- strategy: strategy
77
- )
78
- IR::Automaton.new(grammar: @grammar, states: states, conflict_summary: summary,
79
- algorithm: algorithm_name, entry_states: entry_states)
91
+ final_items, final_lookahead_items = profiled_final_item_counts(merged_items)
92
+ @metrics = build_metrics(collection, states.length, final_items, final_lookahead_items)
93
+ build_output_automaton(states: states, conflict_summary: summary, entry_states: entry_states)
80
94
  end
81
95
 
82
96
  private
83
97
 
98
+ # @rbs (states: Array[IR::AutomatonState], conflict_summary: IR::conflict_summary,
99
+ # entry_states: Hash[String, Integer]) -> IR::Automaton
100
+ def build_output_automaton(states:, conflict_summary:, entry_states:)
101
+ IR::Automaton.new(
102
+ grammar: @grammar, states: states, conflict_summary: conflict_summary,
103
+ algorithm: algorithm_name, entry_states: entry_states,
104
+ entry_construction: output_entry_construction || raise(Ibex::Error, "missing entry construction")
105
+ )
106
+ end
107
+
84
108
  # @rbs (Array[IR::AutomatonState] states) -> IR::conflict_summary
85
109
  def conflict_summary(states)
86
110
  conflicts = states.flat_map(&:conflicts)
@@ -99,39 +123,112 @@ module Ibex
99
123
  summary
100
124
  end
101
125
 
102
- # @rbs () -> [Array[packed_items], transitions, Integer, Integer?, Symbol]
126
+ # @rbs () -> [Array[packed_items], transitions, build_collection]
103
127
  def automaton_collection
104
- if @algorithm == :ielr
105
- states, transitions = canonical_collection
106
- items, merged_transitions = IELRPartition.new(@grammar, states, transitions).build
107
- return [items, merged_transitions, states.length, states.length, :ielr_partition]
108
- end
128
+ return ielr_collection if @algorithm == :ielr
129
+ return canonical_lr1_collection if @algorithm == :lr1
130
+ return merged_canonical_collection(:canonical_merge) if @lalr_strategy == :canonical_merge
131
+ return merged_canonical_collection(:canonical_merge_multi_entry) if @grammar.starts.length > 1
109
132
 
110
- if @algorithm == :lr1
111
- states, transitions = canonical_collection
112
- return [pack_canonical_items(states), transitions, states.length, states.length, :canonical_lr1]
113
- end
133
+ direct_collection
134
+ ensure
135
+ @canonical_item_cache = nil
136
+ end
114
137
 
115
- if @lalr_strategy == :canonical_merge
116
- states, transitions = canonical_collection
117
- items, merged_transitions = merge_lalr(states, transitions)
118
- apply_slr_lookaheads(items) if @algorithm == :slr
119
- return [items, merged_transitions, states.length, states.length, :canonical_merge]
120
- end
138
+ # @rbs () -> [Array[packed_items], transitions, build_collection]
139
+ def ielr_collection
140
+ return ielr_direct_collection if @ielr_strategy == :direct
121
141
 
122
- if @grammar.starts.length > 1
123
- states, transitions = canonical_collection
124
- items, merged_transitions = merge_lalr(states, transitions)
125
- apply_slr_lookaheads(items) if @algorithm == :slr
126
- return [items, merged_transitions, states.length, states.length, :canonical_merge_multi_entry]
127
- end
142
+ states, transitions = canonical_collection
143
+ partition = IELRPartition.new(@grammar, states, transitions, profile: @profile)
144
+ items, merged_transitions = partition.build
145
+ profile = canonical_profile(states, strategy: :ielr_partition)
146
+ profile[:ielr_initial_partitions] = partition.initial_partition_count
147
+ profile[:ielr_final_partitions] = partition.final_partition_count
148
+ [items, merged_transitions, profile]
149
+ end
150
+
151
+ # @rbs () -> [Array[packed_items], transitions, build_collection]
152
+ def ielr_direct_collection
153
+ pipeline = IELR::Pipeline.new(@grammar, @sets, starts: @start_names, profile: @profile)
154
+ pipeline.build
155
+ end
128
156
 
129
- items, transitions = DirectLookaheads.new(@grammar, @sets).build
157
+ # @rbs () -> [Array[packed_items], transitions, build_collection]
158
+ def canonical_lr1_collection
159
+ states, transitions = canonical_collection
160
+ [pack_canonical_items(states), transitions, canonical_profile(states, strategy: :canonical_lr1)]
161
+ end
162
+
163
+ # @rbs (Symbol strategy) -> [Array[packed_items], transitions, build_collection]
164
+ def merged_canonical_collection(strategy)
165
+ states, transitions = canonical_collection
166
+ items, merged_transitions = merge_lalr(states, transitions)
130
167
  apply_slr_lookaheads(items) if @algorithm == :slr
131
- collection = [items, transitions, items.length, nil, :direct_lalr]
132
- collection #: [Array[packed_items], transitions, Integer, Integer?, Symbol]
133
- ensure
134
- @canonical_item_cache = nil
168
+ [items, merged_transitions, canonical_profile(states, strategy: strategy)]
169
+ end
170
+
171
+ # @rbs () -> untyped
172
+ def direct_collection
173
+ direct = DirectLookaheads.new(@grammar, @sets, profile: @profile)
174
+ items, transitions = direct.build
175
+ apply_slr_lookaheads(items) if @algorithm == :slr
176
+ profile = {
177
+ construction_states: items.length, canonical_states: nil, strategy: :direct_lalr,
178
+ lr0_states: direct.lr0_state_count, lr0_items: direct.lr0_item_count, canonical_items: nil,
179
+ propagation_edges: direct.propagation_edge_count,
180
+ ielr_initial_partitions: nil, ielr_final_partitions: nil,
181
+ ielr_annotations: nil, ielr_annotated_states: nil, ielr_inadequacies: nil,
182
+ ielr_split_stable_discarded: nil, ielr_lalr_states: nil, ielr_split_states: nil,
183
+ ielr_unreachable_removed: nil, ielr_remergeable_candidates: nil
184
+ }
185
+ [items, transitions, profile]
186
+ end
187
+
188
+ # @rbs (Array[item_set] states, strategy: Symbol) -> build_collection
189
+ def canonical_profile(states, strategy:)
190
+ cores = states.to_h { |items| [core_key(items), true] }.keys if @profile
191
+ {
192
+ construction_states: states.length, canonical_states: states.length, strategy: strategy,
193
+ lr0_states: cores&.length, lr0_items: cores&.sum(&:length),
194
+ canonical_items: @profile ? states.sum(&:length) : nil,
195
+ propagation_edges: nil, ielr_initial_partitions: nil, ielr_final_partitions: nil,
196
+ ielr_annotations: nil, ielr_annotated_states: nil, ielr_inadequacies: nil,
197
+ ielr_split_stable_discarded: nil, ielr_lalr_states: nil, ielr_split_states: nil,
198
+ ielr_unreachable_removed: nil, ielr_remergeable_candidates: nil
199
+ }
200
+ end
201
+
202
+ # @rbs (Array[packed_items] items) -> [Integer?, Integer?]
203
+ def profiled_final_item_counts(items)
204
+ return [nil, nil] unless @profile
205
+
206
+ [items.sum(&:length), items.sum { |state| state.values.sum(&:length) }]
207
+ end
208
+
209
+ # @rbs (build_collection collection, Integer final_states, Integer? final_items,
210
+ # Integer? final_lookahead_items) -> BuildMetrics
211
+ def build_metrics(collection, final_states, final_items, final_lookahead_items)
212
+ BuildMetrics.new(
213
+ construction_states: collection.fetch(:construction_states),
214
+ canonical_states: collection.fetch(:canonical_states),
215
+ strategy: collection.fetch(:strategy),
216
+ lr0_states: collection.fetch(:lr0_states),
217
+ lr0_items: collection.fetch(:lr0_items),
218
+ canonical_items: collection.fetch(:canonical_items),
219
+ propagation_edges: collection.fetch(:propagation_edges),
220
+ ielr_initial_partitions: collection.fetch(:ielr_initial_partitions),
221
+ ielr_final_partitions: collection.fetch(:ielr_final_partitions),
222
+ ielr_annotations: collection.fetch(:ielr_annotations, nil),
223
+ ielr_annotated_states: collection.fetch(:ielr_annotated_states, nil),
224
+ ielr_inadequacies: collection.fetch(:ielr_inadequacies, nil),
225
+ ielr_split_stable_discarded: collection.fetch(:ielr_split_stable_discarded, nil),
226
+ ielr_lalr_states: collection.fetch(:ielr_lalr_states, nil),
227
+ ielr_split_states: collection.fetch(:ielr_split_states, nil),
228
+ ielr_unreachable_removed: collection.fetch(:ielr_unreachable_removed, nil),
229
+ ielr_remergeable_candidates: collection.fetch(:ielr_remergeable_candidates, nil),
230
+ final_states: final_states, final_items: final_items, final_lookahead_items: final_lookahead_items
231
+ )
135
232
  end
136
233
 
137
234
  # @rbs () -> String
@@ -335,21 +432,21 @@ module Ibex
335
432
  end
336
433
 
337
434
  # Conflict hashes are produced locally immediately before this boundary.
338
- # Keeping the parameter untyped avoids duplicating both discriminated
339
- # hash variants solely to add their common optional provenance field.
340
- # @rbs (untyped conflict) -> IR::conflict
435
+ # Both conflict variants carry the same optional midrule provenance field.
436
+ # @rbs (IR::conflict conflict) -> IR::conflict
341
437
  def attribute_midrule_conflict(conflict)
342
438
  production_ids = if conflict[:type] == :shift_reduce
343
439
  [conflict[:reduce]]
344
440
  else
345
441
  conflict[:reductions]
346
- end
442
+ end #: Array[Integer]
347
443
  origins = production_ids.filter_map do |production_id|
348
444
  production = @grammar.productions.fetch(production_id)
349
445
  production.origin[:loc] if production.origin[:kind] == :inline_action
350
446
  end
351
- conflict[:midrule_origins] = origins.uniq unless origins.empty?
352
- conflict
447
+ result = conflict.dup #: Hash[Symbol, untyped]
448
+ result[:midrule_origins] = origins.uniq unless origins.empty?
449
+ result #: IR::conflict
353
450
  end
354
451
 
355
452
  # @rbs (Array[IR::AutomatonItem] items, Hash[Integer, Array[IR::parser_action]] candidates) -> void
@@ -465,23 +562,60 @@ module Ibex
465
562
  canonical_counts << metrics.canonical_states
466
563
  end
467
564
  canonical_states = canonical_counts.compact.sum if canonical_counts.none?(&:nil?)
468
- @metrics = BuildMetrics.new(
469
- construction_states: construction_states,
470
- canonical_states: canonical_states,
471
- final_states: states.length,
472
- strategy: :entry_isolation
565
+ @metrics = isolated_metrics(entries, construction_states, canonical_states, states.length)
566
+ build_output_automaton(
567
+ states: states, conflict_summary: conflict_summary(states), entry_states: entry_states
473
568
  )
474
- IR::Automaton.new(
475
- grammar: @grammar, states: states, conflict_summary: conflict_summary(states),
476
- algorithm: algorithm_name, entry_states: entry_states
569
+ end
570
+
571
+ # @rbs (Array[[String, IR::Automaton, BuildMetrics]] entries, Integer construction_states,
572
+ # Integer? canonical_states, Integer final_states) -> BuildMetrics
573
+ def isolated_metrics(entries, construction_states, canonical_states, final_states)
574
+ BuildMetrics.new(
575
+ construction_states: construction_states, canonical_states: canonical_states,
576
+ final_states: final_states, strategy: :entry_isolation,
577
+ lr0_states: sum_optional_metric(entries, :lr0_states),
578
+ lr0_items: sum_optional_metric(entries, :lr0_items),
579
+ canonical_items: sum_optional_metric(entries, :canonical_items),
580
+ final_items: sum_optional_metric(entries, :final_items),
581
+ final_lookahead_items: sum_optional_metric(entries, :final_lookahead_items),
582
+ propagation_edges: sum_optional_metric(entries, :propagation_edges),
583
+ ielr_initial_partitions: sum_optional_metric(entries, :ielr_initial_partitions),
584
+ ielr_final_partitions: sum_optional_metric(entries, :ielr_final_partitions),
585
+ ielr_annotations: sum_optional_metric(entries, :ielr_annotations),
586
+ ielr_annotated_states: sum_optional_metric(entries, :ielr_annotated_states),
587
+ ielr_inadequacies: sum_optional_metric(entries, :ielr_inadequacies),
588
+ ielr_split_stable_discarded: sum_optional_metric(entries, :ielr_split_stable_discarded),
589
+ ielr_lalr_states: sum_optional_metric(entries, :ielr_lalr_states),
590
+ ielr_split_states: sum_optional_metric(entries, :ielr_split_states),
591
+ ielr_unreachable_removed: sum_optional_metric(entries, :ielr_unreachable_removed),
592
+ ielr_remergeable_candidates: sum_optional_metric(entries, :ielr_remergeable_candidates)
477
593
  )
478
594
  end
479
595
 
596
+ # @rbs (Array[[String, IR::Automaton, BuildMetrics]] entries, Symbol method) -> Integer?
597
+ def sum_optional_metric(entries, method)
598
+ values = entries.map { |_name, _automaton, metrics| metrics.public_send(method) }
599
+ values.compact.sum if values.none?(&:nil?)
600
+ end
601
+
602
+ # @rbs () -> Integer
603
+ def output_schema_version
604
+ IR::SCHEMA_VERSION
605
+ end
606
+
607
+ # @rbs () -> String?
608
+ def output_entry_construction
609
+ @entry_isolation ? "isolated" : "shared"
610
+ end
611
+
480
612
  # @rbs (String name) -> [String, IR::Automaton, BuildMetrics]
481
613
  def isolated_entry(name)
482
614
  builder = self.class.new(
483
615
  @grammar, algorithm: @algorithm, lalr_strategy: @lalr_strategy,
484
- starts: [name], attribute_entries: false
616
+ ielr_strategy: @ielr_strategy,
617
+ starts: [name], entry_isolation: true, attribute_entries: false, profile: @profile,
618
+ remove_unreachable: @remove_unreachable
485
619
  )
486
620
  automaton = builder.build
487
621
  metrics = builder.metrics
@@ -569,11 +703,12 @@ module Ibex
569
703
  reachable
570
704
  end
571
705
 
572
- # @rbs () -> Set[Array[untyped]]
706
+ # @rbs () -> Set[conflict_fingerprint]
573
707
  def isolated_conflict_fingerprints
574
708
  @start_names.each_with_object(Set.new) do |name, fingerprints|
575
709
  isolated = self.class.new(
576
710
  @grammar, algorithm: @algorithm, lalr_strategy: @lalr_strategy,
711
+ ielr_strategy: @ielr_strategy,
577
712
  starts: [name], attribute_entries: false
578
713
  ).build
579
714
  isolated.states.each do |state|
@@ -582,13 +717,13 @@ module Ibex
582
717
  end
583
718
  end
584
719
 
585
- # @rbs (IR::conflict conflict) -> Array[untyped]
720
+ # @rbs (IR::conflict conflict) -> conflict_fingerprint
586
721
  def conflict_fingerprint(conflict)
587
722
  reductions = if conflict[:type] == :shift_reduce
588
723
  [conflict[:reduce]]
589
724
  else
590
725
  conflict[:reductions]
591
- end
726
+ end #: Array[Integer]
592
727
  [conflict[:type], conflict[:symbol], reductions]
593
728
  end
594
729
  end
@@ -47,9 +47,9 @@ module Ibex
47
47
  @initial_state = automaton.entry_states.fetch(entry)
48
48
  end
49
49
 
50
- # @rbs () -> search_result?
50
+ # @rbs () -> search_outcome
51
51
  def call
52
- return unless @lookahead
52
+ return outcome(:not_found) unless @lookahead
53
53
 
54
54
  initial = configuration([@initial_state], Array.new(0))
55
55
  queue = [[initial, Array.new(0)]] #: Array[[Configuration, Array[Integer]]]
@@ -58,11 +58,11 @@ module Ibex
58
58
  current, prefix = queue.shift
59
59
  conflict_configurations(current).each do |candidate|
60
60
  result = unify_from(candidate, prefix)
61
- return result if result
61
+ return outcome(:found, result) if result
62
62
  end
63
63
  enqueue_prefixes(queue, visited, current, prefix)
64
64
  end
65
- nil
65
+ outcome(exhausted? ? :exhausted : :not_found)
66
66
  end
67
67
 
68
68
  # @rbs () -> bool
@@ -70,6 +70,17 @@ module Ibex
70
70
 
71
71
  private
72
72
 
73
+ # @rbs (:found | :not_found | :exhausted status, ?search_result? result) -> search_outcome
74
+ def outcome(status, result = nil)
75
+ {
76
+ status: status,
77
+ result: result,
78
+ explored: @explored,
79
+ exhausted: status == :exhausted,
80
+ bounds: { max_tokens: @max_tokens, max_configurations: @max_configurations }
81
+ }
82
+ end
83
+
73
84
  # @rbs (Configuration current) -> Array[Configuration]
74
85
  def conflict_configurations(current)
75
86
  advance(current, required_lookahead, stop_at: @state.id, branch_conflicts: true)
@@ -17,14 +17,14 @@ module Ibex
17
17
  @shortest_yields = compute_shortest_yields
18
18
  end
19
19
 
20
- # @rbs () -> Array[IR::counterexample]
20
+ # @rbs () -> Array[search_counterexample]
21
21
  def all
22
22
  @automaton.states.flat_map do |state|
23
23
  state.conflicts.map { |conflict| build_example(state, conflict) }
24
24
  end
25
25
  end
26
26
 
27
- # @rbs (Integer state_id, Integer conflict_index) -> IR::counterexample
27
+ # @rbs (Integer state_id, Integer conflict_index) -> search_counterexample
28
28
  def for_conflict(state_id, conflict_index)
29
29
  state = @automaton.states.find { |candidate| candidate.id == state_id }
30
30
  raise ArgumentError, "unknown automaton state #{state_id}" unless state
@@ -39,31 +39,34 @@ module Ibex
39
39
 
40
40
  private
41
41
 
42
- # @rbs (IR::AutomatonState state, IR::conflict conflict) -> IR::counterexample
42
+ # @rbs (IR::AutomatonState state, IR::conflict conflict) -> search_counterexample
43
43
  def build_example(state, conflict)
44
- unifying = ConflictSearch.new(
44
+ outcome = ConflictSearch.new(
45
45
  @automaton, state, conflict, max_tokens: @max_tokens, max_configurations: @max_configurations
46
46
  ).call
47
- return unifying_example(state, conflict, unifying) if unifying
47
+ result = outcome[:result]
48
+ return unifying_example(state, conflict, outcome, result) if outcome[:status] == :found && result
48
49
 
49
- reachability_example(state, conflict)
50
+ reachability_example(state, conflict, outcome)
50
51
  end
51
52
 
52
- # @rbs (IR::AutomatonState state, IR::conflict conflict, Hash[Symbol, untyped] result) -> IR::counterexample
53
- def unifying_example(state, conflict, result)
53
+ # @rbs (IR::AutomatonState state, IR::conflict conflict, search_outcome outcome,
54
+ # search_result result) -> search_counterexample
55
+ def unifying_example(state, conflict, outcome, result)
54
56
  { state: state.id, type: conflict[:type], symbol_path: Array.new(0),
55
57
  sentence: names(result[:sentence_ids]), lookahead_index: result[:lookahead_index], unifying: true,
56
- interpretations: result[:interpretations] }
58
+ inconclusive: false, search: outcome, interpretations: result[:interpretations] }
57
59
  end
58
60
 
59
- # @rbs (IR::AutomatonState state, IR::conflict conflict) -> IR::counterexample
60
- def reachability_example(state, conflict)
61
+ # @rbs (IR::AutomatonState state, IR::conflict conflict, search_outcome outcome) -> search_counterexample
62
+ def reachability_example(state, conflict, outcome)
61
63
  path = shortest_state_path(state.id, conflict)
62
64
  lookahead = @grammar.symbol(conflict[:symbol])
63
65
  terminal_ids = path.flat_map { |symbol_id| @shortest_yields[symbol_id] || [] }
64
66
  terminal_ids << lookahead.id if lookahead
65
67
  { state: state.id, type: conflict[:type], symbol_path: names(path), sentence: names(terminal_ids),
66
- lookahead_index: terminal_ids.length - 1, unifying: false, interpretations: interpretations(conflict) }
68
+ lookahead_index: terminal_ids.length - 1, unifying: false,
69
+ inconclusive: outcome[:status] == :exhausted, search: outcome, interpretations: interpretations(conflict) }
67
70
  end
68
71
 
69
72
  # @rbs (Integer target, IR::conflict conflict) -> Array[Integer]
@@ -125,12 +128,14 @@ module Ibex
125
128
  end
126
129
  end
127
130
 
128
- # @rbs (IR::shift_reduce_conflict conflict) -> IR::interpretation
131
+ # The compact counterexample tree intentionally uses a lightweight shape
132
+ # whose children are symbol names rather than recursively expanded nodes.
133
+ # @rbs (IR::shift_reduce_conflict conflict) -> untyped
129
134
  def shift_interpretation(conflict)
130
135
  { kind: :shift, state: conflict[:shift_to], tree: { token: conflict[:symbol] } }
131
136
  end
132
137
 
133
- # @rbs (Integer production_id) -> IR::interpretation
138
+ # @rbs (Integer production_id) -> untyped
134
139
  def reduce_interpretation(production_id)
135
140
  production = @grammar.productions.fetch(production_id)
136
141
  lhs = symbol_name(production.lhs)