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,103 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Rewrites semantic-location expressions without touching Ruby literals,
7
+ # comments, heredoc bodies, or ordinary instance/class variables.
8
+ class ActionLocations
9
+ SEMANTIC_HELPERS = %w[loc result_loc].freeze #: Array[String]
10
+ private_constant :SEMANTIC_HELPERS
11
+
12
+ # @rbs @source: String
13
+ # @rbs @maximum: Integer
14
+ # @rbs @location: IR::location
15
+
16
+ # @rbs (String source, maximum: Integer, location: IR::location) -> void
17
+ def initialize(source, maximum:, location:)
18
+ @source = source
19
+ @maximum = maximum
20
+ @location = location
21
+ end
22
+
23
+ # @rbs () -> String
24
+ def rewrite
25
+ rewritten = mutable_binary_source_copy
26
+ return rewritten.force_encoding(@source.encoding) unless @source.match?(/@(?:\$|\d+)/)
27
+
28
+ replacements = semantic_references.map do |offset, spelling|
29
+ [offset, spelling.bytesize, replacement_for(spelling)]
30
+ end #: Array[[Integer, Integer, String]]
31
+ replacements.reverse_each { |offset, length, replacement| rewritten[offset, length] = replacement }
32
+ rewritten.force_encoding(@source.encoding)
33
+ end
34
+
35
+ # @rbs () -> bool
36
+ def references?
37
+ return true if @source.match?(/@(?:\$|\d+)/) && !semantic_references.empty?
38
+ return false unless @source.match?(/\b(?:loc|result_loc)\b/)
39
+
40
+ require "ripper"
41
+ tokens = Object.const_get(:Ripper).__send__(:lex, lexable_source)
42
+ tokens.any? do |_position, type, token, _state|
43
+ type == :on_ident && SEMANTIC_HELPERS.include?(token)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # @rbs () -> String
50
+ def mutable_binary_source_copy
51
+ String.new(encoding: Encoding::BINARY).replace(@source.b)
52
+ end
53
+
54
+ # @rbs () -> Array[[Integer, String]]
55
+ def semantic_references
56
+ require "ripper"
57
+
58
+ offsets = line_offsets
59
+ tokens = Object.const_get(:Ripper).__send__(:lex, lexable_source)
60
+ # @type var tokens: Array[[[Integer, Integer], Symbol, String, Object?]]
61
+ tokens.filter_map do |position, type, _token, _state|
62
+ next unless type == :on_ident
63
+
64
+ line, column = position
65
+ offset = offsets.fetch(line - 1) + column
66
+ spelling = @source.b.byteslice(offset..)&.match(/\A@(?:\$|\d+)/)&.[](0)
67
+ [offset, spelling] if spelling
68
+ end
69
+ end
70
+
71
+ # Give every Ripper implementation syntactically valid input while
72
+ # preserving byte offsets and lexical string/comment boundaries.
73
+ # @rbs () -> String
74
+ def lexable_source
75
+ @source.gsub(/@(?:\$|\d+)/) { |spelling| "_" * spelling.bytesize }
76
+ end
77
+
78
+ # @rbs () -> Array[Integer]
79
+ def line_offsets
80
+ offset = 0
81
+ @source.lines.map do |line|
82
+ current = offset
83
+ offset += line.bytesize
84
+ current
85
+ end
86
+ end
87
+
88
+ # @rbs (String spelling) -> String
89
+ def replacement_for(spelling)
90
+ return "_ibex_location" if spelling == "@$"
91
+
92
+ index = spelling.delete_prefix("@").to_i
93
+ if index.zero? || index > @maximum
94
+ raise Ibex::Error,
95
+ "#{@location[:file]}:#{@location[:line]}:#{@location[:column]}: " \
96
+ "semantic location #{spelling} is outside 1..#{@maximum}"
97
+ end
98
+
99
+ "_ibex_locations[#{index - 1}]"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "action_locations"
5
+ require_relative "generated_action_abi"
6
+
7
+ module Ibex
8
+ module Codegen
9
+ # Builds semantic method source shared by runtime and static shadow output.
10
+ class ActionMethodSource
11
+ # @rbs @grammar: IR::Grammar
12
+ # @rbs @generated_action_abi: GeneratedActionABI::Cache
13
+
14
+ # @rbs (IR::Grammar grammar, ?generated_action_abi: GeneratedActionABI::Cache?) -> void
15
+ def initialize(grammar, generated_action_abi: nil)
16
+ @grammar = grammar
17
+ @generated_action_abi = generated_action_abi || GeneratedActionABI::Cache.new
18
+ end
19
+
20
+ # @rbs (IR::Production production, IR::action_composition_step step, Integer index) -> String
21
+ def composed_fragment_method_source(production, step, index)
22
+ source = "private def #{composed_fragment_name(production, index)}" \
23
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location); "
24
+ append_parameter_values(source)
25
+ context_length = step.fetch(:context_length)
26
+ if context_length.positive?
27
+ source << "val = _values.last(#{context_length}); "
28
+ source << "_ibex_locations = _ibex_location_stack.last(#{context_length}); "
29
+ end
30
+ named_refs = step.fetch(:named_refs)
31
+ named_refs.each { |reference| source << "#{reference[:name]} = val[#{reference[:index]}]; " }
32
+ append_named_values(source, named_refs)
33
+ source << "result = val[0]; " if step.fetch(:result_var)
34
+ source << composed_semantic_code(step)
35
+ source << "\nresult" if step.fetch(:result_var)
36
+ source << "\nend"
37
+ end
38
+
39
+ # @rbs (IR::Production production, Integer index) -> String
40
+ def composed_fragment_name(production, index)
41
+ "_ibex_inline_fragment_#{production.id}_#{index}"
42
+ end
43
+
44
+ # @rbs (IR::Production production) -> String
45
+ def compiled_action_method_source(production)
46
+ action = production.action
47
+ source = "private def _ibex_action_#{production.id}#{action_parameters(production)}; "
48
+ append_parameter_values(source, production: production)
49
+ return "#{source}#{default_value_expression(production)}\nend" unless action
50
+
51
+ if action.context_length.positive?
52
+ source << "val = _values.last(#{action.context_length}); "
53
+ source << "_ibex_locations = _ibex_location_stack.last(#{action.context_length}); "
54
+ end
55
+ action.named_refs.each do |reference|
56
+ source << "#{reference[:name]} = #{value_expression(production, reference[:index])}; "
57
+ end
58
+ append_named_values(source, action.named_refs)
59
+ append_action_body(source, production, action)
60
+ source << "\nend"
61
+ end
62
+
63
+ # @rbs (IR::Production production) -> String
64
+ def direct_action_method_source(production)
65
+ action = production.action
66
+ lines = [
67
+ "private def _ibex_action_#{production.id}#{action_parameters(production)}"
68
+ ]
69
+ append_direct_parameter_values(lines, production: production)
70
+ if action&.context_length&.positive?
71
+ lines << " val = _values.last(#{action.context_length})"
72
+ lines << " _ibex_locations = _ibex_location_stack.last(#{action.context_length})"
73
+ end
74
+ if action&.named_refs&.any?
75
+ action.named_refs.each do |reference|
76
+ lines << " #{reference[:name]} = #{value_expression(production, reference[:index])}"
77
+ end
78
+ names = action.named_refs.map { |reference| reference[:name] }
79
+ lines << " _ibex_named_values = [#{names.join(', ')}]"
80
+ end
81
+ append_direct_action_body(lines, production, action)
82
+ lines << "end"
83
+ lines.join("\n")
84
+ end
85
+
86
+ # @rbs (Integer symbol_id, IR::value_printer printer) -> String
87
+ def value_printer_method_source(symbol_id, printer)
88
+ source = "private def _ibex_value_printer_#{symbol_id}(value); "
89
+ append_parameter_values(source)
90
+ source << printer[:code]
91
+ source << "\nend"
92
+ end
93
+
94
+ # @rbs (String source) -> bool
95
+ def column_sensitive?(source)
96
+ return false unless source.include?("<<")
97
+
98
+ require "ripper"
99
+ tokens = Object.const_get(:Ripper).__send__(:lex, source)
100
+ # @type var tokens: Array[GeneratedActionABI::ripper_token]
101
+ tokens.any? { |_position, event, _token, _state| event == :on_heredoc_beg }
102
+ end
103
+
104
+ private
105
+
106
+ # @rbs (IR::Production production) -> String
107
+ def action_parameters(production)
108
+ if @generated_action_abi.positional_values?(production)
109
+ parameters = Array.new(production.rhs.length) { |index| "v#{index}" }
110
+ return "(#{parameters.join(', ')})"
111
+ end
112
+ return "(val)" if @generated_action_abi.values_only?(production)
113
+
114
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location)"
115
+ end
116
+
117
+ # @rbs (IR::Production production, Integer index) -> String
118
+ def value_expression(production, index)
119
+ return "v#{index}" if @generated_action_abi.positional_values?(production)
120
+
121
+ "val[#{index}]"
122
+ end
123
+
124
+ # @rbs (String source, ?production: IR::Production?) -> void
125
+ def append_parameter_values(source, production: nil)
126
+ excluded = if production && @generated_action_abi.positional_values?(production)
127
+ Array.new(production.rhs.length) { |index| "v#{index}" }
128
+ else
129
+ [] #: Array[String]
130
+ end
131
+ @grammar.parser_parameters.each do |parameter|
132
+ next if excluded.include?(parameter[:name])
133
+
134
+ source << "#{parameter[:name]} = @#{parameter[:name]}; "
135
+ end
136
+ end
137
+
138
+ # @rbs (Array[String] lines, production: IR::Production) -> void
139
+ def append_direct_parameter_values(lines, production:)
140
+ excluded = if @generated_action_abi.positional_values?(production)
141
+ Array.new(production.rhs.length) { |index| "v#{index}" }
142
+ else
143
+ [] #: Array[String]
144
+ end
145
+ @grammar.parser_parameters.each do |parameter|
146
+ next if excluded.include?(parameter[:name])
147
+
148
+ lines << " #{parameter[:name]} = @#{parameter[:name]}"
149
+ end
150
+ end
151
+
152
+ # @rbs (IR::action_composition_step step) -> String
153
+ def composed_semantic_code(step)
154
+ maximum = [step.fetch(:inputs).length, step.fetch(:context_length)].max
155
+ code = step.fetch(:code) #: String
156
+ ActionLocations.new(code, maximum: maximum, location: step.fetch(:loc)).rewrite
157
+ end
158
+
159
+ # @rbs (String source, Array[IR::named_ref] named_refs) -> void
160
+ def append_named_values(source, named_refs)
161
+ return if named_refs.empty?
162
+
163
+ names = named_refs.map { |reference| reference[:name] }
164
+ source << "_ibex_named_values = [#{names.join(', ')}]; "
165
+ end
166
+
167
+ # @rbs (String source, IR::Production production, IR::Action action) -> void
168
+ def append_action_body(source, production, action)
169
+ source << "result = #{default_value_expression(production)}; " if @grammar.options[:result_var]
170
+ source << semantic_action_code(production, action)
171
+ source << "\nresult" if @grammar.options[:result_var]
172
+ end
173
+
174
+ # @rbs (Array[String] lines, IR::Production production, IR::Action? action) -> void
175
+ def append_direct_action_body(lines, production, action)
176
+ unless action
177
+ lines << " #{default_value_expression(production)}"
178
+ return
179
+ end
180
+
181
+ lines << " result = #{default_value_expression(production)}" if @grammar.options[:result_var]
182
+ semantic_code = semantic_action_code(production, action)
183
+ if column_sensitive?(semantic_code)
184
+ lines << semantic_code
185
+ else
186
+ semantic_code.lines.each { |line| lines << " #{line.rstrip}" }
187
+ end
188
+ lines << " result" if @grammar.options[:result_var]
189
+ end
190
+
191
+ # @rbs (IR::Production production, IR::Action action) -> String
192
+ def semantic_action_code(production, action)
193
+ positional = @generated_action_abi.positional_action_source(production)
194
+ return positional unless positional.nil?
195
+
196
+ maximum = action.context_length.positive? ? action.context_length : production.rhs.length
197
+ ActionLocations.new(action.code, maximum: maximum, location: action.location).rewrite
198
+ end
199
+
200
+ # @rbs (IR::Production production) -> String
201
+ def default_value_expression(production)
202
+ return "nil" if production.rhs.empty?
203
+ return "v0" if @generated_action_abi.positional_values?(production)
204
+
205
+ "val[0]"
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,119 @@
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
+ # Generates static-check-only Ruby containing semantic action methods.
10
+ class ActionSource
11
+ include RubyAST
12
+
13
+ # @rbs @automaton: IR::Automaton
14
+ # @rbs @grammar: IR::Grammar
15
+ # @rbs @omit_action_call: bool
16
+ # @rbs @method_source: ActionMethodSource
17
+
18
+ # @rbs (IR::Automaton automaton, ?omit_action_call: bool?) -> void
19
+ def initialize(automaton, omit_action_call: nil)
20
+ @automaton = automaton
21
+ @grammar = automaton.grammar
22
+ @omit_action_call = omit_action_call.nil? ? @grammar.options[:omit_action_call] : omit_action_call
23
+ @method_source = ActionMethodSource.new(@grammar)
24
+ end
25
+
26
+ # @rbs () -> String
27
+ def generate
28
+ lines = [
29
+ "# frozen_string_literal: true",
30
+ "# Generated by Ibex #{grammar_digest_comment}.",
31
+ "# Static-check-only semantic action shadow source.",
32
+ "# DO NOT LOAD OR EXECUTE: runtime wiring and user code are intentionally absent.",
33
+ ""
34
+ ]
35
+ modules, class_name = class_parts
36
+ modules.each { |name| lines << "module #{name}" }
37
+ lines << "class #{class_name}"
38
+ append_ast(lines)
39
+ append_value_printers(lines)
40
+ append_actions(lines)
41
+ lines << "end"
42
+ modules.reverse_each { lines << "end" }
43
+ "#{lines.join("\n")}\n"
44
+ end
45
+
46
+ private
47
+
48
+ # @rbs (Array[String] lines) -> void
49
+ def append_value_printers(lines)
50
+ @grammar.value_printers.each do |printer|
51
+ symbol = @grammar.symbol(printer[:symbol]) || raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
52
+ location = printer.fetch(:loc) #: IR::location
53
+ append_method(lines, location, @method_source.value_printer_method_source(symbol.id, printer))
54
+ end
55
+ end
56
+
57
+ # @rbs (Array[String] lines) -> void
58
+ def append_actions(lines)
59
+ @grammar.productions.each do |production|
60
+ if production.node
61
+ append_method(lines, production.node.fetch(:loc), ast_node_action_source(production))
62
+ elsif composed_action?(production)
63
+ append_composed_actions(lines, production)
64
+ elsif production.action || !@omit_action_call
65
+ append_action(lines, production)
66
+ end
67
+ end
68
+ end
69
+
70
+ # @rbs (Array[String] lines, IR::Production production) -> void
71
+ def append_composed_actions(lines, production)
72
+ plan = production.action&.composition&.dig(:plan)
73
+ raise Ibex::Error, "missing action composition plan" unless plan
74
+
75
+ plan.fetch(:steps).each_with_index do |step, index|
76
+ next unless step[:code]
77
+
78
+ append_method(
79
+ lines, step.fetch(:loc),
80
+ @method_source.composed_fragment_method_source(production, step, index)
81
+ )
82
+ end
83
+ end
84
+
85
+ # @rbs (Array[String] lines, IR::Production production) -> void
86
+ def append_action(lines, production)
87
+ location = production.action&.location || production.origin.fetch(:loc) #: IR::location
88
+ append_method(lines, location, @method_source.compiled_action_method_source(production))
89
+ end
90
+
91
+ # @rbs (Array[String] lines, IR::location location, String source) -> void
92
+ def append_method(lines, location, source)
93
+ lines << ""
94
+ lines << " # Grammar action: #{location.fetch(:file).inspect}:" \
95
+ "#{location.fetch(:line)}:#{location.fetch(:column)}"
96
+ # Keep action bytes at column zero. Ruby lexical nesting does not require
97
+ # indentation, while changing it can invalidate <<HEREDOC terminators or
98
+ # alter <<~HEREDOC dedentation.
99
+ lines << source
100
+ end
101
+
102
+ # @rbs (IR::Production production) -> bool
103
+ def composed_action?(production)
104
+ production.action&.composition&.dig(:plan, :version) == 1
105
+ end
106
+
107
+ # @rbs () -> [Array[String], String]
108
+ def class_parts
109
+ parts = @grammar.class_name.split("::")
110
+ [parts.take(parts.length - 1), parts.fetch(-1)]
111
+ end
112
+
113
+ # @rbs () -> String
114
+ def grammar_digest_comment
115
+ @automaton.grammar_digest.delete_prefix("sha256:").chars.first(12).join
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "../lalr"
5
+
6
+ module Ibex
7
+ module Codegen
8
+ # @rbs!
9
+ # type ambiguity_search = {
10
+ # max_tokens: Integer,
11
+ # max_configurations: Integer
12
+ # }
13
+ # type ambiguity_summary = {
14
+ # conflicts: Integer,
15
+ # ambiguous: Integer,
16
+ # not_found: Integer,
17
+ # configuration_budget_exhausted: Integer
18
+ # }
19
+ # type ambiguity_check = {
20
+ # state: Integer,
21
+ # type: String,
22
+ # token: String,
23
+ # result: String,
24
+ # sentence: Array[String],
25
+ # lookahead_index: Integer?,
26
+ # interpretations: Array[IR::interpretation],
27
+ # explored_configurations: Integer,
28
+ # configuration_budget_exhausted: bool
29
+ # }
30
+ # type ambiguity_document = {
31
+ # ibex_check: String,
32
+ # schema_version: Integer,
33
+ # algorithm: String,
34
+ # search: ambiguity_search,
35
+ # status: String,
36
+ # summary: ambiguity_summary,
37
+ # conflicts: Array[ambiguity_check]
38
+ # }
39
+
40
+ # Renders a bounded ambiguity search over every parser conflict.
41
+ class Ambiguity
42
+ SCHEMA_VERSION = 1 #: Integer
43
+
44
+ # @rbs @automaton: IR::Automaton
45
+ # @rbs @grammar: IR::Grammar
46
+ # @rbs @max_tokens: Integer
47
+ # @rbs @max_configurations: Integer
48
+ # @rbs @checks: Array[ambiguity_check]
49
+
50
+ # @rbs (IR::Automaton automaton, ?max_tokens: Integer, ?max_configurations: Integer) -> void
51
+ def initialize(
52
+ automaton,
53
+ max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS,
54
+ max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS
55
+ )
56
+ LALR::ConflictSearchLimits.validate!(
57
+ max_tokens: max_tokens, max_configurations: max_configurations
58
+ )
59
+ @automaton = automaton
60
+ @grammar = automaton.grammar
61
+ @max_tokens = max_tokens
62
+ @max_configurations = max_configurations
63
+ @checks = check_conflicts
64
+ end
65
+
66
+ # @rbs () -> Integer
67
+ def exit_status
68
+ return 1 if status == "ambiguous"
69
+ return 2 if status == "inconclusive"
70
+
71
+ 0
72
+ end
73
+
74
+ # @rbs () -> ambiguity_document
75
+ def to_h
76
+ {
77
+ ibex_check: "ambiguity",
78
+ schema_version: SCHEMA_VERSION,
79
+ algorithm: @automaton.algorithm,
80
+ search: { max_tokens: @max_tokens, max_configurations: @max_configurations },
81
+ status: status,
82
+ summary: summary,
83
+ conflicts: @checks
84
+ }
85
+ end
86
+
87
+ # @rbs () -> String
88
+ def render_text
89
+ counts = summary
90
+ lines = [
91
+ "Ibex ambiguity check v#{SCHEMA_VERSION}",
92
+ "Algorithm: #{@automaton.algorithm}",
93
+ "Search budget: #{@max_tokens} tokens, #{@max_configurations} configurations per conflict",
94
+ "Result: #{status}",
95
+ "Conflicts: #{counts.fetch(:conflicts)}, ambiguous: #{counts.fetch(:ambiguous)}, " \
96
+ "exhausted: #{counts.fetch(:configuration_budget_exhausted)}"
97
+ ]
98
+ @checks.each_with_index { |check, index| append_check(lines, check, index + 1) }
99
+ "#{lines.join("\n")}\n"
100
+ end
101
+
102
+ private
103
+
104
+ # @rbs () -> String
105
+ def status
106
+ return "ambiguous" if @checks.any? { |check| check.fetch(:result) == "ambiguous" }
107
+ return "inconclusive" if @checks.any? { |check| check.fetch(:configuration_budget_exhausted) }
108
+
109
+ "no_ambiguity_found_within_bounds"
110
+ end
111
+
112
+ # @rbs () -> ambiguity_summary
113
+ def summary
114
+ {
115
+ conflicts: @checks.length,
116
+ ambiguous: @checks.count { |check| check.fetch(:result) == "ambiguous" },
117
+ not_found: @checks.count { |check| check.fetch(:result) == "not_found" },
118
+ configuration_budget_exhausted: @checks.count do |check|
119
+ check.fetch(:configuration_budget_exhausted)
120
+ end
121
+ }
122
+ end
123
+
124
+ # @rbs () -> Array[ambiguity_check]
125
+ def check_conflicts
126
+ @automaton.states.flat_map do |state|
127
+ state.conflicts.map { |conflict| check_conflict(state, conflict) }
128
+ end
129
+ end
130
+
131
+ # @rbs (IR::AutomatonState state, IR::conflict conflict) -> ambiguity_check
132
+ def check_conflict(state, conflict)
133
+ search = LALR::ConflictSearch.new(
134
+ @automaton, state, conflict,
135
+ max_tokens: @max_tokens, max_configurations: @max_configurations
136
+ )
137
+ outcome = search.call
138
+ result = outcome[:result]
139
+ {
140
+ state: state.id,
141
+ type: conflict.fetch(:type).to_s,
142
+ token: conflict.fetch(:symbol),
143
+ result: outcome[:status] == :found ? "ambiguous" : "not_found",
144
+ sentence: result ? symbol_names(result.fetch(:sentence_ids)) : [],
145
+ lookahead_index: result&.fetch(:lookahead_index),
146
+ interpretations: result ? result.fetch(:interpretations) : [],
147
+ explored_configurations: outcome.fetch(:explored),
148
+ configuration_budget_exhausted: outcome.fetch(:exhausted)
149
+ }
150
+ end
151
+
152
+ # @rbs (Array[Integer] ids) -> Array[String]
153
+ def symbol_names(ids)
154
+ ids.map do |id|
155
+ symbol = @grammar.symbol_by_id(id) || raise(Ibex::Error, "missing grammar symbol id #{id}")
156
+ symbol.display_name || symbol.name
157
+ end
158
+ end
159
+
160
+ # @rbs (Array[String] lines, ambiguity_check check, Integer number) -> void
161
+ def append_check(lines, check, number)
162
+ lines << ""
163
+ lines << "#{number}. State #{check.fetch(:state)}, #{check.fetch(:type)}, token #{check.fetch(:token)}"
164
+ lines << " Result: #{check.fetch(:result)}"
165
+ sentence = check.fetch(:sentence)
166
+ lines << " Sentence: #{sentence.join(' ')}" unless sentence.empty?
167
+ lines << " Explored configurations: #{check.fetch(:explored_configurations)}"
168
+ return unless check.fetch(:configuration_budget_exhausted)
169
+
170
+ lines << " Configuration budget exhausted before a counterexample was found."
171
+ end
172
+ end
173
+ end
174
+ end