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
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require_relative "bits"
7
+
8
+ module Ibex
9
+ module LALR
10
+ module IELR
11
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12
+ module SplitStability
13
+ MAX_ENUMERATED_POTENTIALS = 12
14
+
15
+ module_function
16
+
17
+ # @rbs (Annotation) -> bool
18
+ def simple?(annotation)
19
+ annotation.matrix.all? { |row| row.nil? || row.zero? }
20
+ end
21
+
22
+ # @rbs (Annotation, ConflictResolver) -> bool
23
+ def split_stable?(annotation, resolver)
24
+ return true if simple?(annotation)
25
+
26
+ contributions = annotation.inadequacy.contributions
27
+ kept = contributions.each_index.reject { |index| annotation.matrix[index]&.zero? }
28
+ return true if kept.empty?
29
+
30
+ potential = kept.reject { |index| annotation.matrix[index].nil? }
31
+ return false if potential.length > MAX_ENUMERATED_POTENTIALS
32
+
33
+ base = resolve(resolver, annotation.inadequacy.token, kept.map { |index| contributions[index] })
34
+ subsets(potential).all? do |removed|
35
+ remaining = kept.reject { |index| removed.include?(index) }
36
+ remaining.empty? || resolve(resolver, annotation.inadequacy.token,
37
+ remaining.map { |index| contributions[index] }) == base
38
+ end
39
+ end
40
+
41
+ # @rbs (ConflictResolver, Integer, Array[Object]) -> Object?
42
+ def resolve(resolver, token, contributions)
43
+ actions = contributions.map do |kind, production_id|
44
+ case kind
45
+ when :shift then { type: :shift, state: 0 }
46
+ when :reduce then { type: :reduce, production: production_id }
47
+ when :accept then { type: :accept }
48
+ when :error then { type: :error }
49
+ else raise Ibex::Error, "unknown IELR contribution #{kind.inspect}"
50
+ end
51
+ end
52
+ action, = resolver.resolve(token, actions)
53
+ normalize(action)
54
+ end
55
+
56
+ # @rbs (Object?) -> Object?
57
+ def normalize(action)
58
+ return nil unless action
59
+ return [:shift] if action[:type] == :shift
60
+ return [:reduce, action[:production]] if action[:type] == :reduce
61
+ return [:accept] if action[:type] == :accept
62
+ return [:error] if action[:type] == :error
63
+
64
+ action
65
+ end
66
+
67
+ # @rbs (Array[Integer]) -> Array[Array[Integer]]
68
+ def subsets(values)
69
+ (0...(1 << values.length)).map do |bits|
70
+ values.each_index.filter_map { |index| values.fetch(index) if bits.anybits?(1 << index) }
71
+ end
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
75
+ end
76
+ end
77
+ end
78
+ # steep:ignore:end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module LALR
6
+ module IELR
7
+ # @rbs skip
8
+ SplitState = Struct.new(:core, :transitions, :lalr_isocore, keyword_init: true)
9
+
10
+ # @rbs!
11
+ # class SplitState < Struct[Array[item_core] | Array[[Integer, Integer]] | Integer]
12
+ # attr_accessor core: Array[item_core]
13
+ # attr_accessor transitions: Array[[Integer, Integer]]
14
+ # attr_accessor lalr_isocore: Integer
15
+ # def self.new: (core: Array[item_core], transitions: Array[[Integer, Integer]],
16
+ # lalr_isocore: Integer) -> instance
17
+ # end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,258 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require "set"
7
+ require_relative "bits"
8
+ require_relative "split_state"
9
+ require_relative "annotator"
10
+ require_relative "split_stability"
11
+
12
+ module Ibex
13
+ module LALR
14
+ module IELR
15
+ # Splits LR(0) isocores only where an inadequacy would change the
16
+ # resolved action. New states copy their transition arrays; no mutable
17
+ # transition table is shared between isocores.
18
+ class StateSplitter
19
+ attr_reader :annotations #: Array[Array[Annotation]]
20
+ attr_reader :states #: Array[SplitState]
21
+ attr_reader :lalr_isocores #: Array[Integer]
22
+ attr_reader :split_states #: Integer
23
+ attr_reader :inadequacies #: Array[Array[Inadequacy]]
24
+ attr_reader :split_stable_discarded #: Integer
25
+
26
+ # @rbs (IR::Grammar grammar, Array[core_set] states, transitions transitions,
27
+ # Array[packed_items] items, GotoFollows goto_follows, ?resolver: ConflictResolver?) -> void
28
+ # rubocop:disable Metrics/AbcSize -- initialization wires the phase tables once.
29
+ def initialize(grammar, states, transitions, items, goto_follows, resolver: nil)
30
+ @grammar = grammar
31
+ @base_states = states
32
+ @base_transitions = transitions
33
+ @base_items = items
34
+ @goto_follows = goto_follows
35
+ @resolver = resolver || ConflictResolver.new(grammar)
36
+ @kernel_cores = states.map { |state| kernel_items(state) }
37
+ annotator = Annotator.new(grammar, states, transitions, items, goto_follows, resolver: @resolver)
38
+ @annotations = annotator.build
39
+ @inadequacies = annotator.inadequacies
40
+ @split_stable_discarded = annotator.split_stable_discarded
41
+ @item_lookaheads = annotator.item_lookaheads
42
+ @states = states.each_with_index.map do |_state, state_id|
43
+ SplitState.new(core: @kernel_cores.fetch(state_id),
44
+ transitions: transitions.fetch(state_id).sort_by(&:first).map(&:dup),
45
+ lalr_isocore: state_id)
46
+ end
47
+ @lalr_isocores = states.each_index.to_a
48
+ @isocore_nexts = states.each_index.to_a
49
+ @lookaheads_recomputed = Array.new(states.length, false)
50
+ @lookahead_sets = states.each_with_index.map do |_state, state_id|
51
+ @kernel_cores.fetch(state_id).each_index.map do |index|
52
+ @item_lookaheads.fetch(state_id, index)
53
+ end
54
+ end
55
+ @filters = {}
56
+ @split_states = 0
57
+ end
58
+ # rubocop:enable Metrics/AbcSize
59
+
60
+ # @rbs () -> [Array[packed_items], transitions]
61
+ def build
62
+ state_id = 0
63
+ while state_id < @states.length
64
+ @states.fetch(state_id).transitions.each_index do |index|
65
+ target = @states.fetch(state_id).transitions.fetch(index).fetch(1)
66
+ compute_state(state_id, target, index)
67
+ end
68
+ state_id += 1
69
+ end
70
+ [pack_items, packed_transitions]
71
+ end
72
+
73
+ private
74
+
75
+ # @rbs (Integer from_id, Integer to_id, Integer transition_index) -> void
76
+ def compute_state(from_id, to_id, transition_index)
77
+ incoming = propagate_lookaheads(from_id, to_id)
78
+ target = to_id
79
+ found = false
80
+ loop do
81
+ if compatible?(target, incoming)
82
+ found = true
83
+ break
84
+ end
85
+ break if @isocore_nexts.fetch(target) == to_id
86
+
87
+ target = @isocore_nexts.fetch(target)
88
+ end
89
+
90
+ if !found
91
+ target = append_isocore(target, incoming)
92
+ elsif !@lookaheads_recomputed.fetch(target)
93
+ raise Ibex::Error, "IELR target changed before initial lookahead computation" unless target == to_id
94
+
95
+ @lookahead_sets[target] = incoming
96
+ @lookaheads_recomputed[target] = true
97
+ else
98
+ merge_lookaheads(target, incoming)
99
+ end
100
+ @states.fetch(from_id).transitions.fetch(transition_index)[1] = target
101
+ end
102
+
103
+ # @rbs (Integer from_id, Integer to_id) -> Array[Integer]
104
+ def propagate_lookaheads(from_id, to_id)
105
+ filters = lookahead_set_filters(to_id)
106
+ @kernel_cores.fetch(to_id).each_with_index.map do |(production_id, dot), index|
107
+ bits = if dot > 1
108
+ previous = kernel_index_of(from_id, production_id, dot - 1)
109
+ previous ? @lookahead_sets.fetch(from_id).fetch(previous) : 0
110
+ elsif dot == 1
111
+ compute_goto_follow_set(from_id, lhs_for(production_id))
112
+ else
113
+ raise Ibex::Error, "IELR transition produced a dot-zero kernel"
114
+ end
115
+ bits & filters.fetch(index)
116
+ end
117
+ end
118
+
119
+ # @rbs (Integer state_id, Integer nonterminal_id) -> Integer
120
+ def compute_goto_follow_set(state_id, nonterminal_id)
121
+ goto_id = @goto_follows.goto_for(@lalr_isocores.fetch(state_id), nonterminal_id)
122
+ raise Ibex::Error, "missing GOTO for #{nonterminal_id} from #{state_id}" unless goto_id
123
+
124
+ bits = @goto_follows.always_follows.fetch(goto_id)
125
+ Bits.each_set_bit(@goto_follows.follow_kernel_items.fetch(goto_id)) do |index|
126
+ bits |= @lookahead_sets.fetch(state_id).fetch(index)
127
+ end
128
+ bits
129
+ end
130
+
131
+ # @rbs (Integer state_id) -> Array[Integer]
132
+ def lookahead_set_filters(state_id)
133
+ core_id = @lalr_isocores.fetch(state_id)
134
+ return @filters.fetch(core_id) if @filters.key?(core_id)
135
+
136
+ filters = Array.new(@kernel_cores.fetch(core_id).length, 0)
137
+ @annotations.fetch(core_id).each do |annotation|
138
+ token_bit = 1 << annotation.inadequacy.token
139
+ annotation.matrix.each do |row|
140
+ next if row.nil?
141
+
142
+ Bits.each_set_bit(row) { |index| filters[index] |= token_bit }
143
+ end
144
+ end
145
+ @filters[core_id] = filters
146
+ end
147
+
148
+ # @rbs (Integer state_id, Array[Integer]) -> bool
149
+ def compatible?(state_id, incoming)
150
+ return true unless @lookaheads_recomputed.fetch(state_id)
151
+
152
+ @annotations.fetch(@lalr_isocores.fetch(state_id)).all? do |annotation|
153
+ current = dominant_contribution(annotation, @lookahead_sets.fetch(state_id))
154
+ next true unless current
155
+
156
+ candidate = dominant_contribution(annotation, incoming)
157
+ !candidate || current == candidate
158
+ end
159
+ end
160
+
161
+ # @rbs (Annotation, Array[Integer]) -> Object?
162
+ def dominant_contribution(annotation, lookaheads)
163
+ token_bit = 1 << annotation.inadequacy.token
164
+ selected = annotation.inadequacy.contributions.each_index.select do |index|
165
+ row = annotation.matrix.fetch(index)
166
+ row.nil? || Bits.each_set_bit(row).any? { |kernel| lookaheads.fetch(kernel).anybits?(token_bit) }
167
+ end
168
+ return nil if selected.empty?
169
+
170
+ contributions = selected.map { |index| annotation.inadequacy.contributions.fetch(index) }
171
+ SplitStability.resolve(@resolver, annotation.inadequacy.token, contributions)
172
+ end
173
+
174
+ # @rbs (Integer after_id, Array[Integer]) -> Integer
175
+ def append_isocore(after_id, lookaheads)
176
+ source = @states.fetch(after_id)
177
+ @states << SplitState.new(
178
+ core: source.core.dup,
179
+ transitions: source.transitions.map(&:dup),
180
+ lalr_isocore: @lalr_isocores.fetch(after_id)
181
+ )
182
+ appended = @states.length - 1
183
+ @lalr_isocores << @lalr_isocores.fetch(after_id)
184
+ @isocore_nexts << @isocore_nexts.fetch(after_id)
185
+ @isocore_nexts[after_id] = appended
186
+ @lookaheads_recomputed << true
187
+ @lookahead_sets << lookaheads
188
+ @split_states += 1
189
+ appended
190
+ end
191
+
192
+ # @rbs (Integer state_id, Array[Integer]) -> void
193
+ def merge_lookaheads(state_id, incoming)
194
+ changed = false
195
+ incoming.each_with_index do |bits, index|
196
+ added = bits & ~@lookahead_sets.fetch(state_id).fetch(index)
197
+ next if added.zero?
198
+
199
+ @lookahead_sets.fetch(state_id)[index] |= added
200
+ changed = true
201
+ end
202
+ return unless changed
203
+
204
+ @states.fetch(state_id).transitions.each_index do |index|
205
+ target = @states.fetch(state_id).transitions.fetch(index).fetch(1)
206
+ break unless @lookaheads_recomputed.fetch(target)
207
+
208
+ compute_state(state_id, target, index)
209
+ end
210
+ end
211
+
212
+ # @rbs () -> Array[packed_items]
213
+ def pack_items
214
+ @states.each_with_index.map do |state, state_id|
215
+ packed = Hash.new { |hash, key| hash[key] = Set.new }
216
+ @base_items.fetch(state.lalr_isocore).each do |core, values|
217
+ packed[core].merge(values)
218
+ end
219
+ state.core.each_with_index do |core, index|
220
+ packed[core] = Set.new(Bits.each_set_bit(@lookahead_sets.fetch(state_id).fetch(index)).to_a)
221
+ end
222
+ packed
223
+ end
224
+ end
225
+
226
+ # @rbs () -> transitions
227
+ def packed_transitions
228
+ @states.map { |state| state.transitions.to_h { |symbol, target| [symbol, target] } }
229
+ end
230
+
231
+ # @rbs (core_set items) -> Array[item_core]
232
+ def kernel_items(items)
233
+ items.select { |production_id, dot| production_id.negative? || dot.positive? }.to_a.sort
234
+ end
235
+
236
+ # @rbs (Integer state_id, Integer production_id, Integer dot) -> Integer?
237
+ def kernel_index_of(state_id, production_id, dot)
238
+ @kernel_cores.fetch(@lalr_isocores.fetch(state_id)).index([production_id, dot])
239
+ end
240
+
241
+ # @rbs (Integer production_id) -> Integer
242
+ def lhs_for(production_id)
243
+ return @grammar.symbol(@grammar.starts.fetch(-production_id - 1)).id if production_id.negative?
244
+
245
+ @grammar.productions.fetch(production_id).lhs
246
+ end
247
+
248
+ # @rbs (Integer production_id) -> Array[Integer]
249
+ def rhs_for(production_id)
250
+ return [lhs_for(production_id)] if production_id.negative?
251
+
252
+ @grammar.productions.fetch(production_id).rhs
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+ # steep:ignore:end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "set"
5
+
6
+ module Ibex
7
+ module LALR
8
+ # Deterministically merges compatible canonical LR(1) states and splits
9
+ # partitions until their outgoing transitions are congruent.
10
+ class IELRPartition
11
+ # @rbs! type contribution_action = [:shift] | [:reduce, Integer] | [:accept]
12
+
13
+ AUGMENTED_PRODUCTION = -1 #: Integer
14
+
15
+ # @rbs @grammar: IR::Grammar
16
+ # @rbs @states: Array[item_set]
17
+ # @rbs @transitions: transitions
18
+ # @rbs @contributions: Array[Hash[Integer, Set[contribution_action]]]
19
+ # @rbs @initial_partition_count: Integer?
20
+ # @rbs @final_partition_count: Integer?
21
+ # @rbs @profile: bool
22
+
23
+ attr_reader :initial_partition_count #: Integer?
24
+ attr_reader :final_partition_count #: Integer?
25
+
26
+ # @rbs (IR::Grammar grammar, Array[item_set] states, transitions transitions, ?profile: bool) -> void
27
+ def initialize(grammar, states, transitions, profile: false)
28
+ @grammar = grammar
29
+ @states = states
30
+ @transitions = transitions
31
+ @contributions = Array.new(states.length) { |state_id| action_contributions(state_id) }
32
+ @initial_partition_count = nil
33
+ @final_partition_count = nil
34
+ @profile = profile
35
+ end
36
+
37
+ # @rbs () -> [Array[packed_items], transitions]
38
+ def build
39
+ partitions = initial_partitions
40
+ @initial_partition_count = partitions.length if @profile
41
+ partitions = refine_transitions(partitions)
42
+ @final_partition_count = partitions.length if @profile
43
+ indexes = partition_indexes(partitions)
44
+ items = partitions.map { |members| merge_items(members) }
45
+ transitions = partitions.map do |members|
46
+ @transitions.fetch(members.first).to_h do |symbol_id, target|
47
+ [symbol_id, indexes.fetch(target)]
48
+ end
49
+ end
50
+ [items, transitions]
51
+ end
52
+
53
+ private
54
+
55
+ # @rbs () -> Array[state_partition]
56
+ def initial_partitions
57
+ cores = {} #: Hash[Array[item_core], Array[Integer]]
58
+ @states.each_with_index do |items, state_id|
59
+ cores[core_key(items)] ||= []
60
+ cores.fetch(core_key(items)) << state_id
61
+ end
62
+ cores.values.flat_map { |members| compatible_partitions(members) }
63
+ end
64
+
65
+ # @rbs (Array[Integer] members) -> Array[state_partition]
66
+ def compatible_partitions(members)
67
+ partitions = [] #: Array[state_partition]
68
+ members.each do |state_id|
69
+ partition = partitions.find { |candidate| compatible?(candidate + [state_id]) }
70
+ partition ? partition << state_id : partitions << [state_id]
71
+ end
72
+ partitions
73
+ end
74
+
75
+ # A canonical member may gain an action only where it previously had no
76
+ # action. Every nonempty member cell must equal the merged cell.
77
+ # @rbs (state_partition members) -> bool
78
+ def compatible?(members)
79
+ merged = Hash.new { |hash, key| hash[key] = Set.new } #: Hash[Integer, Set[contribution_action]]
80
+ members.each do |state_id|
81
+ @contributions.fetch(state_id).each { |token_id, actions| merged[token_id].merge(actions) }
82
+ end
83
+ merged.all? do |token_id, actions|
84
+ members.all? do |state_id|
85
+ member_actions = @contributions.fetch(state_id)[token_id]
86
+ member_actions.nil? || member_actions.empty? || member_actions == actions
87
+ end
88
+ end
89
+ end
90
+
91
+ # @rbs (Array[state_partition] partitions) -> Array[state_partition]
92
+ def refine_transitions(partitions)
93
+ loop do
94
+ indexes = partition_indexes(partitions)
95
+ refined = partitions.flat_map do |members|
96
+ members.group_by { |state_id| transition_signature(state_id, indexes) }.values
97
+ end
98
+ return partitions if refined == partitions
99
+
100
+ partitions = refined
101
+ end
102
+ end
103
+
104
+ # @rbs (Integer state_id, Hash[Integer, Integer] indexes) -> Array[[Integer, Integer]]
105
+ def transition_signature(state_id, indexes)
106
+ @transitions.fetch(state_id).map do |symbol_id, target|
107
+ [symbol_id, indexes.fetch(target)] #: [Integer, Integer]
108
+ end.sort
109
+ end
110
+
111
+ # @rbs (Array[state_partition] partitions) -> Hash[Integer, Integer]
112
+ def partition_indexes(partitions)
113
+ indexes = {} #: Hash[Integer, Integer]
114
+ partitions.each_with_index do |members, partition_id|
115
+ members.each { |state_id| indexes[state_id] = partition_id }
116
+ end
117
+ indexes
118
+ end
119
+
120
+ # @rbs (state_partition members) -> packed_items
121
+ def merge_items(members)
122
+ merged = Hash.new { |hash, key| hash[key] = Set.new } #: packed_items
123
+ members.each do |state_id|
124
+ @states.fetch(state_id).each do |production_id, dot, lookahead|
125
+ merged[[production_id, dot]] << lookahead
126
+ end
127
+ end
128
+ merged
129
+ end
130
+
131
+ # @rbs (Integer state_id) -> Hash[Integer, Set[contribution_action]]
132
+ def action_contributions(state_id)
133
+ actions = Hash.new { |hash, key| hash[key] = Set.new } #: Hash[Integer, Set[contribution_action]]
134
+ @transitions.fetch(state_id).each_key do |symbol_id|
135
+ symbol = @grammar.symbol_by_id(symbol_id)
136
+ actions[symbol_id] << [:shift] if symbol&.terminal?
137
+ end
138
+ @states.fetch(state_id).each do |production_id, dot, lookahead|
139
+ next unless dot == rhs_for(production_id).length
140
+
141
+ action = production_id.negative? ? [:accept] : [:reduce, production_id] #: contribution_action
142
+ actions[lookahead] << action
143
+ end
144
+ actions
145
+ end
146
+
147
+ # @rbs (Integer production_id) -> Array[Integer]
148
+ def rhs_for(production_id)
149
+ if production_id.negative?
150
+ name = @grammar.starts.fetch(-production_id - 1)
151
+ start = @grammar.symbol(name) || raise(Ibex::Error, "missing start symbol #{name}")
152
+ return [start.id]
153
+ end
154
+
155
+ @grammar.productions.fetch(production_id).rhs
156
+ end
157
+
158
+ # @rbs (item_set items) -> Array[item_core]
159
+ def core_key(items)
160
+ items.map do |production_id, dot, _lookahead|
161
+ [production_id, dot] #: item_core
162
+ end.uniq.sort
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require "json"
7
+ require_relative "../verify/action_correspondence"
8
+
9
+ module Ibex
10
+ module LALR
11
+ # @rbs! type report_value = String | Symbol | Integer | bool | nil | IR::parser_action |
12
+ # Array[report_value] | Hash[Symbol, report_value]
13
+
14
+ # Diagnostic-only report for canonical-vs-LALR action differences. It is
15
+ # intentionally separate from normal construction because it enumerates a
16
+ # canonical LR(1) reference.
17
+ class InadequacyReport
18
+ # @rbs (IR::Automaton canonical, IR::Automaton target, ?max_pairs: Integer) -> void
19
+ def initialize(canonical, target, max_pairs: nil)
20
+ @canonical = canonical
21
+ @target = target
22
+ @max_pairs = max_pairs
23
+ end
24
+
25
+ # @rbs () -> Hash[Symbol, report_value]
26
+ def to_h
27
+ result = Verify::ActionCorrespondence.new(@canonical, @target, max_pairs: @max_pairs).verify
28
+ {
29
+ algorithm: @target.algorithm,
30
+ canonical_algorithm: @canonical.algorithm,
31
+ explored_pairs: result.explored,
32
+ truncated: result.truncated,
33
+ differences: result.differences.map do |difference|
34
+ {
35
+ kind: difference.kind, canonical_state: difference.canonical_state,
36
+ target_state: difference.target_state, symbol: difference.symbol,
37
+ canonical: difference.canonical, target: difference.target
38
+ }
39
+ end
40
+ }
41
+ end
42
+
43
+ # @rbs () -> String
44
+ def to_json(*)
45
+ "#{JSON.pretty_generate(to_h)}\n"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ # steep:ignore:end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ # steep:ignore:start
5
+
6
+ require "set"
7
+
8
+ module Ibex
9
+ module LALR
10
+ # Recomputes item lookaheads on an already-built LR(0) automaton. This is
11
+ # Phase 4 of direct IELR and is also useful as an independent cross-check
12
+ # for DirectLookaheads.
13
+ class LookaheadPropagation
14
+ EMPTY = Array.new(0).freeze #: Array[Integer]
15
+
16
+ attr_reader :propagation_edge_count #: Integer
17
+
18
+ # @rbs (IR::Grammar grammar, Analysis::Sets sets, Array[core_set] states, transitions transitions,
19
+ # seeds: Array[[Integer, item_core, Integer]]) -> Array[packed_items]
20
+ def initialize(grammar, sets, states, transitions, seeds:)
21
+ @grammar = grammar
22
+ @sets = sets
23
+ @states = states
24
+ @transitions = transitions
25
+ @seeds = seeds
26
+ @productions_by_lhs = grammar.productions.group_by(&:lhs)
27
+ end
28
+
29
+ # @rbs () -> Array[packed_items]
30
+ def build
31
+ lookaheads = @states.map { |items| items.to_h { |item| [item, Set.new] } }
32
+ edges = Hash.new { |hash, key| hash[key] = [] }
33
+ @states.each_with_index do |items, state_id|
34
+ items.each do |production_id, dot|
35
+ add_transition(edges, state_id, production_id, dot)
36
+ add_closure(edges, lookaheads, state_id, production_id, dot)
37
+ end
38
+ end
39
+ @seeds.each { |state_id, item, token| lookaheads.fetch(state_id).fetch(item) << token }
40
+ @propagation_edge_count = edges.values.sum(&:length)
41
+ propagate(lookaheads, edges)
42
+ lookaheads
43
+ end
44
+
45
+ private
46
+
47
+ # @rbs (Hash[Object, Array[Object]], Integer, Integer, Integer) -> void
48
+ def add_transition(edges, state_id, production_id, dot)
49
+ symbol_id = rhs_for(production_id)[dot]
50
+ return unless symbol_id
51
+
52
+ target = @transitions.fetch(state_id).fetch(symbol_id)
53
+ edges[[state_id, production_id, dot]] << [target, production_id, dot + 1]
54
+ end
55
+
56
+ # @rbs (Hash[Object, Array[Object]], Array[packed_items], Integer, Integer, Integer) -> void
57
+ def add_closure(edges, lookaheads, state_id, production_id, dot)
58
+ rhs = rhs_for(production_id)
59
+ symbol = @grammar.symbol_by_id(rhs[dot])
60
+ return unless symbol&.nonterminal?
61
+
62
+ suffix = rhs.drop(dot + 1)
63
+ spontaneous = terminal_ids(@sets.first_of_sequence(suffix))
64
+ @productions_by_lhs.fetch(symbol.id, []).each do |production|
65
+ item = [production.id, 0].freeze
66
+ lookaheads.fetch(state_id).fetch(item).merge(spontaneous)
67
+ edges[[state_id, production_id, dot]] << [state_id, production.id, 0] if
68
+ @sets.sequence_nullable?(suffix)
69
+ end
70
+ end
71
+
72
+ # @rbs (Array[packed_items], Hash[Object, Array[Object]]) -> void
73
+ def propagate(lookaheads, edges)
74
+ queue = @seeds.map { |state_id, (production_id, dot), _token| [state_id, production_id, dot] }
75
+ queue.concat(lookaheads.each_with_index.flat_map do |items, state_id|
76
+ items.filter_map { |(production_id, dot), values| [state_id, production_id, dot] unless values.empty? }
77
+ end)
78
+ queued = queue.to_h { |node| [node, true] }
79
+ cursor = 0
80
+ while cursor < queue.length
81
+ source = queue.fetch(cursor)
82
+ cursor += 1
83
+ queued.delete(source)
84
+ source_set = lookaheads.fetch(source[0]).fetch([source[1], source[2]])
85
+ edges.fetch(source, EMPTY).each do |target|
86
+ target_set = lookaheads.fetch(target[0]).fetch([target[1], target[2]])
87
+ previous_size = target_set.size
88
+ target_set.merge(source_set)
89
+ next if target_set.size == previous_size || queued[target]
90
+
91
+ queue << target
92
+ queued[target] = true
93
+ end
94
+ end
95
+ end
96
+
97
+ # @rbs (Integer bits) -> Array[Integer]
98
+ def terminal_ids(bits)
99
+ @grammar.terminals.filter_map { |terminal| terminal.id if bits.anybits?(1 << terminal.id) }
100
+ end
101
+
102
+ # @rbs (Integer production_id) -> Array[Integer]
103
+ def rhs_for(production_id)
104
+ return [@grammar.symbol(@grammar.starts.fetch(-production_id - 1)).id] if production_id.negative?
105
+
106
+ @grammar.productions.fetch(production_id).rhs
107
+ end
108
+ end
109
+ end
110
+ end
111
+ # steep:ignore:end