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
@@ -2,23 +2,65 @@
2
2
 
3
3
  module Ibex
4
4
  module Frontend
5
+ # Keeps the public Rule constructor compatible with ASTs built before parameters and inline rules existed.
6
+ module ASTRuleDefaults
7
+ # @rbs (*untyped arguments, **untyped keywords) -> void
8
+ def initialize(*arguments, **keywords)
9
+ if arguments.empty?
10
+ keywords = keywords.merge(parameters: keywords[:parameters] || [], inline: keywords[:inline] || false)
11
+ elsif arguments.one? && arguments.first.is_a?(Hash)
12
+ attributes = arguments.first
13
+ arguments = [
14
+ attributes.merge(parameters: attributes[:parameters] || [], inline: attributes[:inline] || false)
15
+ ]
16
+ end
17
+ super(*arguments, **keywords) # rubocop:disable Style/SuperArguments
18
+ end
19
+ end
20
+
5
21
  # Grammar frontend node types.
22
+ # rubocop:disable Metrics/ModuleLength -- the public node vocabulary is intentionally kept together.
6
23
  module AST
7
24
  # @rbs!
8
- # type declaration = Tokens | Precedence | Options | Expect | Start | Convert
9
- # type item = SymbolReference | InlineAction | Optional | Star | Plus | Group | SeparatedList
25
+ # type symbol_metadata = DisplayName | SemanticType
26
+ # type declaration = Include | Tokens | Precedence | Options | Expect | ExpectRR | Start | Recovery |
27
+ # OnErrorReduce | GrammarTest | Lexer | Convert | Parameter | Printer | ParserConfiguration | symbol_metadata
28
+ # type lexer_entry = LexerRule | LexerState
29
+ # type item = SymbolReference | ParameterizedReference | InlineAction | Optional | Star | Plus | Group |
30
+ # SeparatedList | Empty
10
31
  # type user_code = Hash[String, Array[UserCode]]
32
+ # class Rule < Struct[String | Array[String] | Array[Alternative] | Location | String? | bool]
33
+ # attr_accessor lhs: String
34
+ # attr_accessor parameters: Array[String]
35
+ # attr_accessor alternatives: Array[Alternative]
36
+ # attr_accessor loc: Location
37
+ # attr_accessor documentation: String?
38
+ # attr_accessor inline: bool
39
+ # def self.new: (?lhs: String, ?parameters: Array[String]?, ?alternatives: Array[Alternative],
40
+ # ?loc: Location, ?documentation: String?, ?inline: bool?) -> instance
41
+ # | ({ ?lhs: String, ?parameters: Array[String]?, ?alternatives: Array[Alternative],
42
+ # ?loc: Location, ?documentation: String?, ?inline: bool? }) -> instance
43
+ # end
11
44
 
12
45
  # Adds deterministic, recursively serializable hashes to Struct nodes.
13
- # @rbs module-self Struct[untyped]
46
+ # @rbs module-self Struct[Object?]
14
47
  module Node
48
+ # @rbs () -> Hash[Symbol, untyped]
15
49
  def to_h
16
50
  fields = each_pair.to_h { |name, value| [name, serialize(value)] }
51
+ fields.delete(:aliases) if self.class.name.end_with?("::Tokens") && !fields[:aliases]
52
+ if self.class.name.end_with?("::Root")
53
+ fields.delete(:extended) unless fields[:extended]
54
+ fields.delete(:extended_loc) unless fields[:extended_loc]
55
+ fields.delete(:cst) unless fields[:cst]
56
+ end
57
+ fields.delete(:node_annotation) if self.class.name.end_with?("::Alternative") && !fields[:node_annotation]
17
58
  { node: self.class.name.split("::").last }.merge(fields)
18
59
  end
19
60
 
20
61
  private
21
62
 
63
+ # @rbs (untyped value) -> untyped
22
64
  def serialize(value)
23
65
  return value if value.nil?
24
66
 
@@ -37,12 +79,25 @@ module Ibex
37
79
  :rules, #: Array[Rule]
38
80
  :user_code, #: user_code
39
81
  :loc, #: Location
82
+ :extended, #: bool?
83
+ :cst, #: bool?
84
+ :extended_loc, #: Location?
40
85
  keyword_init: true
41
- ) do
42
- include Node
43
- end
86
+ ) { include Node }
87
+ Fragment = Struct.new(
88
+ :declarations, #: Array[declaration]
89
+ :rules, #: Array[Rule]
90
+ :loc, #: Location
91
+ keyword_init: true
92
+ ) { include Node }
93
+ Include = Struct.new(
94
+ :path, #: String
95
+ :loc, #: Location
96
+ keyword_init: true
97
+ ) { include Node }
44
98
  Tokens = Struct.new(
45
99
  :names, #: Array[String]
100
+ :aliases, #: Hash[String, String]?
46
101
  :loc, #: Location
47
102
  keyword_init: true
48
103
  ) { include Node }
@@ -68,8 +123,49 @@ module Ibex
68
123
  :loc, #: Location
69
124
  keyword_init: true
70
125
  ) { include Node }
126
+ ExpectRR = Struct.new(
127
+ :conflicts, #: Integer
128
+ :loc, #: Location
129
+ keyword_init: true
130
+ ) { include Node }
71
131
  Start = Struct.new(
132
+ :names, #: Array[String]
133
+ :loc, #: Location
134
+ keyword_init: true
135
+ ) { include Node }
136
+ Recovery = Struct.new(
137
+ :sync_tokens, #: Array[String]
138
+ :loc, #: Location
139
+ keyword_init: true
140
+ ) { include Node }
141
+ OnErrorReduce = Struct.new(
142
+ :names, #: Array[String]
143
+ :loc, #: Location
144
+ keyword_init: true
145
+ ) { include Node }
146
+ GrammarTest = Struct.new(
147
+ :expectation, #: Symbol
148
+ :source, #: String
149
+ :loc, #: Location
150
+ keyword_init: true
151
+ ) { include Node }
152
+ Lexer = Struct.new(
153
+ :definitions, #: Array[lexer_entry]
154
+ :loc, #: Location
155
+ keyword_init: true
156
+ ) { include Node }
157
+ LexerRule = Struct.new(
158
+ :kind, #: Symbol
159
+ :token, #: String?
160
+ :pattern, #: String
161
+ :pattern_kind, #: Symbol
162
+ :action, #: String?
163
+ :loc, #: Location
164
+ keyword_init: true
165
+ ) { include Node }
166
+ LexerState = Struct.new(
72
167
  :name, #: String
168
+ :definitions, #: Array[lexer_entry]
73
169
  :loc, #: Location
74
170
  keyword_init: true
75
171
  ) { include Node }
@@ -84,16 +180,67 @@ module Ibex
84
180
  :loc, #: Location
85
181
  keyword_init: true
86
182
  ) { include Node }
183
+ DisplayName = Struct.new(
184
+ :name, #: String
185
+ :value, #: String
186
+ :loc, #: Location
187
+ keyword_init: true
188
+ ) { include Node }
189
+ SemanticType = Struct.new(
190
+ :name, #: String
191
+ :value, #: String
192
+ :loc, #: Location
193
+ keyword_init: true
194
+ ) { include Node }
195
+ Parameter = Struct.new(
196
+ :name, #: String
197
+ :semantic_type, #: String?
198
+ :loc, #: Location
199
+ keyword_init: true
200
+ ) { include Node }
201
+ Printer = Struct.new(
202
+ :name, #: String
203
+ :code, #: String
204
+ :loc, #: Location
205
+ keyword_init: true
206
+ ) { include Node }
207
+ ParserConfiguration = Struct.new(
208
+ :settings, #: Array[ParserSetting]
209
+ :loc, #: Location
210
+ keyword_init: true
211
+ ) { include Node }
212
+ ParserSetting = Struct.new(
213
+ :key, #: Symbol
214
+ :value, #: Symbol
215
+ :loc, #: Location
216
+ keyword_init: true
217
+ ) { include Node }
218
+ ROOT_ONLY_DECLARATION_NAMES = {
219
+ Options => "options", Expect => "expect", ExpectRR => "%expect-rr", Parameter => "%param",
220
+ Start => "start", Recovery => "%recover", OnErrorReduce => "%on_error_reduce", GrammarTest => "%test",
221
+ Lexer => "lexer", ParserConfiguration => "parser"
222
+ }.freeze #: Hash[Class, String]
223
+ # @rbs skip
87
224
  Rule = Struct.new(
88
225
  :lhs, #: String
226
+ :parameters, #: Array[String]
89
227
  :alternatives, #: Array[Alternative]
90
228
  :loc, #: Location
229
+ :documentation, #: String?
230
+ :inline, #: bool
91
231
  keyword_init: true
92
- ) { include Node }
232
+ ) { include Node, ASTRuleDefaults }
93
233
  Alternative = Struct.new(
94
234
  :items, #: Array[item]
95
235
  :action, #: InlineAction?
96
236
  :precedence, #: String?
237
+ :node_annotation, #: NodeAnnotation?
238
+ :loc, #: Location
239
+ keyword_init: true
240
+ ) { include Node }
241
+ NodeAnnotation = Struct.new(
242
+ :name, #: String
243
+ :fields, #: Array[String]
97
244
  :loc, #: Location
98
245
  keyword_init: true
99
246
  ) { include Node }
@@ -103,11 +250,22 @@ module Ibex
103
250
  :loc, #: Location
104
251
  keyword_init: true
105
252
  ) { include Node }
253
+ ParameterizedReference = Struct.new(
254
+ :name, #: String
255
+ :arguments, #: Array[item]
256
+ :named_reference, #: String?
257
+ :loc, #: Location
258
+ keyword_init: true
259
+ ) { include Node }
106
260
  InlineAction = Struct.new(
107
261
  :code, #: String
108
262
  :loc, #: Location
109
263
  keyword_init: true
110
264
  ) { include Node }
265
+ Empty = Struct.new(
266
+ :loc, #: Location
267
+ keyword_init: true
268
+ ) { include Node }
111
269
  Optional = Struct.new(
112
270
  :item, #: item
113
271
  :loc, #: Location
@@ -142,5 +300,6 @@ module Ibex
142
300
  keyword_init: true
143
301
  ) { include Node }
144
302
  end
303
+ # rubocop:enable Metrics/ModuleLength
145
304
  end
146
305
  end
@@ -6,18 +6,21 @@ module Ibex
6
6
  class BootstrapParser
7
7
  include BootstrapParserDeclarations
8
8
  include BootstrapParserRules
9
+ include BootstrapParserParameters
10
+ include ParserConfigurationSupport
9
11
 
10
12
  # @rbs @tokens: Array[Token]
11
13
  # @rbs @index: Integer
12
14
  # @rbs @mode: Symbol
13
15
 
14
16
  # @rbs (String | Array[Token] source, ?file: String, ?mode: Symbol) -> void
15
- def initialize(source, file: "(grammar)", mode: :racc)
16
- raise ArgumentError, "mode must be :racc or :extended" unless %i[racc extended].include?(mode)
17
+ def initialize(source, file: "(grammar)", mode: :default)
18
+ raise ArgumentError, "mode must be :default or :extended" unless %i[default extended].include?(mode)
17
19
 
18
20
  @tokens = source.is_a?(Array) ? source : Lexer.new(source, file: file).tokenize
19
21
  @index = 0
20
22
  @mode = mode
23
+ @pragmas = {} #: Hash[String, Location]
21
24
  end
22
25
 
23
26
  # @rbs () -> AST::Root
@@ -27,17 +30,50 @@ module Ibex
27
30
  superclass = accept(:<) ? parse_constant_path : nil
28
31
  parse_pragmas
29
32
  declarations = parse_declarations
33
+ validate_root_parser_configuration(declarations)
30
34
  expect_keyword("rule")
31
35
  rules = parse_rules
32
- expect_keyword("end")
36
+ expect_keyword("end") unless current.type == :user_code
33
37
  user_code = parse_user_code
34
38
  expect(:eof)
35
39
  AST::Root.new(class_name: class_name, superclass: superclass, declarations: declarations,
36
- rules: rules, user_code: user_code, loc: location)
40
+ rules: rules, user_code: user_code, loc: location,
41
+ extended: @mode == :extended || @pragmas.key?("extended") || @pragmas.key?("cst"),
42
+ cst: @pragmas.key?("cst"),
43
+ extended_loc: @pragmas["extended"] || @pragmas["cst"])
44
+ end
45
+
46
+ # @rbs () -> AST::Fragment
47
+ def parse_fragment
48
+ location = expect_keyword("fragment").location
49
+ extended_only!(location, "fragments")
50
+ declarations = parse_declarations
51
+ reject_fragment_root_declarations(declarations)
52
+ expect_keyword("rule")
53
+ rules = keyword?("end") ? Array.new(0) : parse_rules #: Array[AST::Rule]
54
+ expect_keyword("end")
55
+ user_code = parse_user_code
56
+ fail_at(user_code.values.flatten.first.loc, "user code is not allowed in fragments") unless user_code.empty?
57
+ expect(:eof)
58
+ AST::Fragment.new(declarations: declarations, rules: rules, loc: location)
37
59
  end
38
60
 
39
61
  private
40
62
 
63
+ # @rbs (Array[AST::declaration] declarations) -> void
64
+ def reject_fragment_root_declarations(declarations)
65
+ root_only = declarations.find { |declaration| fragment_root_declaration_name(declaration) }
66
+ return unless root_only
67
+
68
+ name = fragment_root_declaration_name(root_only)
69
+ fail_at(root_only.loc, "#{name} declarations are not allowed in fragments")
70
+ end
71
+
72
+ # @rbs (AST::declaration declaration) -> String?
73
+ def fragment_root_declaration_name(declaration)
74
+ AST::ROOT_ONLY_DECLARATION_NAMES.find { |node_class, _name| declaration.is_a?(node_class) }&.last
75
+ end
76
+
41
77
  # @rbs () -> String
42
78
  def parse_constant_path
43
79
  parts = [token_string(expect(:identifier))]
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module Frontend
5
+ # An immutable machine-readable frontend error.
6
+ class Diagnostic
7
+ attr_reader :code #: String
8
+ attr_reader :phase #: Symbol
9
+ attr_reader :message #: String
10
+ attr_reader :location #: Location
11
+ attr_reader :span #: SourceSpan?
12
+ attr_reader :expected #: Array[String]
13
+ attr_reader :received #: String?
14
+
15
+ # @rbs (code: String, phase: Symbol, message: String, location: Location, ?span: SourceSpan?,
16
+ # ?expected: Array[String], ?received: String?, ?rendered: String?) -> void
17
+ def initialize(code:, phase:, message:, location:, span: nil, expected: [], received: nil, rendered: nil)
18
+ @code = code.dup.freeze
19
+ @phase = phase
20
+ @message = message.dup.freeze
21
+ @location = Location.new(
22
+ file: location.file.dup.freeze, line: location.line, column: location.column
23
+ ).freeze
24
+ @span = span
25
+ @expected = expected.map { |value| value.dup.freeze }.freeze
26
+ @received = received&.dup&.freeze
27
+ @rendered = (rendered || "#{location}: #{message}").dup.freeze
28
+ freeze
29
+ end
30
+
31
+ # @rbs () -> String
32
+ def severity
33
+ "error"
34
+ end
35
+
36
+ # @rbs () -> String
37
+ def to_s
38
+ @rendered
39
+ end
40
+
41
+ # @rbs () -> Hash[Symbol, Object?]
42
+ def to_h
43
+ {
44
+ code: code,
45
+ severity: severity,
46
+ phase: phase.to_s,
47
+ message: message,
48
+ location: location.to_h,
49
+ span: span&.to_h,
50
+ expected: expected,
51
+ received: received
52
+ }
53
+ end
54
+ end
55
+
56
+ # Immutable output from a diagnostic parse.
57
+ class ParseResult
58
+ attr_reader :diagnostics #: Array[Diagnostic]
59
+ attr_reader :ast #: AST::Root?
60
+ attr_reader :document #: SourceDocument?
61
+
62
+ # @rbs (diagnostics: Array[Diagnostic], ast: AST::Root?, document: SourceDocument?) -> void
63
+ def initialize(diagnostics:, ast:, document:)
64
+ @diagnostics = diagnostics.dup.freeze
65
+ @ast = ast
66
+ @document = document
67
+ freeze
68
+ end
69
+
70
+ # @rbs () -> bool
71
+ def success?
72
+ diagnostics.empty? && !ast.nil?
73
+ end
74
+
75
+ # @rbs () -> bool
76
+ def partial?
77
+ diagnostics.any? && !ast.nil?
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,268 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module Frontend
5
+ # Re-runs the generated parser after suppressing only conservative source regions.
6
+ class DiagnosticRecovery
7
+ DECLARATION_STARTS = %w[
8
+ pragma include import token prechigh preclow options expect expect_rr start recover on_error_reduce test lexer
9
+ convert display type param printer
10
+ ].freeze #: Array[String]
11
+
12
+ # @rbs @tokens: Array[Token]
13
+ # @rbs @mode: Symbol
14
+ # @rbs @max_diagnostics: Integer
15
+ # @rbs @suppressed: Hash[Integer, bool]
16
+
17
+ # @rbs (Array[Token] tokens, mode: Symbol, max_diagnostics: Integer) -> void
18
+ def initialize(tokens, mode:, max_diagnostics:)
19
+ @tokens = tokens
20
+ @mode = mode
21
+ @max_diagnostics = max_diagnostics
22
+ @diagnostics = [] #: Array[Diagnostic]
23
+ @suppressed = {} #: Hash[Integer, bool]
24
+ end
25
+
26
+ # @rbs () -> [AST::Root | AST::Fragment | nil, Array[Diagnostic]]
27
+ def parse
28
+ ast = parse_until_stable
29
+ [ast, sorted_diagnostics]
30
+ end
31
+
32
+ private
33
+
34
+ # @rbs () -> (AST::Root | AST::Fragment | nil)
35
+ def parse_until_stable
36
+ attempts = 0
37
+ loop do
38
+ parser = GeneratedParser.new(working_tokens, mode: @mode)
39
+ begin
40
+ return parser.parse
41
+ rescue Ibex::Error => e
42
+ return if @diagnostics.length >= @max_diagnostics
43
+
44
+ diagnostic = diagnostic_from(e, parser.diagnostic_token, phase: :syntax)
45
+ append_diagnostic(diagnostic)
46
+ range = suppression_range(parser.diagnostic_token, e)
47
+ return unless range && suppress(range)
48
+
49
+ attempts += 1
50
+ return if attempts >= @tokens.length
51
+ end
52
+ end
53
+ end
54
+
55
+ # @rbs () -> Array[Token]
56
+ def working_tokens
57
+ @tokens.each_with_index.filter_map { |token, index| token unless @suppressed[index] }
58
+ end
59
+
60
+ # @rbs (Diagnostic diagnostic) -> void
61
+ def append_diagnostic(diagnostic)
62
+ key = diagnostic_key(diagnostic)
63
+ return if @diagnostics.any? { |existing| diagnostic_key(existing) == key }
64
+
65
+ @diagnostics << diagnostic
66
+ end
67
+
68
+ # @rbs (Diagnostic diagnostic) -> [String, String, Integer, Integer, String]
69
+ def diagnostic_key(diagnostic)
70
+ location = diagnostic.location
71
+ [diagnostic.phase.to_s, location.file, location.line, location.column, diagnostic.message]
72
+ end
73
+
74
+ # @rbs () -> Array[Diagnostic]
75
+ def sorted_diagnostics
76
+ @diagnostics.uniq { |diagnostic| diagnostic_key(diagnostic) }
77
+ .sort_by { |diagnostic| diagnostic_sort_key(diagnostic) }
78
+ .first(@max_diagnostics)
79
+ .freeze
80
+ end
81
+
82
+ # @rbs (Diagnostic diagnostic) -> [String, Integer, Integer, String, String]
83
+ def diagnostic_sort_key(diagnostic)
84
+ location = diagnostic.location
85
+ [location.file, location.line, location.column, diagnostic.phase.to_s, diagnostic.code]
86
+ end
87
+
88
+ # @rbs (Token? token, Exception error) -> Range[Integer]?
89
+ def suppression_range(token, error)
90
+ index = token_index(token) || token_index_for_message(error.message)
91
+ return unless index
92
+
93
+ rule_marker = rule_marker_index
94
+ return declaration_range(index, rule_marker) if rule_marker && index < rule_marker
95
+ return rule_range(index, rule_marker) if rule_marker
96
+
97
+ nil
98
+ end
99
+
100
+ # @rbs (Token? token) -> Integer?
101
+ def token_index(token)
102
+ return unless token
103
+
104
+ @tokens.index { |candidate| candidate.equal?(token) }
105
+ end
106
+
107
+ # @rbs (String message) -> Integer?
108
+ def token_index_for_message(message)
109
+ @tokens.index { |token| message.start_with?("#{token.location}:") }
110
+ end
111
+
112
+ # @rbs () -> Integer?
113
+ def rule_marker_index
114
+ @tokens.index { |token| token.type == :identifier && token.value == "rule" }
115
+ end
116
+
117
+ # @rbs (Integer failure, Integer rule_marker) -> Range[Integer]?
118
+ def declaration_range(failure, rule_marker)
119
+ starts = (0...rule_marker).select { |index| declaration_start?(index) }
120
+ start = starts.reverse.find { |index| index <= failure }
121
+ return unless start
122
+
123
+ finish = declaration_finish(start, rule_marker, starts)
124
+ start...finish
125
+ end
126
+
127
+ # @rbs (Integer index) -> bool
128
+ def declaration_start?(index)
129
+ token = @tokens[index]
130
+ token&.type == :identifier && DECLARATION_STARTS.include?(token.value)
131
+ end
132
+
133
+ # @rbs (Integer start, Integer rule_marker, Array[Integer] starts) -> Integer
134
+ def declaration_finish(start, rule_marker, starts)
135
+ value = @tokens.fetch(start).value
136
+ return matching_declaration_end(start, rule_marker, value == "prechigh" ? "preclow" : "prechigh") if
137
+ %w[prechigh preclow].include?(value)
138
+ return matching_declaration_end(start, rule_marker, "end") if %w[convert lexer].include?(value)
139
+
140
+ starts.find { |index| index > start } || rule_marker
141
+ end
142
+
143
+ # @rbs (Integer start, Integer fallback, String closer) -> Integer
144
+ def matching_declaration_end(start, fallback, closer)
145
+ index = ((start + 1)...fallback).find { |candidate| @tokens[candidate]&.value == closer }
146
+ index ? index + 1 : fallback
147
+ end
148
+
149
+ # @rbs (Integer failure, Integer rule_marker) -> Range[Integer]?
150
+ def rule_range(failure, rule_marker)
151
+ grammar_end = grammar_end_index(rule_marker)
152
+ definitions = rule_definition_starts(rule_marker, grammar_end)
153
+ start = definitions.reverse.find { |index| index <= failure }
154
+ return unless start
155
+
156
+ finish = definitions.find { |index| index > start } || grammar_end
157
+ alternative_range(failure, start, finish) || (start...finish)
158
+ end
159
+
160
+ # @rbs (Integer rule_marker) -> Integer
161
+ def grammar_end_index(rule_marker)
162
+ depth = 0
163
+ ((rule_marker + 1)...@tokens.length).each do |index|
164
+ token = @tokens.fetch(index)
165
+ depth += 1 if token.type == :"("
166
+ depth -= 1 if token.type == :")" && depth.positive?
167
+ return index if depth.zero? && token.type == :identifier && token.value == "end"
168
+ end
169
+ @tokens.length - 1
170
+ end
171
+
172
+ # @rbs (Integer rule_marker, Integer grammar_end) -> Array[Integer]
173
+ def rule_definition_starts(rule_marker, grammar_end)
174
+ starts = [] #: Array[Integer]
175
+ depth = 0
176
+ lhs_column = nil #: Integer?
177
+ ((rule_marker + 1)...grammar_end).each do |index|
178
+ token = @tokens.fetch(index)
179
+ depth += 1 if token.type == :"("
180
+ depth -= 1 if token.type == :")" && depth.positive?
181
+ next unless depth.zero? && lhs_candidate?(index, lhs_column)
182
+
183
+ lhs_column ||= token.location.column
184
+ starts << index
185
+ end
186
+ starts
187
+ end
188
+
189
+ # @rbs (Integer index, Integer? lhs_column) -> bool
190
+ def lhs_candidate?(index, lhs_column)
191
+ token = @tokens[index]
192
+ following = @tokens[index + 1]
193
+ return false unless token&.type == :identifier && following&.type == :":"
194
+
195
+ lhs_column.nil? || token.location.column <= lhs_column
196
+ end
197
+
198
+ # @rbs (Integer failure, Integer start, Integer finish) -> Range[Integer]?
199
+ def alternative_range(failure, start, finish)
200
+ colon = ((start + 1)...finish).find { |index| @tokens[index]&.type == :":" }
201
+ return unless colon
202
+
203
+ pipes = top_level_pipes(colon + 1, finish)
204
+ return if pipes.empty?
205
+
206
+ previous = pipes.reverse.find { |index| index < failure }
207
+ following = pipes.find { |index| index >= failure }
208
+ alternative_slice(previous, following, colon, finish)
209
+ end
210
+
211
+ # @rbs (Integer? previous, Integer? following, Integer colon, Integer finish) -> Range[Integer]?
212
+ def alternative_slice(previous, following, colon, finish)
213
+ if previous
214
+ following ? (previous...following) : (previous...finish)
215
+ elsif following
216
+ (colon + 1)..following
217
+ end
218
+ end
219
+
220
+ # @rbs (Integer start, Integer finish) -> Array[Integer]
221
+ def top_level_pipes(start, finish)
222
+ depth = 0
223
+ (start...finish).filter_map do |index|
224
+ token = @tokens.fetch(index)
225
+ depth += 1 if token.type == :"("
226
+ depth -= 1 if token.type == :")" && depth.positive?
227
+ index if depth.zero? && token.type == :|
228
+ end
229
+ end
230
+
231
+ # @rbs (Range[Integer] range) -> bool
232
+ def suppress(range)
233
+ changed = false
234
+ range.each do |index|
235
+ next if index.negative? || index >= @tokens.length || @tokens[index]&.type == :eof
236
+ next if @suppressed[index]
237
+
238
+ @suppressed[index] = true
239
+ changed = true
240
+ end
241
+ changed
242
+ end
243
+
244
+ # @rbs (Exception error, Token? token, phase: Symbol) -> Diagnostic
245
+ def diagnostic_from(error, token, phase:)
246
+ matching = @tokens.find { |candidate| error.message.start_with?("#{candidate.location}:") }
247
+ token = matching || token || @tokens.last
248
+ location = token&.location || Location.new(file: "(grammar)", line: 1, column: 1)
249
+ prefix = "#{location}: "
250
+ message = error.message.delete_prefix(prefix)
251
+ expected, received = expected_and_received(message)
252
+ Diagnostic.new(code: "frontend.#{phase}_error", phase: phase, message: message,
253
+ location: location, span: token&.span, expected: expected,
254
+ received: received, rendered: error.message)
255
+ end
256
+
257
+ # @rbs (String message) -> [Array[String], String?]
258
+ def expected_and_received(message)
259
+ match = message.match(/\Aexpected (.+), got (.+)\z/)
260
+ return [[], nil] unless match
261
+
262
+ expected = match[1]
263
+ received = match[2]
264
+ [expected ? [expected] : [], received]
265
+ end
266
+ end
267
+ end
268
+ end