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
@@ -1,11 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../runtime/parser"
3
+ require "ibex/runtime/table_format"
4
+ require_relative "cst_metadata"
5
+ require_relative "generated_action_abi"
6
+ require_relative "ruby_actions"
7
+ require_relative "ruby_error_messages"
8
+ require_relative "ruby_table_metadata"
9
+ require_relative "ruby_value_printers"
10
+ require_relative "ruby_lexer"
11
+ require_relative "ruby_ast"
12
+ require_relative "ruby_syntax"
4
13
 
5
14
  module Ibex
6
15
  module Codegen
7
16
  # Generates a standalone Ruby parser class from Automaton IR.
17
+ # rubocop:disable Metrics/ClassLength -- generation stages are split into focused mixins.
8
18
  class Ruby
19
+ include RubyActions
20
+ include RubyErrorMessages
21
+ include RubyTableMetadata
22
+ include RubyValuePrinters
23
+ include RubyLexer
24
+ include RubyAST
25
+ include RubySyntax
26
+
9
27
  # @rbs @automaton: IR::Automaton
10
28
  # @rbs @grammar: IR::Grammar
11
29
  # @rbs @table_format: Symbol
@@ -16,14 +34,21 @@ module Ibex
16
34
  # @rbs @omit_action_call: bool
17
35
  # @rbs @superclass: String
18
36
  # @rbs @executable: String?
37
+ # @rbs @cst_trivia: Symbol
38
+ # @rbs @error_messages: Hash[Integer, String | { id: String, message: String }]
39
+ # @rbs @generated_action_abi: GeneratedActionABI::Cache
40
+ # @rbs @runtime_require: String?
19
41
 
20
42
  # @rbs (IR::Automaton automaton, ?table: Symbol | String, ?embedded: bool, ?line_convert: bool,
21
43
  # ?line_convert_all: bool, ?debug: bool, ?omit_action_call: bool?, ?superclass: String?,
22
- # ?executable: String?) -> void
44
+ # ?executable: String?, ?cst_trivia: Symbol | String, ?runtime_require: String?,
45
+ # ?error_messages: Hash[Integer, String | { id: String, message: String }]) -> void
23
46
  def initialize(automaton, table: :compact, embedded: false, line_convert: true, debug: false,
24
- line_convert_all: false, omit_action_call: nil, superclass: nil, executable: nil)
47
+ line_convert_all: false, omit_action_call: nil, superclass: nil, executable: nil,
48
+ cst_trivia: :leading, runtime_require: "ibex/runtime", error_messages: {})
25
49
  @automaton = automaton
26
50
  @grammar = automaton.grammar
51
+ reject_foreign_actions
27
52
  @table_format = table.to_sym
28
53
  @embedded = embedded
29
54
  @line_convert = line_convert
@@ -32,6 +57,15 @@ module Ibex
32
57
  @omit_action_call = omit_action_call.nil? ? @grammar.options[:omit_action_call] : omit_action_call
33
58
  @superclass = superclass || @grammar.superclass || "Ibex::Runtime::Parser"
34
59
  @executable = executable
60
+ @cst_trivia = cst_trivia.to_sym
61
+ @generated_action_abi = GeneratedActionABI::Cache.new
62
+ @runtime_require = runtime_require
63
+ @cst_trivia = :leading if @cst_trivia == :attach
64
+ unless %i[leading balanced drop].include?(@cst_trivia)
65
+ raise ArgumentError, "cst_trivia must be :leading, :balanced, or :drop"
66
+ end
67
+
68
+ @error_messages = error_messages.sort.to_h.freeze
35
69
  end
36
70
 
37
71
  # @rbs () -> String
@@ -44,7 +78,13 @@ module Ibex
44
78
  modules, class_name = class_parts
45
79
  modules.each { |name| lines << "module #{name}" }
46
80
  lines << "class #{class_name} < #{@superclass}"
81
+ append_ast(lines)
82
+ append_syntax(lines)
47
83
  append_tables(lines)
84
+ append_parameter_initializer(lines)
85
+ append_entry_methods(lines)
86
+ append_lexer(lines)
87
+ append_value_printers(lines)
48
88
  append_actions(lines)
49
89
  append_user_code(lines, "inner", indent: 2)
50
90
  lines << "end"
@@ -55,50 +95,169 @@ module Ibex
55
95
 
56
96
  private
57
97
 
98
+ # @rbs () -> void
99
+ def reject_foreign_actions
100
+ production = @grammar.productions.find do |entry|
101
+ entry.action&.code&.include?(foreign_action_sentinel)
102
+ end
103
+ return unless production
104
+
105
+ location = production.action&.location
106
+ rendered = location ? "#{location[:file]}:#{location[:line]}:#{location[:column]}" : "(codegen):1:1"
107
+ raise Ibex::Error,
108
+ "#{rendered}: cannot generate Ruby from imported C semantic actions; use analysis commands only"
109
+ end
110
+
111
+ # Kept local so the generic generator does not load the optional Bison
112
+ # importer and its IR validation graph.
113
+ # @rbs () -> String
114
+ def foreign_action_sentinel
115
+ "__ibex_foreign_action_c__"
116
+ end
117
+
58
118
  # @rbs (Array[String] lines) -> void
59
119
  def append_runtime(lines)
60
120
  if @embedded
61
- lines << embedded_source("../runtime/parser.rb")
62
- lines << embedded_source("../../ibex/tables.rb")
63
- else
64
- lines << 'require "ibex/runtime"'
65
- lines << 'require "ibex/tables"' if @table_format == :compact
121
+ require "ibex/runtime/embedded_source"
122
+ lines << Runtime::EmbeddedSource.render
123
+ elsif @runtime_require
124
+ lines << "require #{@runtime_require.inspect}"
66
125
  end
67
126
  lines << ""
68
127
  end
69
128
 
70
- # @rbs (String relative_path) -> String
71
- def embedded_source(relative_path)
72
- path = File.expand_path(relative_path, File.dirname(__FILE__))
73
- File.read(path).lines.reject { |line| line.start_with?("# frozen_string_literal:") }.join.rstrip
74
- end
75
-
76
129
  # @rbs (Array[String] lines) -> void
77
130
  def append_tables(lines)
78
131
  table_set = Tables.build(@automaton, format: @table_format)
79
132
  indent = " "
80
- lines << "#{indent}PARSER_TABLE_FORMAT_VERSION = #{Runtime::PARSER_TABLE_FORMAT_VERSION}"
133
+ append_table_metadata(lines, indent)
81
134
  lines << "#{indent}TOKEN_IDS = #{token_ids_literal}.freeze"
82
135
  lines << "#{indent}TOKEN_NAMES = #{token_names_literal}.freeze"
136
+ append_cst_metadata(lines, indent)
83
137
  lines << "#{indent}ACTIONS = #{table_literal(table_set.actions)}"
84
138
  lines << "#{indent}GOTOS = #{table_literal(table_set.gotos)}"
85
139
  lines << "#{indent}DEFAULT_ACTIONS = #{table_set.default_actions.inspect}.freeze"
140
+ eager_type = "Hash[Integer, [:reduce, Integer]]"
141
+ lines << "#{indent}eager_reductions = #{eager_reductions_literal} # @type var eager_reductions: #{eager_type}"
142
+ lines << "#{indent}EAGER_REDUCTIONS = eager_reductions.freeze #: #{eager_type}"
86
143
  lines << "#{indent}PRODUCTIONS = #{productions_literal}.freeze"
144
+ append_value_printer_table(lines, indent)
145
+ declaration = "#{indent}error_messages = #{error_messages_literal}"
146
+ type = "Hash[Integer, String | { id: String, message: String }]"
147
+ lines << "#{declaration} # @type var error_messages: #{type}"
148
+ lines << "#{indent}ERROR_MESSAGES = error_messages.freeze #: #{type}"
149
+ append_parser_tables(lines, indent, table_set)
150
+ lines << "#{indent}def self.parser_tables = PARSER_TABLES"
151
+ lines << "#{indent}DEBUG_ENABLED = #{@debug}"
152
+ lines << ""
153
+ end
154
+
155
+ # @rbs (Array[String] lines, String indent) -> void
156
+ def append_cst_metadata(lines, indent)
157
+ return unless cst?
158
+
159
+ lines << "#{indent}SYMBOL_NAMES = #{symbol_names_literal}.freeze"
160
+ lines << "#{indent}CST_METADATA = #{deep_frozen_literal(cst_metadata)}"
161
+ lines << "#{indent}CST_KIND_MODEL = Ibex::Runtime::CST::Kind.new("
162
+ lines << "#{indent} CST_METADATA.fetch(:kinds), slots: CST_METADATA.fetch(:slots)"
163
+ lines << "#{indent})"
164
+ end
165
+
166
+ # @rbs (Array[String] lines, String indent, Tables::TableSet table_set) -> void
167
+ def append_parser_tables(lines, indent, table_set)
87
168
  lines << "#{indent}PARSER_TABLES = { format_version: PARSER_TABLE_FORMAT_VERSION,"
169
+ lines << "#{indent} grammar_digest: GRAMMAR_DIGEST,"
170
+ lines << "#{indent} state_count: STATE_COUNT, production_count: PRODUCTION_COUNT,"
171
+ lines << "#{indent} uses_locations: #{uses_locations?},"
172
+ if @table_format == :compact
173
+ default_codes = table_set.default_actions.map { |action| Tables::CompactActions.pack(action) }
174
+ lines << "#{indent} compact_fast_driver: true, " \
175
+ "compact_action_encoding: :signed, compact_default_actions: #{default_codes.inspect}.freeze,"
176
+ end
177
+ lines << "#{indent} cst: CST_METADATA, cst_kinds: CST_KIND_MODEL," if cst?
178
+ lines << "#{indent} exact_expected_tokens: true," if @grammar.mode == :extended
88
179
  lines << "#{indent} tokens: TOKEN_IDS, token_names: TOKEN_NAMES, actions: ACTIONS,"
89
180
  lines << "#{indent} gotos: GOTOS, default_actions: DEFAULT_ACTIONS,"
90
- lines << "#{indent} productions: PRODUCTIONS }.freeze"
91
- lines << "#{indent}def self.parser_tables = PARSER_TABLES"
92
- lines << "#{indent}DEBUG_ENABLED = #{@debug}"
181
+ entries = entry_table_fields
182
+ recovery = recovery_table_fields
183
+ value_printers = @grammar.value_printers.empty? ? "" : " value_printers: VALUE_PRINTERS,"
184
+ lines << "#{indent} productions: PRODUCTIONS,#{entries}#{value_printers} " \
185
+ "#{recovery} eager_reductions: EAGER_REDUCTIONS, error_messages: ERROR_MESSAGES }.freeze"
186
+ return unless shareable_parser_tables?
187
+
188
+ lines << "#{indent}Ractor.make_shareable(PARSER_TABLES) " \
189
+ "if defined?(Ractor) && Ractor.respond_to?(:make_shareable)"
190
+ end
191
+
192
+ # @rbs (Array[String] lines) -> void
193
+ def append_parameter_initializer(lines)
194
+ parameters = @grammar.parser_parameters
195
+ return if parameters.empty?
196
+
197
+ keywords = parameters.map { |parameter| "#{parameter[:name]}:" }.join(", ")
198
+ lines << " IBEX_PARAMETER_INITIALIZER = Module.new do"
199
+ lines << " def initialize(#{keywords}, **_ibex_super_arguments)"
200
+ parameters.each { |parameter| lines << " @#{parameter[:name]} = #{parameter[:name]}" }
201
+ lines << " super(**_ibex_super_arguments)"
202
+ lines << " end"
203
+ lines << " end"
204
+ lines << " prepend IBEX_PARAMETER_INITIALIZER"
205
+ lines << " private_constant :IBEX_PARAMETER_INITIALIZER"
93
206
  lines << ""
94
207
  end
95
208
 
96
- # @rbs (untyped table) -> String
209
+ # Custom conversion expressions can return caller-owned mutable or
210
+ # inherently unshareable objects, so only standard token mappings are
211
+ # safe to freeze transitively.
212
+ # @rbs () -> bool
213
+ def shareable_parser_tables?
214
+ @grammar.conversions.empty?
215
+ end
216
+
217
+ # @rbs () -> CSTMetadata::metadata
218
+ def cst_metadata
219
+ @cst_metadata ||= CSTMetadata.new(@grammar, trivia_policy: @cst_trivia).build
220
+ end
221
+
222
+ # @rbs (Object? value) -> String
223
+ def deep_frozen_literal(value)
224
+ case value
225
+ when Array
226
+ "[#{value.map { |item| deep_frozen_literal(item) }.join(', ')}].freeze"
227
+ when Hash
228
+ entries = value.map do |key, item|
229
+ "#{deep_frozen_literal(key)} => #{deep_frozen_literal(item)}"
230
+ end
231
+ "{ #{entries.join(', ')} }.freeze"
232
+ when String
233
+ "#{value.inspect}.freeze"
234
+ else
235
+ value.inspect
236
+ end
237
+ end
238
+
239
+ # @rbs (Object? table) -> String
97
240
  def table_literal(table)
241
+ if table.is_a?(Tables::CompactActions)
242
+ return "Ibex::Tables::CompactActions.packed(#{packed_integers_literal(table.offsets)}, " \
243
+ "#{packed_signed_integers_literal(table.codes)}, #{packed_integers_literal(table.checks)}, " \
244
+ "row_count: #{table.row_count}, encoding: :signed, column_count: #{table.column_count})"
245
+ end
98
246
  return "#{table.inspect}.freeze" unless table.is_a?(Tables::Compact)
99
247
 
100
- "Ibex::Tables::Compact.new(offsets: #{table.offsets.inspect}, values: #{table.values.inspect}, " \
101
- "checks: #{table.checks.inspect}, row_count: #{table.row_count})"
248
+ "Ibex::Tables::Compact.packed(#{packed_integers_literal(table.offsets)}, " \
249
+ "#{packed_integers_literal(table.values)}, #{packed_integers_literal(table.checks)}, " \
250
+ "row_count: #{table.row_count}, dense_width: #{table.dense_width})"
251
+ end
252
+
253
+ # @rbs (Array[untyped] values) -> String
254
+ def packed_integers_literal(values)
255
+ Tables::PackedIntegers.encode(values).inspect
256
+ end
257
+
258
+ # @rbs (Array[untyped] values) -> String
259
+ def packed_signed_integers_literal(values)
260
+ Tables::PackedIntegers.encode_signed(values).inspect
102
261
  end
103
262
 
104
263
  # @rbs () -> String
@@ -122,77 +281,156 @@ module Ibex
122
281
 
123
282
  # @rbs () -> String
124
283
  def token_names_literal
125
- entries = @grammar.terminals.map { |terminal| "#{terminal.id} => #{terminal.name.inspect}" }
284
+ entries = @grammar.terminals.map do |terminal|
285
+ "#{terminal.id} => #{(terminal.display_name || terminal.name).inspect}"
286
+ end
287
+ "{ #{entries.join(', ')} }"
288
+ end
289
+
290
+ # @rbs () -> String
291
+ def symbol_names_literal
292
+ entries = @grammar.symbols.map { |symbol| "#{symbol.id} => #{symbol.name.inspect}" }
126
293
  "{ #{entries.join(', ')} }"
127
294
  end
128
295
 
129
296
  # @rbs () -> String
130
297
  def productions_literal
298
+ return compact_productions_literal if @table_format == :compact
299
+
300
+ plain_productions_literal
301
+ end
302
+
303
+ # @rbs () -> String
304
+ def plain_productions_literal
131
305
  entries = @grammar.productions.map do |production|
132
- action = action_method?(production) ? ":_ibex_action_#{production.id}" : "nil"
133
- "{ lhs: #{production.lhs}, length: #{production.rhs.length}, action: #{action} }"
306
+ generated_action = action_method?(production)
307
+ action = generated_action ? ":_ibex_action_#{production.id}" : "nil"
308
+ action_abi = production_action_abi_literal(production, generated_action)
309
+ composition_action = composed_action?(production) ? ", composition_action: true" : ""
310
+ cst_rhs = cst? ? ", rhs: #{production.rhs.inspect}.freeze" : ""
311
+ location_context, named_locations = production_location_metadata(production.action)
312
+ "{ lhs: #{production.lhs}, length: #{production.rhs.length}, action: #{action}" \
313
+ "#{action_abi}#{composition_action}#{cst_rhs}#{location_context}#{named_locations} }"
134
314
  end
135
315
  "[#{entries.join(', ')}]"
136
316
  end
137
317
 
138
- # @rbs (Array[String] lines) -> void
139
- def append_actions(lines)
140
- @grammar.productions.each do |production|
141
- next unless action_method?(production)
318
+ # @rbs (IR::Production production, bool generated_action) -> String
319
+ def production_action_abi_literal(production, generated_action)
320
+ return "" unless generated_action
321
+ return ", location_action: true" unless @generated_action_abi.values_only?(production)
322
+ return ", positional_action: true" if @generated_action_abi.positional_values?(production)
323
+
324
+ borrowed = if @generated_action_abi.borrowed_values?(production)
325
+ ", borrowed_values_action: true"
326
+ else
327
+ ""
328
+ end
329
+ ", values_action: true#{borrowed}"
330
+ end
331
+
332
+ # @rbs () -> String
333
+ def compact_productions_literal
334
+ lhs_ids = @grammar.productions.map(&:lhs)
335
+ lengths = @grammar.productions.map { |production| production.rhs.length }
336
+ flags = @grammar.productions.map { |production| compact_production_flags(production) }
337
+ metadata = compact_production_metadata_literal
338
+ "Ibex::Tables::CompactProductions.packed(#{packed_integers_literal(lhs_ids)}, " \
339
+ "#{packed_integers_literal(lengths)}, #{packed_integers_literal(flags)}, metadata: #{metadata})"
340
+ end
341
+
342
+ # @rbs (IR::Production production) -> Integer
343
+ def compact_production_flags(production)
344
+ return 0 unless action_method?(production)
142
345
 
143
- append_action_constant(lines, production)
144
- append_action_method(lines, production)
346
+ value = 0
347
+ if @generated_action_abi.positional_values?(production)
348
+ value |= Tables::CompactProductions::POSITIONAL_ACTION
349
+ elsif @generated_action_abi.values_only?(production)
350
+ value |= Tables::CompactProductions::VALUES_ACTION
351
+ value |= Tables::CompactProductions::BORROWED_VALUES_ACTION if
352
+ @generated_action_abi.borrowed_values?(production)
353
+ else
354
+ value |= Tables::CompactProductions::LOCATION_ACTION
145
355
  end
356
+ value |= Tables::CompactProductions::COMPOSITION_ACTION if composed_action?(production)
357
+ value
146
358
  end
147
359
 
148
- # @rbs (Array[String] lines, IR::Production production) -> void
149
- def append_action_constant(lines, production)
150
- return unless production.action && @line_convert
360
+ # @rbs () -> String
361
+ def compact_production_metadata_literal
362
+ entries = @grammar.productions.filter_map do |production|
363
+ fields = [] #: Array[String]
364
+ fields << "rhs: #{production.rhs.inspect}.freeze" if cst?
365
+ action = production.action
366
+ if action
367
+ fields << "location_context_length: #{action.context_length}" if action.context_length.positive?
368
+ names = action.named_refs.to_h { |reference| [reference[:name].to_sym, reference[:index]] }
369
+ fields << "location_names: #{names.inspect}.freeze" unless names.empty?
370
+ end
371
+ next if fields.empty?
151
372
 
152
- lines << " ACTION_CODE_#{production.id} = #{production.action.code.inspect}.freeze"
373
+ "#{production.id} => { #{fields.join(', ')} }.freeze"
374
+ end
375
+ entries.empty? ? "Hash.new.freeze" : "{ #{entries.join(', ')} }.freeze"
153
376
  end
154
377
 
155
- # @rbs (Array[String] lines, IR::Production production) -> void
156
- def append_action_method(lines, production)
157
- action = production.action
158
- lines << " private def _ibex_action_#{production.id}(val, _values)"
159
- lines << " val = _values.last(#{action.context_length})" if action&.context_length&.positive?
160
- append_named_bindings(lines, action)
161
- if action
162
- append_semantic_code(lines, production)
163
- else
164
- lines << " val[0]"
378
+ # Reductions that are the sole non-error behavior of a state may run
379
+ # before requesting another lexer token. This enables parser actions to
380
+ # select lexer_state without speculative lookahead.
381
+ # @rbs () -> String
382
+ def eager_reductions_literal
383
+ return "{}" unless @grammar.lexer
384
+
385
+ entries = @automaton.states.filter_map do |state|
386
+ action = eager_lexer_feedback_reduction(state)
387
+ next unless action
388
+
389
+ "#{state.id} => [:reduce, #{action.fetch(:production)}].freeze"
165
390
  end
166
- lines << " end"
167
- lines << ""
391
+ "{ #{entries.join(', ')} }"
168
392
  end
169
393
 
170
- # @rbs (Array[String] lines, IR::Action? action) -> void
171
- def append_named_bindings(lines, action)
172
- return unless action&.named_refs&.any?
394
+ # @rbs (IR::AutomatonState state) -> IR::reduce_action?
395
+ def eager_lexer_feedback_reduction(state)
396
+ candidates = state.actions.values
397
+ candidates += [state.default_action] if state.default_action
398
+ actions = candidates.reject { |action| action[:type] == :error }.uniq
399
+ return unless actions.one?
400
+ return unless actions.first[:type] == :reduce
173
401
 
174
- action.named_refs.each { |reference| lines << " #{reference[:name]} = val[#{reference[:index]}]" }
175
- names = action.named_refs.map { |reference| reference[:name] }
176
- lines << " _ibex_named_values = [#{names.join(', ')}]"
402
+ reduction = actions.first #: IR::reduce_action
403
+ production = @grammar.productions.fetch(reduction.fetch(:production))
404
+ reduction if production.action&.code&.match?(/\blexer_state\s*=/)
177
405
  end
178
406
 
179
- # @rbs (Array[String] lines, IR::Production production) -> void
180
- def append_semantic_code(lines, production)
181
- action = production.action || raise(Ibex::Error, "missing semantic action")
182
- lines << " result = val[0]" if @grammar.options[:result_var]
183
- if @line_convert
184
- evaluation = "eval(ACTION_CODE_#{production.id}, binding, #{action.location[:file].inspect}, " \
185
- "#{action.location[:line]})"
186
- lines << " #{@grammar.options[:result_var] ? evaluation : "return #{evaluation}"}"
187
- else
188
- action.code.lines.each { |line| lines << " #{line.rstrip}" }
407
+ # @rbs (IR::Action? action) -> [String, String]
408
+ def production_location_metadata(action)
409
+ return ["", ""] unless action
410
+
411
+ context = action.context_length.positive? ? ", location_context_length: #{action.context_length}" : ""
412
+ names = action.named_refs.to_h { |reference| [reference[:name].to_sym, reference[:index]] }
413
+ named = names.empty? ? "" : ", location_names: #{names.inspect}.freeze"
414
+ [context, named]
415
+ end
416
+
417
+ # @rbs () -> bool
418
+ def uses_locations?
419
+ cst? || @grammar.productions.any? do |production|
420
+ action = production.action
421
+ action && (!action.composition.nil? || action_references_locations?(production, action))
189
422
  end
190
- lines << " result" if @grammar.options[:result_var]
191
423
  end
192
424
 
193
- # @rbs (IR::Production production) -> bool
194
- def action_method?(production)
195
- !!(production.action || !@omit_action_call)
425
+ # @rbs (IR::Production production, IR::Action action) -> bool
426
+ def action_references_locations?(production, action)
427
+ maximum = action.context_length.positive? ? action.context_length : production.rhs.length
428
+ ActionLocations.new(action.code, maximum: maximum, location: action.location).references?
429
+ end
430
+
431
+ # @rbs () -> bool
432
+ def cst?
433
+ @grammar.options[:cst] == true
196
434
  end
197
435
 
198
436
  # @rbs (Array[String] lines, String name, ?indent: Integer) -> void
@@ -231,5 +469,6 @@ module Ibex
231
469
  @automaton.grammar_digest.delete_prefix("sha256:").chars.first(12).join
232
470
  end
233
471
  end
472
+ # rubocop:enable Metrics/ClassLength
234
473
  end
235
474
  end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "action_method_source"
5
+ require_relative "ruby_ast"
6
+
7
+ module Ibex
8
+ module Codegen
9
+ # Semantic-action method generation shared by direct and source-mapped
10
+ # Ruby output.
11
+ module RubyActions
12
+ include RubyAST
13
+
14
+ # @rbs @grammar: IR::Grammar
15
+ # @rbs @line_convert: bool
16
+ # @rbs @omit_action_call: bool
17
+ # @rbs @action_method_source: ActionMethodSource?
18
+
19
+ private
20
+
21
+ # @rbs (Array[String] lines) -> void
22
+ def append_actions(lines)
23
+ @grammar.productions.each do |production|
24
+ next unless action_method?(production)
25
+
26
+ if production.node
27
+ source = ast_node_action_source(production)
28
+ source.lines.each { |line| lines << " #{line.rstrip}" }
29
+ lines << ""
30
+ elsif composed_action?(production)
31
+ append_composed_action_method(lines, production)
32
+ elsif production.action && @line_convert
33
+ append_compiled_action_method(lines, production)
34
+ else
35
+ append_action_method(lines, production)
36
+ end
37
+ end
38
+ end
39
+
40
+ # @rbs (Array[String] lines, IR::Production production) -> void
41
+ def append_composed_action_method(lines, production)
42
+ action = production.action || raise(Ibex::Error, "missing composed semantic action")
43
+ plan = action.composition&.dig(:plan) || raise(Ibex::Error, "missing action composition plan")
44
+ steps = plan.fetch(:steps)
45
+ steps.each_with_index do |step, index|
46
+ append_composed_fragment_method(lines, production, step, index) if step[:code]
47
+ end
48
+ append_composed_orchestrator(lines, production, plan)
49
+ end
50
+
51
+ # @rbs (Array[String] lines, IR::Production production, IR::action_composition_step step, Integer index) -> void
52
+ def append_composed_fragment_method(lines, production, step, index)
53
+ source = action_method_source.composed_fragment_method_source(production, step, index)
54
+ if @line_convert
55
+ location = step.fetch(:loc)
56
+ lines << " class_eval(#{source.dump}, #{location[:file].inspect}, #{location[:line]})"
57
+ else
58
+ code = step.fetch(:code) #: String
59
+ if action_method_source.column_sensitive?(code)
60
+ lines << source
61
+ else
62
+ source.lines.each { |line| lines << " #{line.rstrip}" }
63
+ end
64
+ end
65
+ lines << ""
66
+ end
67
+
68
+ # @rbs (IR::Production production, Integer index) -> String
69
+ def composed_fragment_name(production, index)
70
+ action_method_source.composed_fragment_name(production, index)
71
+ end
72
+
73
+ # @rbs (Array[String] lines, IR::Production production, IR::action_composition_plan plan) -> void
74
+ def append_composed_orchestrator(lines, production, plan)
75
+ lines << " private def _ibex_action_#{production.id}" \
76
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location, " \
77
+ "_ibex_lookahead_location)"
78
+ lines << " _ibex_composed_values = val.dup"
79
+ lines << " _ibex_composed_locations = _ibex_locations.dup"
80
+ plan.fetch(:steps).each_with_index do |step, index|
81
+ append_composed_step(lines, production, step, index)
82
+ end
83
+ lines.push(" _ibex_composed_values.last", " end", "")
84
+ end
85
+
86
+ # @rbs (Array[String] lines, IR::Production production, IR::action_composition_step step, Integer index) -> void
87
+ def append_composed_step(lines, production, step, index)
88
+ inputs = step.fetch(:inputs)
89
+ lines << " _ibex_step_values = _ibex_composed_values.values_at(#{inputs.join(', ')})"
90
+ lines << " _ibex_step_locations = _ibex_composed_locations.values_at(#{inputs.join(', ')})"
91
+ lookahead = step[:lookahead]
92
+ boundary = lookahead ? "_ibex_locations[#{lookahead}]" : "_ibex_lookahead_location"
93
+ lines << " _ibex_step_location = Ibex::Runtime::LocationSpan.for_reduction(" \
94
+ "_ibex_step_locations, lookahead: #{boundary})"
95
+ result = if step[:code]
96
+ stack_inputs = step.fetch(:stack_inputs)
97
+ "#{composed_fragment_name(production, index)}(" \
98
+ "_ibex_step_values, _values + _ibex_composed_values.values_at(#{stack_inputs.join(', ')}), " \
99
+ "_ibex_step_locations, _ibex_location_stack + " \
100
+ "_ibex_composed_locations.values_at(#{stack_inputs.join(', ')}), _ibex_step_location)"
101
+ else
102
+ "_ibex_step_values[0]"
103
+ end
104
+ lines << " _ibex_composed_values << #{result}"
105
+ lines << " _ibex_composed_locations << _ibex_step_location"
106
+ lines << " return _ibex_composed_values.last if @accept_requested || @semantic_error"
107
+ end
108
+
109
+ # @rbs (Array[String] lines, IR::Production production) -> void
110
+ def append_compiled_action_method(lines, production)
111
+ action = production.action || raise(Ibex::Error, "missing semantic action")
112
+ source = action_method_source.compiled_action_method_source(production)
113
+ lines << " class_eval(#{source.dump}, #{action.location[:file].inspect}, #{action.location[:line]})"
114
+ lines << ""
115
+ end
116
+
117
+ # @rbs (Array[String] lines, IR::Production production) -> void
118
+ def append_action_method(lines, production)
119
+ source = action_method_source.direct_action_method_source(production)
120
+ if production.action && action_method_source.column_sensitive?(production.action.code)
121
+ lines << source
122
+ else
123
+ source.lines.each { |line| lines << " #{line.rstrip}" }
124
+ end
125
+ lines << ""
126
+ end
127
+
128
+ # @rbs (IR::Production production) -> bool
129
+ def action_method?(production)
130
+ !!(production.node || production.action || !@omit_action_call)
131
+ end
132
+
133
+ # @rbs (IR::Production production) -> bool
134
+ def composed_action?(production)
135
+ production.action&.composition&.dig(:plan, :version) == 1
136
+ end
137
+
138
+ # @rbs () -> ActionMethodSource
139
+ def action_method_source
140
+ @action_method_source ||= ActionMethodSource.new(
141
+ @grammar, generated_action_abi: @generated_action_abi
142
+ )
143
+ end
144
+ end
145
+ end
146
+ end