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,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Static validation and collection for rules eliminated by inline expansion.
5
+ module NormalizeInlineValidation
6
+ private
7
+
8
+ # @rbs () -> void
9
+ def gather_inline_rules
10
+ # @type self: Normalizer
11
+ @inline_rule_names = Set.new #: Set[String]
12
+ markings = {} #: Hash[String, bool]
13
+ @ast.rules.each do |rule|
14
+ previous = markings[rule.lhs]
15
+ if !previous.nil? && previous != rule.inline
16
+ fail_at(rule.loc, "rule #{rule.lhs} has both inline and ordinary definitions")
17
+ end
18
+ markings[rule.lhs] = rule.inline
19
+ @inline_rule_names << rule.lhs if rule.inline
20
+ end
21
+ validate_inline_terminal_collisions
22
+ validate_inline_start
23
+ validate_inline_cycles
24
+ end
25
+
26
+ # @rbs () -> void
27
+ def validate_inline_terminal_collisions
28
+ # @type self: Normalizer
29
+ @ast.rules.each do |rule|
30
+ next unless rule.inline
31
+ next unless @declared_tokens.key?(rule.lhs) || @precedence.key?(rule.lhs)
32
+
33
+ fail_at(rule.loc, "inline rule #{rule.lhs} collides with terminal #{rule.lhs}")
34
+ end
35
+ end
36
+
37
+ # @rbs () -> void
38
+ def validate_inline_start
39
+ # @type self: Normalizer
40
+ inline_start = @explicit_starts&.find { |name| @inline_rule_names.include?(name) }
41
+ return unless inline_start
42
+
43
+ fail_at(@start_location || @ast.loc, "inline rule #{inline_start} cannot be the start symbol")
44
+ end
45
+
46
+ # @rbs () -> void
47
+ def validate_inline_cycles
48
+ # @type self: Normalizer
49
+ names = @ast.rules.to_set(&:lhs)
50
+ liveness = parameter_formal_liveness
51
+ graph = Hash.new { |hash, name| hash[name] = [] } #: Hash[String, Array[[String, Frontend::Location]]]
52
+ @ast.rules.each do |rule|
53
+ rule.alternatives.each do |alternative|
54
+ alternative.items.each do |item|
55
+ collect_inline_edges(item, rule.parameters, names, graph[rule.lhs], liveness)
56
+ end
57
+ end
58
+ end
59
+ states = {} #: Hash[String, Symbol]
60
+ names.each { |name| visit_inline_cycle(name, graph, states) unless states.key?(name) }
61
+ end
62
+
63
+ # A formal is live for cycle analysis only when substituting its actual can
64
+ # introduce a grammar reference. Calls propagate liveness through their
65
+ # callee's live positions until the finite formal set reaches a fixed point.
66
+ # @rbs () -> Hash[String, Set[Integer]]
67
+ def parameter_formal_liveness
68
+ # @type self: Normalizer
69
+ liveness = @parameter_formals.to_h { |name, _formals| [name, Set.new] } #: Hash[String, Set[Integer]]
70
+ loop do
71
+ changed = false
72
+ @parameter_templates.each do |name, rules|
73
+ formals = @parameter_formals.fetch(name)
74
+ found = Set.new #: Set[Integer]
75
+ rules.each do |rule|
76
+ rule.alternatives.each do |alternative|
77
+ alternative.items.each { |item| collect_live_formals(item, formals, liveness, found) }
78
+ end
79
+ end
80
+ additions = found - liveness.fetch(name)
81
+ next if additions.empty?
82
+
83
+ liveness.fetch(name).merge(additions)
84
+ changed = true
85
+ end
86
+ return liveness unless changed
87
+ end
88
+ end
89
+
90
+ # @rbs (Frontend::AST::item item, Array[String] formals,
91
+ # Hash[String, Set[Integer]] liveness, Set[Integer] found) -> void
92
+ def collect_live_formals(item, formals, liveness, found)
93
+ # @type self: Normalizer
94
+ case item
95
+ when Frontend::AST::SymbolReference
96
+ index = formals.index(item.name)
97
+ found << index if index
98
+ when Frontend::AST::ParameterizedReference
99
+ liveness.fetch(item.name, Set.new).each do |index|
100
+ collect_live_formals(item.arguments.fetch(index), formals, liveness, found)
101
+ end
102
+ when Frontend::AST::Group
103
+ item.alternatives.flatten.each { |child| collect_live_formals(child, formals, liveness, found) }
104
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
105
+ collect_live_formals(item.item, formals, liveness, found)
106
+ when Frontend::AST::SeparatedList
107
+ collect_live_formals(item.item, formals, liveness, found)
108
+ collect_live_formals(item.separator, formals, liveness, found)
109
+ end
110
+ end
111
+
112
+ # Structural AST traversal necessarily branches once for each public item shape.
113
+ # rubocop:disable Metrics/CyclomaticComplexity
114
+ # @rbs (Frontend::AST::item item, Array[String] formals, Set[String] names,
115
+ # Array[[String, Frontend::Location]] edges, Hash[String, Set[Integer]] liveness) -> void
116
+ def collect_inline_edges(item, formals, names, edges, liveness)
117
+ # @type self: Normalizer
118
+ case item
119
+ when Frontend::AST::SymbolReference
120
+ edges << [item.name, item.loc] if !formals.include?(item.name) && names.include?(item.name)
121
+ when Frontend::AST::ParameterizedReference
122
+ edges << [item.name, item.loc] if names.include?(item.name)
123
+ liveness.fetch(item.name, Set.new).each do |index|
124
+ collect_inline_edges(item.arguments.fetch(index), formals, names, edges, liveness)
125
+ end
126
+ when Frontend::AST::Group
127
+ item.alternatives.flatten.each do |child|
128
+ collect_inline_edges(child, formals, names, edges, liveness)
129
+ end
130
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
131
+ collect_inline_edges(item.item, formals, names, edges, liveness)
132
+ when Frontend::AST::SeparatedList
133
+ collect_inline_edges(item.item, formals, names, edges, liveness)
134
+ collect_inline_edges(item.separator, formals, names, edges, liveness)
135
+ end
136
+ end
137
+ # rubocop:enable Metrics/CyclomaticComplexity
138
+
139
+ # @rbs (String name, Hash[String, Array[[String, Frontend::Location]]] graph,
140
+ # Hash[String, Symbol] states) -> void
141
+ def visit_inline_cycle(name, graph, states)
142
+ # @type self: Normalizer
143
+ states[name] = :visiting
144
+ path = [name] #: Array[String]
145
+ positions = { name => 0 } #: Hash[String, Integer]
146
+ worklist = [[name, 0]] #: Array[[String, Integer]]
147
+ until worklist.empty?
148
+ current, edge_index = worklist.fetch(-1)
149
+ edges = graph[current]
150
+ if edge_index >= edges.length
151
+ worklist.pop
152
+ positions.delete(path.pop || raise(Ibex::Error, "internal inline cycle path underflow"))
153
+ states[current] = :visited
154
+ next
155
+ end
156
+
157
+ worklist[-1] = [current, edge_index + 1]
158
+ target, location = edges.fetch(edge_index)
159
+ if states[target] == :visiting
160
+ cycle = path.drop(positions.fetch(target))
161
+ next unless cycle.any? { |entry| @inline_rule_names.include?(entry) }
162
+
163
+ fail_at(location, "inline expansion cycle: #{(cycle + [target]).join(' -> ')}")
164
+ end
165
+ next if states.key?(target)
166
+
167
+ states[target] = :visiting
168
+ positions[target] = path.length
169
+ path << target
170
+ worklist << [target, 0]
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Lexer declaration normalization and static safety checks.
5
+ module NormalizeLexer
6
+ private
7
+
8
+ # @rbs () -> IR::Lexer?
9
+ def normalize_lexer
10
+ # @type self: Normalizer
11
+ declaration = @lexer_declaration
12
+ return unless declaration
13
+
14
+ states = ["INITIAL"] #: Array[String]
15
+ rules = [] #: Array[IR::LexerRule]
16
+ warnings = [] #: Array[IR::lexer_warning]
17
+ declaration.definitions.each do |definition|
18
+ if definition.is_a?(Frontend::AST::LexerState)
19
+ normalize_lexer_state(definition, states, rules, warnings)
20
+ else
21
+ rules << normalize_lexer_rule(definition, "INITIAL", rules.length, warnings)
22
+ end
23
+ end
24
+ fail_at(declaration.loc, "lexer declaration requires at least one rule") if rules.empty?
25
+ IR::Lexer.new(
26
+ states: states, rules: rules, warnings: warnings,
27
+ source_provenance: { file: declaration.loc.file, root: @resolution&.root_directory, byte_span: nil }
28
+ )
29
+ end
30
+
31
+ # @rbs (Frontend::AST::LexerState definition, Array[String] states, Array[IR::LexerRule] rules,
32
+ # Array[IR::lexer_warning] warnings) -> void
33
+ def normalize_lexer_state(definition, states, rules, warnings)
34
+ # @type self: Normalizer
35
+ fail_at(definition.loc, "lexer state INITIAL is reserved") if definition.name == "INITIAL"
36
+ fail_at(definition.loc, "duplicate lexer state #{definition.name}") if states.include?(definition.name)
37
+ states << definition.name
38
+ definition.definitions.each do |entry|
39
+ fail_at(entry.loc, "nested lexer states are not supported") if entry.is_a?(Frontend::AST::LexerState)
40
+
41
+ rules << normalize_lexer_rule(entry, definition.name, rules.length, warnings)
42
+ end
43
+ end
44
+
45
+ # @rbs (Frontend::AST::LexerRule definition, String state, Integer id,
46
+ # Array[IR::lexer_warning] warnings) -> IR::LexerRule
47
+ def normalize_lexer_rule(definition, state, id, warnings)
48
+ # @type self: Normalizer
49
+ validate_lexer_token(definition)
50
+ validate_lexer_action(definition)
51
+ source, options = normalize_lexer_pattern(definition)
52
+ validate_lexer_regexp(definition, source, options)
53
+ if risky_lexer_pattern?(source)
54
+ warning = { type: :lexer_redos, loc: definition.loc.to_h } #: IR::grammar_warning
55
+ warning[:symbol] = definition.token if definition.token
56
+ @warnings << warning
57
+ warnings << { type: :redos, rule: id, loc: definition.loc.to_h }
58
+ end
59
+ IR::LexerRule.new(
60
+ id: id, state: state, kind: definition.kind, token: definition.token,
61
+ pattern: source, pattern_kind: definition.pattern_kind, options: options,
62
+ action: definition.action, location: definition.loc.to_h
63
+ )
64
+ end
65
+
66
+ # @rbs (Frontend::AST::LexerRule definition) -> void
67
+ def validate_lexer_token(definition)
68
+ # @type self: Normalizer
69
+ return unless definition.kind == :token
70
+ return if definition.token && @declared_tokens.key?(definition.token)
71
+
72
+ fail_at(definition.loc, "lexer rule references undeclared terminal #{definition.token}")
73
+ end
74
+
75
+ # @rbs (Frontend::AST::LexerRule definition) -> void
76
+ def validate_lexer_action(definition)
77
+ # @type self: Normalizer
78
+ action = definition.action
79
+ return unless action&.lstrip&.start_with?("|")
80
+
81
+ match = action.match(/\A\s*\|([a-z_][a-zA-Z0-9_]*)\|/m)
82
+ fail_at(definition.loc, "lexer action accepts exactly one local identifier") unless match
83
+ name = match[1]
84
+ fail_at(definition.loc, "lexer action parameter #{name.inspect} is a Ruby keyword") if
85
+ Normalizer::RUBY_KEYWORDS.include?(name)
86
+ end
87
+
88
+ # @rbs (Frontend::AST::LexerRule definition) -> [String, String]
89
+ def normalize_lexer_pattern(definition)
90
+ # @type self: Normalizer
91
+ raw = definition.pattern
92
+ if definition.pattern_kind == :literal
93
+ decoded = decode_lexer_literal(raw, definition.loc)
94
+ fail_at(definition.loc, "lexer pattern must not be empty") if decoded.empty?
95
+ return [Regexp.escape(decoded), ""]
96
+ end
97
+
98
+ closing = raw.rindex("/")
99
+ fail_at(definition.loc, "invalid lexer regular expression") unless closing&.positive?
100
+ [raw[1...closing] || "", raw[(closing + 1)..] || ""]
101
+ end
102
+
103
+ # @rbs (String raw, Frontend::Location location) -> String
104
+ def decode_lexer_literal(raw, location)
105
+ # @type self: Normalizer
106
+ return raw.undump if raw.start_with?('"')
107
+
108
+ (raw[1...-1] || "").gsub("\\'", "'").gsub("\\\\", "\\")
109
+ rescue RuntimeError => e
110
+ fail_at(location, "invalid lexer literal: #{e.message}")
111
+ end
112
+
113
+ # @rbs (Frontend::AST::LexerRule definition, String source, String options) -> void
114
+ def validate_lexer_regexp(definition, source, options)
115
+ # @type self: Normalizer
116
+ flags = 0
117
+ flags |= Regexp::IGNORECASE if options.include?("i")
118
+ flags |= Regexp::MULTILINE if options.include?("m")
119
+ flags |= Regexp::EXTENDED if options.include?("x")
120
+ regexp = Regexp.new("\\A(?:#{source})", flags)
121
+ fail_at(definition.loc, "lexer pattern must not match an empty string") if regexp.match?("")
122
+ rescue RegexpError => e
123
+ fail_at(definition.loc, "invalid lexer regular expression: #{e.message}")
124
+ end
125
+
126
+ # @rbs (String source) -> bool
127
+ def risky_lexer_pattern?(source)
128
+ source.match?(/\([^)]*[+*][^)]*\)[+*{]/) || source.match?(/\.\*[+*{]/)
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Named-reference collection and validation shared by ordinary and parameterized items.
5
+ module NormalizeNamedReferences
6
+ private
7
+
8
+ # @rbs (Frontend::AST::Group group) -> void
9
+ def reject_group_named_references(group)
10
+ # @type self: Normalizer
11
+ reference = group.alternatives.flatten.filter_map { |item| named_reference_in(item) }.first
12
+ fail_at(reference.loc, "named references inside EBNF groups are not supported") if reference
13
+ end
14
+
15
+ # @rbs (Frontend::AST::item item) -> (Frontend::AST::SymbolReference | Frontend::AST::ParameterizedReference)?
16
+ def named_reference_in(item)
17
+ # @type self: Normalizer
18
+ if (item.is_a?(Frontend::AST::SymbolReference) ||
19
+ item.is_a?(Frontend::AST::ParameterizedReference)) && item.named_reference
20
+ return item
21
+ end
22
+ if item.is_a?(Frontend::AST::Group)
23
+ return item.alternatives.flatten.filter_map { |child| named_reference_in(child) }.first
24
+ end
25
+ if item.is_a?(Frontend::AST::Optional) || item.is_a?(Frontend::AST::Star) ||
26
+ item.is_a?(Frontend::AST::Plus) || item.is_a?(Frontend::AST::SeparatedList)
27
+ return named_reference_in(item.item)
28
+ end
29
+
30
+ nil
31
+ end
32
+
33
+ # @rbs (Frontend::AST::item item, Array[IR::named_ref] refs, Integer index) -> void
34
+ def add_named_reference(item, refs, index)
35
+ # @type self: Normalizer
36
+ reference = unwrap_reference(item)
37
+ return unless reference
38
+
39
+ name = reference.named_reference
40
+ return unless name
41
+
42
+ fail_at(reference.loc, "reserved named reference #{name}") if Normalizer::RESERVED_NAMES.include?(name)
43
+ fail_at(reference.loc, "duplicate named reference #{name}") if refs.any? { |entry| entry[:name] == name }
44
+ refs << { name: name, index: index }
45
+ end
46
+
47
+ # @rbs (Frontend::AST::item item) -> (Frontend::AST::SymbolReference | Frontend::AST::ParameterizedReference)?
48
+ def unwrap_reference(item)
49
+ # @type self: Normalizer
50
+ return item if item.is_a?(Frontend::AST::SymbolReference) ||
51
+ item.is_a?(Frontend::AST::ParameterizedReference)
52
+ if item.is_a?(Frontend::AST::Optional) || item.is_a?(Frontend::AST::Star) ||
53
+ item.is_a?(Frontend::AST::Plus) || item.is_a?(Frontend::AST::SeparatedList)
54
+ return unwrap_reference(item.item)
55
+ end
56
+
57
+ nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Validation and normalization for generated AST node declarations.
5
+ module NormalizeNodes
6
+ private
7
+
8
+ # @rbs (Frontend::AST::Alternative alternative, Array[String] rhs) -> IR::node_annotation?
9
+ def normalize_node_annotation(alternative, rhs)
10
+ # @type self: Normalizer
11
+ annotation = alternative.node_annotation
12
+ return unless annotation
13
+
14
+ if alternative.action || alternative.items.any?(Frontend::AST::InlineAction)
15
+ fail_at(annotation.loc, "@node cannot be combined with semantic actions")
16
+ end
17
+ unless annotation.name.match?(/\A[A-Z][A-Za-z0-9_]*\z/)
18
+ fail_at(annotation.loc, "@node name #{annotation.name.inspect} must be a Ruby constant identifier")
19
+ end
20
+ validate_node_fields(annotation, rhs)
21
+ previous = @node_shapes[annotation.name]
22
+ if previous && previous != annotation.fields
23
+ fail_at(annotation.loc, "@node #{annotation.name} was already declared with fields (#{previous.join(', ')})")
24
+ end
25
+ @node_shapes[annotation.name] = annotation.fields.dup.freeze
26
+ { name: annotation.name, fields: annotation.fields, loc: annotation.loc.to_h }
27
+ end
28
+
29
+ # @rbs (Frontend::AST::NodeAnnotation annotation, Array[String] rhs) -> void
30
+ def validate_node_fields(annotation, rhs)
31
+ # @type self: Normalizer
32
+ unless annotation.fields.length == rhs.length
33
+ fail_at(
34
+ annotation.loc,
35
+ "@node #{annotation.name} declares #{annotation.fields.length} fields for #{rhs.length} RHS values"
36
+ )
37
+ end
38
+ duplicate = annotation.fields.tally.find { |_name, count| count > 1 }&.first
39
+ fail_at(annotation.loc, "@node field #{duplicate.inspect} is duplicated") if duplicate
40
+ invalid = annotation.fields.find do |field|
41
+ !field.match?(/\A[a-z_][a-zA-Z0-9_]*\z/) || Normalizer::RUBY_KEYWORDS.include?(field)
42
+ end
43
+ fail_at(annotation.loc, "@node field #{invalid.inspect} must be a Ruby local identifier") if invalid
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Resumable EBNF lowering used inside specialized parameter alternatives.
5
+ module NormalizeParameterEbnfLowering
6
+ private
7
+
8
+ # @rbs (NormalizeParameters::parameter_frame frame,
9
+ # Frontend::AST::Optional | Frontend::AST::Star | Frontend::AST::Plus item) -> void
10
+ def lower_parameter_suffix(frame, item)
11
+ frame.fetch(:operations).push([:finish_suffix, item], [:item, item.item])
12
+ end
13
+
14
+ # @rbs (NormalizeParameters::parameter_frame frame,
15
+ # Frontend::AST::Optional | Frontend::AST::Star | Frontend::AST::Plus item) -> void
16
+ def finish_parameter_suffix(frame, item)
17
+ # @type self: Normalizer
18
+ base = frame.fetch(:values).pop || raise(Ibex::Error, "missing parameter value")
19
+ helper = case item
20
+ when Frontend::AST::Optional then build_optional(item, base)
21
+ when Frontend::AST::Star then build_star(item, base)
22
+ when Frontend::AST::Plus then build_plus(item, base)
23
+ end
24
+ frame.fetch(:values) << helper
25
+ end
26
+
27
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::SeparatedList item) -> void
28
+ def lower_parameter_separated_list(frame, item)
29
+ frame.fetch(:operations).push(
30
+ [:finish_separated, item], [:item, item.separator], [:item, item.item]
31
+ )
32
+ end
33
+
34
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::SeparatedList item) -> void
35
+ def finish_parameter_separated_list(frame, item)
36
+ # @type self: Normalizer
37
+ separator = frame.fetch(:values).pop || raise(Ibex::Error, "missing parameter value")
38
+ base = frame.fetch(:values).pop || raise(Ibex::Error, "missing parameter value")
39
+ frame.fetch(:values) << build_separated_list(item, base, separator)
40
+ end
41
+
42
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::Group item) -> void
43
+ def lower_parameter_group(frame, item)
44
+ # @type self: Normalizer
45
+ reject_group_named_references(item)
46
+ helper = new_helper("group", item.loc)
47
+ operations = frame.fetch(:operations)
48
+ operations << [:value, helper]
49
+ item.alternatives.reverse_each do |alternative|
50
+ operations << [:group_alternative, helper, item, alternative]
51
+ end
52
+ end
53
+
54
+ # @rbs (NormalizeParameters::parameter_frame frame, String helper, Frontend::AST::Group item,
55
+ # Array[Frontend::AST::item] alternative) -> void
56
+ def start_parameter_group_alternative(frame, helper, item, alternative)
57
+ operations = frame.fetch(:operations)
58
+ operations << [:finish_group_alternative, helper, item, alternative.length]
59
+ alternative.reverse_each { |child| operations << [:item, child] }
60
+ end
61
+
62
+ # @rbs (NormalizeParameters::parameter_frame frame, String helper,
63
+ # Frontend::AST::Group item, Integer length) -> void
64
+ def finish_parameter_group_alternative(frame, helper, item, length)
65
+ # @type self: Normalizer
66
+ rhs = frame.fetch(:values).pop(length)
67
+ add_group_production(helper, rhs, item)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Resumable, source-ordered lowering for specialized parameter alternatives.
5
+ module NormalizeParameterLowering
6
+ private
7
+
8
+ # @rbs (NormalizeParameters::parameter_frame frame) -> void
9
+ def advance_parameter_alternative(frame)
10
+ # @type self: Normalizer
11
+ with_parameter_frame_context(frame) do
12
+ operations = frame.fetch(:operations)
13
+ if operations.any?
14
+ operation = operations.pop #: NormalizeParameters::parameter_operation
15
+ process_parameter_operation(frame, operation)
16
+ elsif parameter_items_remaining?(frame)
17
+ start_parameter_item(frame)
18
+ else
19
+ finish_parameter_alternative(frame)
20
+ end
21
+ end
22
+ end
23
+
24
+ # @rbs (NormalizeParameters::parameter_frame frame) { () -> void } -> void
25
+ def with_parameter_frame_context(frame)
26
+ # @type self: Normalizer
27
+ template, = frame.fetch(:current) || raise(Ibex::Error, "missing parameter alternative")
28
+ previous_chain = @current_include_chain
29
+ previous_expansion = @current_parameter_expansion
30
+ reference = frame.fetch(:reference)
31
+ @current_include_chain = @resolution&.include_chain_for(template) || []
32
+ @current_parameter_expansion = {
33
+ rule: reference.name, arguments: frame.fetch(:rendered_arguments)
34
+ }
35
+ yield
36
+ ensure
37
+ @current_include_chain = previous_chain
38
+ @current_parameter_expansion = previous_expansion
39
+ end
40
+
41
+ # @rbs (NormalizeParameters::parameter_frame frame) -> bool
42
+ def parameter_items_remaining?(frame)
43
+ _template, _rule, alternative = frame.fetch(:current) || raise(Ibex::Error, "missing parameter alternative")
44
+ frame.fetch(:item_index) < alternative.items.length
45
+ end
46
+
47
+ # @rbs (NormalizeParameters::parameter_frame frame) -> void
48
+ def start_parameter_item(frame)
49
+ # @type self: Normalizer
50
+ _template, _rule, alternative = frame.fetch(:current) || raise(Ibex::Error, "missing parameter alternative")
51
+ index = frame.fetch(:item_index)
52
+ item = alternative.items.fetch(index)
53
+ frame[:item_index] = index + 1
54
+ if item.is_a?(Frontend::AST::InlineAction)
55
+ frame.fetch(:rhs) << expand_inline_action(
56
+ item, frame.fetch(:rhs).length, frame.fetch(:named_refs)
57
+ )
58
+ else
59
+ frame.fetch(:operations).push([:finish_item, item], [:item, item])
60
+ end
61
+ end
62
+
63
+ # @rbs (NormalizeParameters::parameter_frame frame, NormalizeParameters::parameter_operation operation) -> void
64
+ def process_parameter_operation(frame, operation)
65
+ # @type self: Normalizer
66
+ kind = operation.fetch(0) #: Symbol
67
+ case kind
68
+ when :item
69
+ item = operation.fetch(1) #: Frontend::AST::item
70
+ lower_parameter_item(frame, item)
71
+ when :finish_item
72
+ item = operation.fetch(1) #: Frontend::AST::item
73
+ finish_parameter_item(frame, item)
74
+ when :value
75
+ value = operation.fetch(1) #: String
76
+ frame.fetch(:values) << value
77
+ when :finish_suffix
78
+ item = operation.fetch(1) #: Frontend::AST::Optional | Frontend::AST::Star | Frontend::AST::Plus
79
+ finish_parameter_suffix(frame, item)
80
+ when :finish_separated
81
+ item = operation.fetch(1) #: Frontend::AST::SeparatedList
82
+ finish_parameter_separated_list(frame, item)
83
+ when :group_alternative
84
+ helper = operation.fetch(1) #: String
85
+ item = operation.fetch(2) #: Frontend::AST::Group
86
+ alternative = operation.fetch(3) #: Array[Frontend::AST::item]
87
+ start_parameter_group_alternative(frame, helper, item, alternative)
88
+ when :finish_group_alternative
89
+ helper = operation.fetch(1) #: String
90
+ item = operation.fetch(2) #: Frontend::AST::Group
91
+ length = operation.fetch(3) #: Integer
92
+ finish_parameter_group_alternative(frame, helper, item, length)
93
+ else raise Ibex::Error, "internal parameter lowering operation #{kind.inspect}"
94
+ end
95
+ end
96
+
97
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::item item) -> void
98
+ def lower_parameter_item(frame, item)
99
+ # @type self: Normalizer
100
+ case item
101
+ when Frontend::AST::SymbolReference
102
+ frame.fetch(:values) << symbol_for_reference(item).name
103
+ when Frontend::AST::ParameterizedReference
104
+ lower_parameter_call(frame, item)
105
+ when Frontend::AST::Group
106
+ lower_parameter_group(frame, item)
107
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
108
+ lower_parameter_suffix(frame, item)
109
+ when Frontend::AST::SeparatedList
110
+ lower_parameter_separated_list(frame, item)
111
+ else
112
+ fail_at(item.loc, "unsupported nested EBNF expression")
113
+ end
114
+ end
115
+
116
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::ParameterizedReference item) -> void
117
+ def lower_parameter_call(frame, item)
118
+ # @type self: Normalizer
119
+ helper, = schedule_parameter_specialization(item)
120
+ frame.fetch(:values) << helper
121
+ end
122
+
123
+ # @rbs (NormalizeParameters::parameter_frame frame, Frontend::AST::item item) -> void
124
+ def finish_parameter_item(frame, item)
125
+ # @type self: Normalizer
126
+ rhs = frame.fetch(:rhs)
127
+ rhs << (frame.fetch(:values).pop || raise(Ibex::Error, "missing parameter value"))
128
+ add_named_reference(item, frame.fetch(:named_refs), rhs.length - 1)
129
+ end
130
+
131
+ # @rbs (NormalizeParameters::parameter_frame frame) -> void
132
+ def finish_parameter_alternative(frame)
133
+ # @type self: Normalizer
134
+ _template, rule, alternative = frame.fetch(:current) || raise(Ibex::Error, "missing parameter alternative")
135
+ action = normalize_action(alternative.action, frame.fetch(:named_refs))
136
+ add_production(
137
+ rule.lhs, frame.fetch(:rhs), action, alternative.precedence,
138
+ { kind: :user, loc: alternative.loc.to_h }, rule.documentation
139
+ )
140
+ clear_parameter_alternative(frame)
141
+ end
142
+ end
143
+ end