ibex 0.1.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 (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -123
  3. data/docs/architecture.md +477 -31
  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 +106 -0
  12. data/docs/cst.md +237 -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 +306 -0
  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 +26 -0
  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 +114 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +629 -18
  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 +56 -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 +45 -6
  63. data/docs/release-readiness.md +221 -0
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +234 -0
  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/examples/README.md +60 -0
  75. data/examples/calculator.y +44 -0
  76. data/examples/csv.y +32 -0
  77. data/examples/ini.y +70 -0
  78. data/examples/json.y +48 -0
  79. data/examples/tiny_language.y +75 -0
  80. data/lib/ibex/analysis/digraph.rb +128 -0
  81. data/lib/ibex/analysis/sets.rb +5 -4
  82. data/lib/ibex/analysis.rb +1 -0
  83. data/lib/ibex/artifact_set.rb +63 -0
  84. data/lib/ibex/bison_import/importer.rb +516 -0
  85. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  86. data/lib/ibex/bison_import.rb +200 -0
  87. data/lib/ibex/bounded_subprocess.rb +171 -0
  88. data/lib/ibex/cli/ambiguity.rb +75 -0
  89. data/lib/ibex/cli/analysis.rb +134 -0
  90. data/lib/ibex/cli/bison_import.rb +121 -0
  91. data/lib/ibex/cli/config.rb +128 -0
  92. data/lib/ibex/cli/counterexample_options.rb +6 -2
  93. data/lib/ibex/cli/coverage.rb +173 -0
  94. data/lib/ibex/cli/debug.rb +106 -0
  95. data/lib/ibex/cli/diagnostics.rb +136 -0
  96. data/lib/ibex/cli/documentation.rb +70 -0
  97. data/lib/ibex/cli/equiv.rb +169 -0
  98. data/lib/ibex/cli/error_messages.rb +184 -0
  99. data/lib/ibex/cli/explain.rb +85 -0
  100. data/lib/ibex/cli/fix.rb +203 -0
  101. data/lib/ibex/cli/formatting.rb +387 -0
  102. data/lib/ibex/cli/fuzz.rb +200 -0
  103. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  104. data/lib/ibex/cli/generation_artifacts.rb +189 -0
  105. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  106. data/lib/ibex/cli/grammar_tests.rb +140 -0
  107. data/lib/ibex/cli/ir_tools.rb +128 -0
  108. data/lib/ibex/cli/lsp.rb +33 -0
  109. data/lib/ibex/cli/outputs.rb +133 -23
  110. data/lib/ibex/cli/racc_migration.rb +87 -0
  111. data/lib/ibex/cli/reduce.rb +202 -0
  112. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  113. data/lib/ibex/cli/samples.rb +118 -0
  114. data/lib/ibex/cli/verify.rb +116 -0
  115. data/lib/ibex/cli/watch.rb +104 -0
  116. data/lib/ibex/cli.rb +825 -55
  117. data/lib/ibex/codegen/action_locations.rb +103 -0
  118. data/lib/ibex/codegen/action_method_source.rb +209 -0
  119. data/lib/ibex/codegen/action_source.rb +119 -0
  120. data/lib/ibex/codegen/ambiguity.rb +174 -0
  121. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  122. data/lib/ibex/codegen/documentation.rb +170 -0
  123. data/lib/ibex/codegen/explain.rb +380 -0
  124. data/lib/ibex/codegen/generated_action_abi.rb +293 -0
  125. data/lib/ibex/codegen/html.rb +94 -10
  126. data/lib/ibex/codegen/mermaid.rb +43 -0
  127. data/lib/ibex/codegen/railroad.rb +197 -0
  128. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  129. data/lib/ibex/codegen/rbs.rb +331 -2
  130. data/lib/ibex/codegen/report.rb +67 -15
  131. data/lib/ibex/codegen/ruby.rb +305 -66
  132. data/lib/ibex/codegen/ruby_actions.rb +146 -0
  133. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  134. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  135. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  136. data/lib/ibex/codegen/ruby_syntax.rb +96 -0
  137. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  138. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  139. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  140. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  141. data/lib/ibex/configuration/explanation.rb +421 -0
  142. data/lib/ibex/configuration/inspector.rb +232 -0
  143. data/lib/ibex/configuration.rb +580 -0
  144. data/lib/ibex/coverage/collector.rb +198 -0
  145. data/lib/ibex/coverage/event_stream.rb +103 -0
  146. data/lib/ibex/coverage/report.rb +267 -0
  147. data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
  148. data/lib/ibex/coverage.rb +13 -0
  149. data/lib/ibex/delta_reducer.rb +99 -0
  150. data/lib/ibex/diff.rb +140 -0
  151. data/lib/ibex/equiv/machine.rb +135 -0
  152. data/lib/ibex/equiv.rb +373 -0
  153. data/lib/ibex/error_messages/parser.rb +159 -0
  154. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  155. data/lib/ibex/error_messages/renderer.rb +65 -0
  156. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  157. data/lib/ibex/error_messages/update.rb +169 -0
  158. data/lib/ibex/error_messages.rb +165 -0
  159. data/lib/ibex/fix.rb +557 -0
  160. data/lib/ibex/frontend/ast.rb +166 -7
  161. data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
  162. data/lib/ibex/frontend/diagnostic.rb +81 -0
  163. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  164. data/lib/ibex/frontend/dsl.rb +66 -7
  165. data/lib/ibex/frontend/formatter.rb +453 -0
  166. data/lib/ibex/frontend/generated_parser.rb +644 -190
  167. data/lib/ibex/frontend/generated_parser_base.rb +170 -32
  168. data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
  169. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  170. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  171. data/lib/ibex/frontend/generation.rb +33 -0
  172. data/lib/ibex/frontend/lexer.rb +162 -10
  173. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  174. data/lib/ibex/frontend/parser/declarations.rb +262 -11
  175. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  176. data/lib/ibex/frontend/parser/rules.rb +43 -6
  177. data/lib/ibex/frontend/parser.rb +182 -4
  178. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  179. data/lib/ibex/frontend/regenerator.rb +27 -1
  180. data/lib/ibex/frontend/resolution.rb +70 -0
  181. data/lib/ibex/frontend/resolver.rb +217 -0
  182. data/lib/ibex/frontend/rule_documentation.rb +104 -0
  183. data/lib/ibex/frontend/source_cursor.rb +133 -9
  184. data/lib/ibex/frontend/source_document.rb +229 -0
  185. data/lib/ibex/frontend/source_loader.rb +150 -0
  186. data/lib/ibex/frontend/source_span.rb +89 -0
  187. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  188. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  189. data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
  190. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  191. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  192. data/lib/ibex/frontend/token_adapter.rb +18 -3
  193. data/lib/ibex/frontend.rb +14 -2
  194. data/lib/ibex/fuzz.rb +219 -0
  195. data/lib/ibex/generation_input.rb +57 -0
  196. data/lib/ibex/generation_manifest.rb +211 -0
  197. data/lib/ibex/generation_transaction.rb +261 -0
  198. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  199. data/lib/ibex/generation_transaction_validation.rb +196 -0
  200. data/lib/ibex/grammar_tests.rb +206 -0
  201. data/lib/ibex/ir/automaton_ir.rb +86 -11
  202. data/lib/ibex/ir/grammar_ir.rb +170 -26
  203. data/lib/ibex/ir/lexer_ir.rb +76 -0
  204. data/lib/ibex/ir/parser_contract.rb +135 -0
  205. data/lib/ibex/ir/serialize.rb +268 -50
  206. data/lib/ibex/ir/validator/automaton.rb +375 -0
  207. data/lib/ibex/ir/validator/base.rb +147 -0
  208. data/lib/ibex/ir/validator/grammar.rb +634 -0
  209. data/lib/ibex/ir/validator/lexer.rb +113 -0
  210. data/lib/ibex/ir/validator.rb +63 -0
  211. data/lib/ibex/ir.rb +71 -5
  212. data/lib/ibex/lalr/build_metrics.rb +71 -0
  213. data/lib/ibex/lalr/builder.rb +514 -52
  214. data/lib/ibex/lalr/conflict.rb +1 -0
  215. data/lib/ibex/lalr/conflict_search.rb +26 -9
  216. data/lib/ibex/lalr/counterexample.rb +38 -18
  217. data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
  218. data/lib/ibex/lalr/goto_follows.rb +229 -0
  219. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  220. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  221. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  222. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  223. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  224. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  225. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  226. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  227. data/lib/ibex/lalr/ielr_partition.rb +166 -0
  228. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  229. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  230. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  231. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  232. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  233. data/lib/ibex/lalr.rb +59 -1
  234. data/lib/ibex/location.rb +129 -0
  235. data/lib/ibex/lsp/document_handlers.rb +68 -0
  236. data/lib/ibex/lsp/document_store.rb +264 -0
  237. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  238. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  239. data/lib/ibex/lsp/initialization_handlers.rb +80 -0
  240. data/lib/ibex/lsp/navigation_handlers.rb +70 -0
  241. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  242. data/lib/ibex/lsp/position_codec.rb +113 -0
  243. data/lib/ibex/lsp/protocol_error.rb +33 -0
  244. data/lib/ibex/lsp/request_handlers.rb +46 -0
  245. data/lib/ibex/lsp/request_support.rb +94 -0
  246. data/lib/ibex/lsp/server.rb +148 -0
  247. data/lib/ibex/lsp/symbol_index.rb +241 -0
  248. data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
  249. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  250. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  251. data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
  252. data/lib/ibex/lsp/transport.rb +128 -0
  253. data/lib/ibex/lsp/workspace.rb +128 -0
  254. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  255. data/lib/ibex/lsp.rb +33 -0
  256. data/lib/ibex/messages/en.yml +28 -0
  257. data/lib/ibex/messages/ja.yml +28 -0
  258. data/lib/ibex/messages.rb +68 -0
  259. data/lib/ibex/metrics.rb +175 -0
  260. data/lib/ibex/normalize/declarations.rb +142 -7
  261. data/lib/ibex/normalize/diagnostics.rb +94 -24
  262. data/lib/ibex/normalize/expander.rb +64 -59
  263. data/lib/ibex/normalize/expression.rb +63 -40
  264. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  265. data/lib/ibex/normalize/inline_expansion.rb +465 -0
  266. data/lib/ibex/normalize/inline_validation.rb +174 -0
  267. data/lib/ibex/normalize/lexer.rb +131 -0
  268. data/lib/ibex/normalize/named_references.rb +60 -0
  269. data/lib/ibex/normalize/nodes.rb +46 -0
  270. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
  271. data/lib/ibex/normalize/parameter_lowering.rb +143 -0
  272. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  273. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  274. data/lib/ibex/normalize/parameters.rb +226 -0
  275. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  276. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  277. data/lib/ibex/normalize.rb +172 -17
  278. data/lib/ibex/racc_migration/checker.rb +122 -0
  279. data/lib/ibex/racc_migration/harness.rb +177 -0
  280. data/lib/ibex/racc_migration/report.rb +97 -0
  281. data/lib/ibex/racc_migration.rb +12 -0
  282. data/lib/ibex/rake_task.rb +116 -0
  283. data/lib/ibex/samples.rb +216 -0
  284. data/lib/ibex/table_artifact/builder.rb +266 -0
  285. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  286. data/lib/ibex/table_artifact/document.rb +39 -0
  287. data/lib/ibex/table_artifact/executor.rb +187 -0
  288. data/lib/ibex/table_artifact/serializer.rb +57 -0
  289. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  290. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  291. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  292. data/lib/ibex/table_artifact/validator.rb +253 -0
  293. data/lib/ibex/table_artifact.rb +88 -0
  294. data/lib/ibex/table_simulation/result.rb +55 -0
  295. data/lib/ibex/table_simulation/simulator.rb +253 -0
  296. data/lib/ibex/table_simulation/step.rb +62 -0
  297. data/lib/ibex/table_simulation/text.rb +31 -0
  298. data/lib/ibex/table_simulation.rb +13 -0
  299. data/lib/ibex/tables.rb +22 -69
  300. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  301. data/lib/ibex/verification_report/builder.rb +159 -0
  302. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  303. data/lib/ibex/verification_report/logical_path.rb +68 -0
  304. data/lib/ibex/verification_report/validator.rb +329 -0
  305. data/lib/ibex/verification_report.rb +69 -0
  306. data/lib/ibex/verify/action_correspondence.rb +138 -0
  307. data/lib/ibex/verify/language_witness.rb +295 -0
  308. data/lib/ibex/verify/reference_collection.rb +190 -0
  309. data/lib/ibex/verify/result.rb +73 -0
  310. data/lib/ibex/verify/verifier.rb +598 -0
  311. data/lib/ibex/verify.rb +15 -0
  312. data/lib/ibex/version.rb +1 -1
  313. data/lib/ibex/watch/runner.rb +181 -0
  314. data/lib/ibex/watch/source_snapshot.rb +98 -0
  315. data/lib/ibex/watch.rb +11 -0
  316. data/lib/ibex.rb +35 -1
  317. data/schema/automaton-ir-definitions.schema.json +401 -0
  318. data/schema/automaton-ir.schema.json +65 -0
  319. data/schema/benchmark-v1.schema.json +212 -0
  320. data/schema/benchmark-v2.schema.json +61 -0
  321. data/schema/bison-import-v1.schema.json +106 -0
  322. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  323. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  324. data/schema/construction-profile-v1.schema.json +779 -0
  325. data/schema/cst-v1.json +170 -0
  326. data/schema/diff-v1.schema.json +41 -0
  327. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  328. data/schema/equiv-v1.schema.json +64 -0
  329. data/schema/error-ux-review-v1.schema.json +609 -0
  330. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  331. data/schema/error-ux-round2-v1.schema.json +519 -0
  332. data/schema/error-ux-v1.schema.json +258 -0
  333. data/schema/explain-v1.schema.json +495 -0
  334. data/schema/fix-v1.schema.json +64 -0
  335. data/schema/fix-v2.schema.json +66 -0
  336. data/schema/fix-v3.schema.json +101 -0
  337. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  338. data/schema/fuzz-regression-v1.schema.json +79 -0
  339. data/schema/fuzz-v1.schema.json +114 -0
  340. data/schema/generation-manifest-v1.schema.json +115 -0
  341. data/schema/grammar-ir-extensions.schema.json +734 -0
  342. data/schema/grammar-ir-foundation.schema.json +426 -0
  343. data/schema/grammar-ir.schema.json +271 -0
  344. data/schema/ielr-benchmark-v1.schema.json +85 -0
  345. data/schema/lexer-ir-v1.schema.json +215 -0
  346. data/schema/lexer-profile-v1.schema.json +491 -0
  347. data/schema/metrics-v1.schema.json +60 -0
  348. data/schema/migration-check-v1.schema.json +60 -0
  349. data/schema/performance-comparison-v1.schema.json +395 -0
  350. data/schema/public-performance-comparison-v1.schema.json +506 -0
  351. data/schema/public-performance-profile-v1.schema.json +360 -0
  352. data/schema/reduce-v1.schema.json +22 -0
  353. data/schema/reduce-v2.schema.json +63 -0
  354. data/schema/runtime-coverage-v1.schema.json +86 -0
  355. data/schema/runtime-event-v1.schema.json +308 -0
  356. data/schema/table-artifact-v1.schema.json +377 -0
  357. data/schema/table-simulation-v1.schema.json +70 -0
  358. data/schema/verification-report-v1.schema.json +222 -0
  359. data/schema/verify-v1.schema.json +42 -0
  360. data/sig/ibex/analysis/digraph.rbs +19 -0
  361. data/sig/ibex/artifact_set.rbs +37 -0
  362. data/sig/ibex/bison_import/importer.rbs +140 -0
  363. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  364. data/sig/ibex/bison_import.rbs +95 -0
  365. data/sig/ibex/bounded_subprocess.rbs +76 -0
  366. data/sig/ibex/cli/ambiguity.rbs +28 -0
  367. data/sig/ibex/cli/analysis.rbs +43 -0
  368. data/sig/ibex/cli/bison_import.rbs +32 -0
  369. data/sig/ibex/cli/config.rbs +35 -0
  370. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  371. data/sig/ibex/cli/coverage.rbs +53 -0
  372. data/sig/ibex/cli/debug.rbs +28 -0
  373. data/sig/ibex/cli/diagnostics.rbs +51 -0
  374. data/sig/ibex/cli/documentation.rbs +29 -0
  375. data/sig/ibex/cli/equiv.rbs +49 -0
  376. data/sig/ibex/cli/error_messages.rbs +63 -0
  377. data/sig/ibex/cli/explain.rbs +31 -0
  378. data/sig/ibex/cli/fix.rbs +53 -0
  379. data/sig/ibex/cli/formatting.rbs +107 -0
  380. data/sig/ibex/cli/fuzz.rbs +47 -0
  381. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  382. data/sig/ibex/cli/generation_artifacts.rbs +69 -0
  383. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  384. data/sig/ibex/cli/grammar_tests.rbs +48 -0
  385. data/sig/ibex/cli/ir_tools.rbs +39 -0
  386. data/sig/ibex/cli/lsp.rbs +14 -0
  387. data/sig/ibex/cli/outputs.rbs +26 -3
  388. data/sig/ibex/cli/racc_migration.rbs +30 -0
  389. data/sig/ibex/cli/reduce.rbs +60 -0
  390. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  391. data/sig/ibex/cli/samples.rbs +38 -0
  392. data/sig/ibex/cli/verify.rbs +28 -0
  393. data/sig/ibex/cli/watch.rbs +43 -0
  394. data/sig/ibex/cli.rbs +182 -9
  395. data/sig/ibex/codegen/action_locations.rbs +45 -0
  396. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  397. data/sig/ibex/codegen/action_source.rbs +50 -0
  398. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  399. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  400. data/sig/ibex/codegen/documentation.rbs +50 -0
  401. data/sig/ibex/codegen/explain.rbs +105 -0
  402. data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
  403. data/sig/ibex/codegen/html.rbs +18 -2
  404. data/sig/ibex/codegen/mermaid.rbs +16 -0
  405. data/sig/ibex/codegen/railroad.rbs +82 -0
  406. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  407. data/sig/ibex/codegen/rbs.rbs +86 -4
  408. data/sig/ibex/codegen/report.rbs +16 -8
  409. data/sig/ibex/codegen/ruby.rbs +105 -28
  410. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  411. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  412. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  413. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  414. data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
  415. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  416. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  417. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  418. data/sig/ibex/configuration/explanation.rbs +195 -0
  419. data/sig/ibex/configuration/inspector.rbs +53 -0
  420. data/sig/ibex/configuration.rbs +242 -0
  421. data/sig/ibex/coverage/collector.rbs +78 -0
  422. data/sig/ibex/coverage/event_stream.rbs +44 -0
  423. data/sig/ibex/coverage/report.rbs +102 -0
  424. data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
  425. data/sig/ibex/coverage.rbs +7 -0
  426. data/sig/ibex/delta_reducer.rbs +38 -0
  427. data/sig/ibex/diff.rbs +47 -0
  428. data/sig/ibex/equiv/machine.rbs +54 -0
  429. data/sig/ibex/equiv.rbs +129 -0
  430. data/sig/ibex/error_messages/parser.rbs +58 -0
  431. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  432. data/sig/ibex/error_messages/renderer.rbs +23 -0
  433. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  434. data/sig/ibex/error_messages/update.rbs +43 -0
  435. data/sig/ibex/error_messages.rbs +85 -0
  436. data/sig/ibex/fix.rbs +138 -0
  437. data/sig/ibex/frontend/ast.rbs +237 -22
  438. data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
  439. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  440. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  441. data/sig/ibex/frontend/dsl.rbs +33 -4
  442. data/sig/ibex/frontend/formatter.rbs +143 -0
  443. data/sig/ibex/frontend/generated_parser.rbs +228 -68
  444. data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
  445. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  446. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  447. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  448. data/sig/ibex/frontend/generation.rbs +6 -0
  449. data/sig/ibex/frontend/lexer.rbs +49 -2
  450. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  451. data/sig/ibex/frontend/parser/declarations.rbs +57 -0
  452. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  453. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  454. data/sig/ibex/frontend/parser.rbs +66 -0
  455. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  456. data/sig/ibex/frontend/regenerator.rbs +11 -0
  457. data/sig/ibex/frontend/resolution.rbs +34 -0
  458. data/sig/ibex/frontend/resolver.rbs +91 -0
  459. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  460. data/sig/ibex/frontend/source_cursor.rbs +38 -5
  461. data/sig/ibex/frontend/source_document.rbs +119 -0
  462. data/sig/ibex/frontend/source_loader.rbs +66 -0
  463. data/sig/ibex/frontend/source_span.rbs +56 -0
  464. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  465. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  466. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
  467. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  468. data/sig/ibex/frontend/token_adapter.rbs +11 -2
  469. data/sig/ibex/frontend.rbs +1 -1
  470. data/sig/ibex/fuzz.rbs +71 -0
  471. data/sig/ibex/generation_input.rbs +37 -0
  472. data/sig/ibex/generation_manifest.rbs +70 -0
  473. data/sig/ibex/generation_transaction.rbs +82 -0
  474. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  475. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  476. data/sig/ibex/grammar_tests.rbs +93 -0
  477. data/sig/ibex/ir/automaton_ir.rbs +35 -10
  478. data/sig/ibex/ir/grammar_ir.rbs +96 -22
  479. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  480. data/sig/ibex/ir/parser_contract.rbs +69 -0
  481. data/sig/ibex/ir/serialize.rbs +75 -23
  482. data/sig/ibex/ir/validator/automaton.rbs +112 -0
  483. data/sig/ibex/ir/validator/base.rbs +69 -0
  484. data/sig/ibex/ir/validator/grammar.rbs +195 -0
  485. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  486. data/sig/ibex/ir/validator.rbs +16 -0
  487. data/sig/ibex/ir.rbs +45 -5
  488. data/sig/ibex/lalr/build_metrics.rbs +60 -0
  489. data/sig/ibex/lalr/builder.rbs +150 -19
  490. data/sig/ibex/lalr/conflict_search.rbs +12 -5
  491. data/sig/ibex/lalr/counterexample.rbs +20 -14
  492. data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
  493. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  494. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  495. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  496. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  497. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  498. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  499. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  500. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  501. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  502. data/sig/ibex/lalr/ielr_partition.rbs +71 -0
  503. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  504. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  505. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  506. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  507. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  508. data/sig/ibex/lalr.rbs +17 -1
  509. data/sig/ibex/location.rbs +67 -0
  510. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  511. data/sig/ibex/lsp/document_store.rbs +94 -0
  512. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  513. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  514. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  515. data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
  516. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  517. data/sig/ibex/lsp/position_codec.rbs +44 -0
  518. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  519. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  520. data/sig/ibex/lsp/request_support.rbs +40 -0
  521. data/sig/ibex/lsp/server.rbs +55 -0
  522. data/sig/ibex/lsp/symbol_index.rbs +77 -0
  523. data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
  524. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  525. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  526. data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
  527. data/sig/ibex/lsp/transport.rbs +47 -0
  528. data/sig/ibex/lsp/workspace.rbs +42 -0
  529. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  530. data/sig/ibex/lsp.rbs +7 -0
  531. data/sig/ibex/messages.rbs +26 -0
  532. data/sig/ibex/metrics.rbs +50 -0
  533. data/sig/ibex/normalize/declarations.rbs +31 -0
  534. data/sig/ibex/normalize/diagnostics.rbs +13 -4
  535. data/sig/ibex/normalize/expander.rbs +22 -16
  536. data/sig/ibex/normalize/expression.rbs +11 -9
  537. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  538. data/sig/ibex/normalize/inline_expansion.rbs +129 -0
  539. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  540. data/sig/ibex/normalize/lexer.rbs +37 -0
  541. data/sig/ibex/normalize/named_references.rbs +20 -0
  542. data/sig/ibex/normalize/nodes.rbs +14 -0
  543. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
  544. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  545. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  546. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  547. data/sig/ibex/normalize/parameters.rbs +51 -0
  548. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  549. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  550. data/sig/ibex/normalize.rbs +129 -18
  551. data/sig/ibex/racc_migration/checker.rbs +36 -0
  552. data/sig/ibex/racc_migration/harness.rbs +16 -0
  553. data/sig/ibex/racc_migration/report.rbs +55 -0
  554. data/sig/ibex/racc_migration.rbs +8 -0
  555. data/sig/ibex/rake_task.rbs +51 -0
  556. data/sig/ibex/samples.rbs +60 -0
  557. data/sig/ibex/table_artifact/builder.rbs +93 -0
  558. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  559. data/sig/ibex/table_artifact/document.rbs +27 -0
  560. data/sig/ibex/table_artifact/executor.rbs +66 -0
  561. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  562. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  563. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  564. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  565. data/sig/ibex/table_artifact/validator.rbs +66 -0
  566. data/sig/ibex/table_artifact.rbs +32 -0
  567. data/sig/ibex/table_simulation/result.rbs +36 -0
  568. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  569. data/sig/ibex/table_simulation/step.rbs +42 -0
  570. data/sig/ibex/table_simulation/text.rbs +14 -0
  571. data/sig/ibex/table_simulation.rbs +7 -0
  572. data/sig/ibex/tables.rbs +10 -35
  573. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  574. data/sig/ibex/verification_report/builder.rbs +53 -0
  575. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  576. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  577. data/sig/ibex/verification_report/validator.rbs +114 -0
  578. data/sig/ibex/verification_report.rbs +44 -0
  579. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  580. data/sig/ibex/verify/language_witness.rbs +112 -0
  581. data/sig/ibex/verify/reference_collection.rbs +63 -0
  582. data/sig/ibex/verify/result.rbs +52 -0
  583. data/sig/ibex/verify/verifier.rbs +170 -0
  584. data/sig/ibex/verify.rbs +6 -0
  585. data/sig/ibex/watch/runner.rbs +58 -0
  586. data/sig/ibex/watch/source_snapshot.rbs +46 -0
  587. data/sig/ibex/watch.rbs +7 -0
  588. data/sig/ibex.rbs +2 -0
  589. metadata +524 -19
  590. data/.rubocop.yml +0 -43
  591. data/CHANGELOG.md +0 -30
  592. data/Rakefile +0 -25
  593. data/Steepfile +0 -10
  594. data/docs/compat-notes.md +0 -37
  595. data/docs/lexer-coverage.md +0 -14
  596. data/docs/phase10-extensions.md +0 -27
  597. data/gemfiles/Gemfile +0 -7
  598. data/gemfiles/Gemfile.lock +0 -98
  599. data/lib/ibex/frontend/grammar.y +0 -156
  600. data/lib/ibex/runtime/parser.rb +0 -360
  601. data/lib/ibex/runtime.rb +0 -8
  602. data/sig/ibex/runtime/parser.rbs +0 -167
  603. data/sig/ibex/runtime.rbs +0 -6
@@ -90,6 +90,7 @@ module Ibex
90
90
  when :left then [reduction, { by: :associativity, associativity: :left, chose: :reduce }]
91
91
  when :right then [shift, { by: :associativity, associativity: :right, chose: :shift }]
92
92
  when :nonassoc then [{ type: :error }, { by: :associativity, associativity: :nonassoc, chose: :error }]
93
+ when :precedence then [shift, { by: :default_shift, chose: :shift }]
93
94
  else raise Ibex::Error, "unknown associativity #{associativity.inspect}"
94
95
  end
95
96
  end
@@ -25,6 +25,9 @@ module Ibex
25
25
  # @rbs @max_configurations: Integer
26
26
  # @rbs @explored: Integer
27
27
  # @rbs @input_tokens: Array[Integer]
28
+ # @rbs @initial_state: Integer
29
+
30
+ attr_reader :explored #: Integer
28
31
 
29
32
  # @rbs (IR::Automaton automaton, IR::AutomatonState state, IR::conflict conflict,
30
33
  # ?max_tokens: Integer, ?max_configurations: Integer) -> void
@@ -40,27 +43,44 @@ module Ibex
40
43
  @max_configurations = max_configurations
41
44
  @explored = 0
42
45
  @input_tokens = @grammar.terminals.reject(&:reserved).sort_by(&:name).map(&:id)
46
+ entry = conflict[:entries]&.first || @grammar.start
47
+ @initial_state = automaton.entry_states.fetch(entry)
43
48
  end
44
49
 
45
- # @rbs () -> search_result?
50
+ # @rbs () -> search_outcome
46
51
  def call
47
- return unless @lookahead
52
+ return outcome(:not_found) unless @lookahead
48
53
 
49
- queue = [[configuration([0], Array.new(0)), Array.new(0)]] #: Array[[Configuration, Array[Integer]]]
50
- visited = { [0] => true }
54
+ initial = configuration([@initial_state], Array.new(0))
55
+ queue = [[initial, Array.new(0)]] #: Array[[Configuration, Array[Integer]]]
56
+ visited = { [@initial_state] => true }
51
57
  until queue.empty? || exhausted?
52
58
  current, prefix = queue.shift
53
59
  conflict_configurations(current).each do |candidate|
54
60
  result = unify_from(candidate, prefix)
55
- return result if result
61
+ return outcome(:found, result) if result
56
62
  end
57
63
  enqueue_prefixes(queue, visited, current, prefix)
58
64
  end
59
- nil
65
+ outcome(exhausted? ? :exhausted : :not_found)
60
66
  end
61
67
 
68
+ # @rbs () -> bool
69
+ def exhausted? = @explored >= @max_configurations
70
+
62
71
  private
63
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
+
64
84
  # @rbs (Configuration current) -> Array[Configuration]
65
85
  def conflict_configurations(current)
66
86
  advance(current, required_lookahead, stop_at: @state.id, branch_conflicts: true)
@@ -323,9 +343,6 @@ module Ibex
323
343
 
324
344
  # @rbs () -> Integer
325
345
  def count_configuration = (@explored += 1)
326
-
327
- # @rbs () -> bool
328
- def exhausted? = @explored >= @max_configurations
329
346
  end
330
347
  # rubocop:enable Metrics/ClassLength
331
348
  end
@@ -17,46 +17,64 @@ 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) -> search_counterexample
28
+ def for_conflict(state_id, conflict_index)
29
+ state = @automaton.states.find { |candidate| candidate.id == state_id }
30
+ raise ArgumentError, "unknown automaton state #{state_id}" unless state
31
+
32
+ unless conflict_index.is_a?(Integer) && conflict_index >= 0 && conflict_index < state.conflicts.length
33
+ raise ArgumentError, "conflict index #{conflict_index.inspect} is invalid for automaton state #{state_id}"
34
+ end
35
+
36
+ conflict = state.conflicts.fetch(conflict_index)
37
+ build_example(state, conflict)
38
+ end
39
+
27
40
  private
28
41
 
29
- # @rbs (IR::AutomatonState state, IR::conflict conflict) -> IR::counterexample
42
+ # @rbs (IR::AutomatonState state, IR::conflict conflict) -> search_counterexample
30
43
  def build_example(state, conflict)
31
- unifying = ConflictSearch.new(
44
+ outcome = ConflictSearch.new(
32
45
  @automaton, state, conflict, max_tokens: @max_tokens, max_configurations: @max_configurations
33
46
  ).call
34
- 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
35
49
 
36
- reachability_example(state, conflict)
50
+ reachability_example(state, conflict, outcome)
37
51
  end
38
52
 
39
- # @rbs (IR::AutomatonState state, IR::conflict conflict, Hash[Symbol, untyped] result) -> IR::counterexample
40
- 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)
41
56
  { state: state.id, type: conflict[:type], symbol_path: Array.new(0),
42
57
  sentence: names(result[:sentence_ids]), lookahead_index: result[:lookahead_index], unifying: true,
43
- interpretations: result[:interpretations] }
58
+ inconclusive: false, search: outcome, interpretations: result[:interpretations] }
44
59
  end
45
60
 
46
- # @rbs (IR::AutomatonState state, IR::conflict conflict) -> IR::counterexample
47
- def reachability_example(state, conflict)
48
- path = shortest_state_path(state.id)
61
+ # @rbs (IR::AutomatonState state, IR::conflict conflict, search_outcome outcome) -> search_counterexample
62
+ def reachability_example(state, conflict, outcome)
63
+ path = shortest_state_path(state.id, conflict)
49
64
  lookahead = @grammar.symbol(conflict[:symbol])
50
65
  terminal_ids = path.flat_map { |symbol_id| @shortest_yields[symbol_id] || [] }
51
66
  terminal_ids << lookahead.id if lookahead
52
67
  { state: state.id, type: conflict[:type], symbol_path: names(path), sentence: names(terminal_ids),
53
- 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) }
54
70
  end
55
71
 
56
- # @rbs (Integer target) -> Array[Integer]
57
- def shortest_state_path(target)
58
- queue = [[0, Array.new(0)]] #: Array[[Integer, Array[Integer]]]
59
- visited = { 0 => true }
72
+ # @rbs (Integer target, IR::conflict conflict) -> Array[Integer]
73
+ def shortest_state_path(target, conflict)
74
+ entry = conflict[:entries]&.first || @grammar.start
75
+ initial = @automaton.entry_states.fetch(entry)
76
+ queue = [[initial, Array.new(0)]] #: Array[[Integer, Array[Integer]]]
77
+ visited = { initial => true }
60
78
  until queue.empty?
61
79
  state_id, path = queue.shift
62
80
  return path if state_id == target
@@ -110,12 +128,14 @@ module Ibex
110
128
  end
111
129
  end
112
130
 
113
- # @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
114
134
  def shift_interpretation(conflict)
115
135
  { kind: :shift, state: conflict[:shift_to], tree: { token: conflict[:symbol] } }
116
136
  end
117
137
 
118
- # @rbs (Integer production_id) -> IR::interpretation
138
+ # @rbs (Integer production_id) -> untyped
119
139
  def reduce_interpretation(production_id)
120
140
  production = @grammar.productions.fetch(production_id)
121
141
  lhs = symbol_name(production.lhs)
@@ -0,0 +1,289 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "set"
5
+
6
+ # This class intentionally owns collection and propagation state so the
7
+ # single-start compatibility path remains byte-identical.
8
+ # rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
9
+
10
+ module Ibex
11
+ module LALR
12
+ # Builds an LR(0) collection and propagates LALR(1) lookaheads directly
13
+ # over item occurrences. Canonical LR(1) states are never materialized.
14
+ class DirectLookaheads
15
+ AUGMENTED_PRODUCTION = -1 #: Integer
16
+ EMPTY_PRODUCTIONS = Array.new(0).freeze #: Array[IR::Production]
17
+ EMPTY_NODES = Array.new(0).freeze #: Array[Integer]
18
+ private_constant :EMPTY_PRODUCTIONS, :EMPTY_NODES
19
+
20
+ attr_reader :lr0_state_count #: Integer?
21
+ attr_reader :lr0_item_count #: Integer?
22
+ attr_reader :propagation_edge_count #: Integer?
23
+ attr_reader :states #: Array[core_set]
24
+ attr_reader :transitions #: transitions
25
+
26
+ # @rbs (IR::Grammar grammar, Analysis::Sets sets, ?starts: Array[String]?, ?profile: bool) -> void
27
+ def initialize(grammar, sets, starts: nil, profile: false)
28
+ @grammar = grammar
29
+ @sets = sets
30
+ @grammar_starts = grammar_starts.freeze
31
+ @starts = (starts || @grammar_starts).dup
32
+ raise ArgumentError, "starts must be a nonempty subset of grammar starts" if
33
+ @starts.empty? || (@starts - @grammar_starts).any?
34
+
35
+ @productions_by_lhs = grammar.productions.group_by(&:lhs)
36
+ @augmented_production_ids = @starts.map { |name| AUGMENTED_PRODUCTION - start_index(name) }
37
+ @augmented_rhs = @starts.each_with_index.to_h do |name, index|
38
+ symbol = grammar.symbol(name) || raise(Ibex::Error, "missing start symbol #{name}")
39
+ [@augmented_production_ids.fetch(index), [symbol.id].freeze]
40
+ end.freeze
41
+ @production_rhs = grammar.productions.map(&:rhs).freeze
42
+ @augmented_item_cores = @augmented_rhs.to_h do |production_id, rhs|
43
+ [production_id, item_cores_for(production_id, rhs.length)]
44
+ end.freeze
45
+ @production_item_cores = grammar.productions.map do |production|
46
+ item_cores_for(production.id, production.rhs.length)
47
+ end.freeze
48
+ initialize_item_encoding
49
+ @terminal_ids = grammar.terminals.map(&:id).freeze
50
+ @terminal_masks = @terminal_ids.map { |id| 1 << id }.freeze
51
+ @terminal_ids_by_bits = {} #: Hash[Integer, Array[Integer]]
52
+ @lr0_state_count = nil
53
+ @lr0_item_count = nil
54
+ @propagation_edge_count = nil
55
+ @profile = profile
56
+ end
57
+
58
+ # @rbs () -> [Array[packed_items], transitions]
59
+ def build
60
+ states, transitions = lr0_collection
61
+ @states = states
62
+ @transitions = transitions
63
+ lookaheads = empty_lookaheads(states)
64
+ propagation = propagation_graph(states, transitions, lookaheads)
65
+ if @profile
66
+ @lr0_state_count = states.length
67
+ @lr0_item_count = states.sum(&:length)
68
+ @propagation_edge_count = propagation.values.sum(&:length)
69
+ end
70
+ @starts.each_with_index do |_name, index|
71
+ lookaheads.fetch(index).fetch(item_core(augmented_production(index), 0)) << 0
72
+ end
73
+ propagate(lookaheads, propagation)
74
+ [lookaheads, transitions]
75
+ end
76
+
77
+ # @rbs (Integer index) -> Integer
78
+ def augmented_production(index)
79
+ @augmented_production_ids.fetch(index)
80
+ end
81
+
82
+ private
83
+
84
+ # @rbs () -> void
85
+ def initialize_item_encoding
86
+ @item_key_stride = [*@augmented_rhs.values, *@production_rhs].map(&:length).max.to_i + 1
87
+ # Negative augmented ids are global to Grammar#starts. A builder
88
+ # may isolate a non-first entry, so reserve the full global range.
89
+ @production_offset = @grammar_starts.length
90
+ @node_stride = (@production_offset + @production_rhs.length) * @item_key_stride
91
+ end
92
+
93
+ # @rbs () -> [Array[core_set], transitions]
94
+ def lr0_collection
95
+ states = @starts.each_index.map { |index| closure(Set[item_core(augmented_production(index), 0)]) }
96
+ transitions = [] #: transitions
97
+ indexes = {} #: Hash[Array[Integer], Integer]
98
+ states.each_with_index { |items, index| indexes[item_key(items)] = index }
99
+ cursor = 0
100
+ while cursor < states.length
101
+ transitions[cursor] = {}
102
+ kernels = shifted_kernels(states.fetch(cursor))
103
+ kernels.keys.sort.each do |symbol_id|
104
+ target = closure(kernels.fetch(symbol_id))
105
+ key = item_key(target)
106
+ target_id = indexes[key] ||= begin
107
+ states << target
108
+ states.length - 1
109
+ end
110
+ transitions.fetch(cursor)[symbol_id] = target_id
111
+ end
112
+ cursor += 1
113
+ end
114
+ [states, transitions]
115
+ end
116
+
117
+ # @rbs (core_set seed) -> core_set
118
+ def closure(seed)
119
+ items = seed.dup
120
+ queue = seed.to_a
121
+ cursor = 0
122
+ while cursor < queue.length
123
+ production_id, dot = queue.fetch(cursor)
124
+ cursor += 1
125
+ symbol = @grammar.symbol_by_id(rhs_for(production_id)[dot])
126
+ next unless symbol&.nonterminal?
127
+
128
+ @productions_by_lhs.fetch(symbol.id, EMPTY_PRODUCTIONS).each do |production|
129
+ item = item_core(production.id, 0)
130
+ queue << item if items.add?(item)
131
+ end
132
+ end
133
+ items
134
+ end
135
+
136
+ # @rbs (core_set items) -> Hash[Integer, core_set]
137
+ def shifted_kernels(items)
138
+ kernels = {} #: Hash[Integer, core_set]
139
+ items.each do |production_id, dot|
140
+ symbol_id = rhs_for(production_id)[dot]
141
+ next unless symbol_id
142
+
143
+ (kernels[symbol_id] ||= Set.new) << item_core(production_id, dot + 1)
144
+ end
145
+ kernels
146
+ end
147
+
148
+ # @rbs (Array[core_set] states) -> Array[packed_items]
149
+ def empty_lookaheads(states)
150
+ states.map { |items| items.to_h { |item| [item, Set.new] } }
151
+ end
152
+
153
+ # @rbs (Array[core_set] states, transitions transitions, Array[packed_items] lookaheads) ->
154
+ # Hash[Integer, Array[Integer]]
155
+ def propagation_graph(states, transitions, lookaheads)
156
+ edges = Hash.new { |hash, key| hash[key] = [] } #: Hash[Integer, Array[Integer]]
157
+ states.each_with_index do |items, state_id|
158
+ items.each do |production_id, dot|
159
+ add_transition_edge(edges, transitions, state_id, production_id, dot)
160
+ add_closure_relations(edges, lookaheads, state_id, production_id, dot)
161
+ end
162
+ end
163
+ edges.each_value(&:uniq!)
164
+ edges
165
+ end
166
+
167
+ # @rbs (Hash[Integer, Array[Integer]] edges, transitions transitions,
168
+ # Integer state_id, Integer production_id, Integer dot) -> void
169
+ def add_transition_edge(edges, transitions, state_id, production_id, dot)
170
+ symbol_id = rhs_for(production_id)[dot]
171
+ return unless symbol_id
172
+
173
+ target_state = transitions.fetch(state_id).fetch(symbol_id)
174
+ edges[node_id(state_id, production_id, dot)] << node_id(target_state, production_id, dot + 1)
175
+ end
176
+
177
+ # @rbs (Hash[Integer, Array[Integer]] edges, Array[packed_items] lookaheads,
178
+ # Integer state_id, Integer production_id, Integer dot) -> void
179
+ def add_closure_relations(edges, lookaheads, state_id, production_id, dot)
180
+ rhs = rhs_for(production_id)
181
+ symbol = @grammar.symbol_by_id(rhs[dot])
182
+ return unless symbol&.nonterminal?
183
+
184
+ suffix = rhs.drop(dot + 1)
185
+ spontaneous = terminal_ids(@sets.first_of_sequence(suffix))
186
+ source = node_id(state_id, production_id, dot)
187
+ @productions_by_lhs.fetch(symbol.id, EMPTY_PRODUCTIONS).each do |production|
188
+ target_item = item_core(production.id, 0)
189
+ lookaheads.fetch(state_id).fetch(target_item).merge(spontaneous)
190
+ edges[source] << node_id(state_id, production.id, 0) if @sets.sequence_nullable?(suffix)
191
+ end
192
+ end
193
+
194
+ # @rbs (Array[packed_items] lookaheads, Hash[Integer, Array[Integer]] edges) -> void
195
+ def propagate(lookaheads, edges)
196
+ queue = lookaheads.each_with_index.flat_map do |items, state_id|
197
+ items.filter_map do |(production_id, dot), tokens|
198
+ node_id(state_id, production_id, dot) unless tokens.empty?
199
+ end
200
+ end
201
+ queued = queue.to_h { |node| [node, true] }
202
+ cursor = 0
203
+ while cursor < queue.length
204
+ source = queue.fetch(cursor)
205
+ cursor += 1
206
+ queued.delete(source)
207
+ source_set = node_set(lookaheads, source)
208
+ edges.fetch(source, EMPTY_NODES).each do |target|
209
+ target_set = node_set(lookaheads, target)
210
+ previous_size = target_set.size
211
+ target_set.merge(source_set)
212
+ next if target_set.size == previous_size || queued[target]
213
+
214
+ queue << target
215
+ queued[target] = true
216
+ end
217
+ end
218
+ end
219
+
220
+ # @rbs (Array[packed_items] lookaheads, Integer node) -> Set[Integer]
221
+ def node_set(lookaheads, node)
222
+ state_id = node / @node_stride
223
+ item = node % @node_stride
224
+ production_id = ((item / @item_key_stride) - @production_offset).to_i
225
+ dot = (item % @item_key_stride).to_i
226
+ lookaheads.fetch(state_id).fetch(item_core(production_id, dot))
227
+ end
228
+
229
+ # @rbs (Integer state_id, Integer production_id, Integer dot) -> Integer
230
+ def node_id(state_id, production_id, dot)
231
+ ((state_id * @node_stride) + ((production_id + @production_offset) * @item_key_stride) + dot).to_i
232
+ end
233
+
234
+ # @rbs (Integer bits) -> Array[Integer]
235
+ def terminal_ids(bits)
236
+ @terminal_ids_by_bits.fetch(bits) do
237
+ selected = @terminal_ids.select { |id| bits.anybits?(@terminal_masks[@terminal_ids.index(id)]) }
238
+ @terminal_ids_by_bits[bits] = selected.freeze
239
+ end
240
+ end
241
+
242
+ # @rbs (Integer production_id) -> Array[Integer]
243
+ def rhs_for(production_id)
244
+ return @augmented_rhs.fetch(production_id) if production_id.negative?
245
+
246
+ @production_rhs.fetch(production_id)
247
+ end
248
+
249
+ # @rbs (Integer production_id, Integer rhs_length) -> Array[item_core]
250
+ def item_cores_for(production_id, rhs_length)
251
+ result = Array.new(rhs_length + 1) #: Array[item_core]
252
+ rhs_length.next.times do |dot|
253
+ core = [production_id, dot].freeze #: item_core
254
+ result[dot] = core
255
+ end
256
+ result.freeze
257
+ end
258
+
259
+ # @rbs (Integer production_id, Integer dot) -> item_core
260
+ def item_core(production_id, dot)
261
+ raise IndexError, "invalid item dot: #{dot}" if dot.negative?
262
+ return @augmented_item_cores.fetch(production_id).fetch(dot) if production_id.negative?
263
+
264
+ @production_item_cores.fetch(production_id).fetch(dot)
265
+ end
266
+
267
+ # @rbs (core_set items) -> Array[Integer]
268
+ def item_key(items)
269
+ items.map do |production_id, dot|
270
+ (((production_id + @production_offset) * @item_key_stride) + dot).to_i
271
+ end.sort!
272
+ end
273
+
274
+ # @rbs (String name) -> Integer
275
+ def start_index(name)
276
+ @grammar_starts.index(name) || raise(Ibex::Error, "missing start symbol #{name}")
277
+ end
278
+
279
+ # @rbs () -> Array[String]
280
+ def grammar_starts
281
+ return @grammar.starts if @grammar.respond_to?(:starts)
282
+
283
+ [@grammar.start]
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ # rubocop:enable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity