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,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module IR
5
+ LEXER_SCHEMA_VERSION = 1
6
+ SUPPORTED_LEXER_SCHEMA_VERSIONS = [LEXER_SCHEMA_VERSION].freeze #: Array[Integer]
7
+
8
+ # One normalized, state-scoped lexer rule.
9
+ class LexerRule
10
+ attr_reader :id #: Integer
11
+ attr_reader :state #: String
12
+ attr_reader :kind #: Symbol
13
+ attr_reader :token #: String?
14
+ attr_reader :pattern #: String
15
+ attr_reader :pattern_kind #: Symbol
16
+ attr_reader :options #: String
17
+ attr_reader :action #: String?
18
+ attr_reader :location #: location
19
+
20
+ # @rbs (id: Integer, state: String, kind: Symbol, token: String?, pattern: String, pattern_kind: Symbol,
21
+ # options: String, action: String?, location: location) -> void
22
+ def initialize(id:, state:, kind:, token:, pattern:, pattern_kind:, options:, action:, location:)
23
+ @id = id
24
+ @state = state.freeze
25
+ @kind = kind
26
+ @token = token&.freeze
27
+ @pattern = pattern.freeze
28
+ @pattern_kind = pattern_kind
29
+ @options = options.freeze
30
+ @action = action&.freeze
31
+ @location = IR.deep_freeze(location)
32
+ freeze
33
+ end
34
+
35
+ # @rbs () -> Hash[Symbol, lexer_rule_document_value]
36
+ def to_h
37
+ {
38
+ id: @id, state: @state, kind: @kind, token: @token, pattern: @pattern,
39
+ pattern_kind: @pattern_kind, options: @options, action: @action, loc: @location
40
+ }
41
+ end
42
+ end
43
+
44
+ # Independently versioned lexer contract embedded by the current Grammar IR.
45
+ class Lexer
46
+ attr_reader :states #: Array[String]
47
+ attr_reader :rules #: Array[LexerRule]
48
+ attr_reader :warnings #: Array[lexer_warning]
49
+ attr_reader :schema_version #: Integer
50
+ attr_reader :source_provenance #: source_provenance?
51
+
52
+ # @rbs (states: Array[String], rules: Array[LexerRule], warnings: Array[lexer_warning],
53
+ # ?schema_version: Integer, ?source_provenance: source_provenance?) -> void
54
+ def initialize(states:, rules:, warnings:, schema_version: LEXER_SCHEMA_VERSION, source_provenance: nil)
55
+ raise ArgumentError, "lexer states must start with INITIAL" unless states.first == "INITIAL"
56
+ raise ArgumentError, "lexer states must be unique" unless states.uniq.length == states.length
57
+
58
+ @states = states.map(&:freeze).freeze
59
+ @rules = rules.freeze
60
+ @warnings = IR.deep_freeze(warnings)
61
+ @schema_version = schema_version
62
+ @source_provenance = IR.deep_freeze(source_provenance)
63
+ freeze
64
+ end
65
+
66
+ # @rbs () -> Hash[Symbol, lexer_document_value]
67
+ def to_h
68
+ {
69
+ ibex_ir: "lexer", schema_version: @schema_version, initial_state: "INITIAL",
70
+ states: @states, rules: @rules.map(&:to_h), warnings: @warnings,
71
+ source_provenance: @source_provenance
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "../location"
5
+
6
+ module Ibex
7
+ module IR
8
+ # Root-owned parser configuration persisted by the current Grammar IR.
9
+ class ParserContract
10
+ # @rbs!
11
+ # type definition = { configuration: String, values: Array[Symbol] }
12
+ # type entry_location = { file: String?, line: Integer, column: Integer }
13
+ # type entry_value = String? | bool | entry_location?
14
+
15
+ DEFINITIONS = {
16
+ algorithm: {
17
+ configuration: "parser.algorithm", values: %i[slr lalr ielr lr1].freeze
18
+ }.freeze,
19
+ entries: {
20
+ configuration: "parser.entries", values: %i[shared isolated].freeze
21
+ }.freeze,
22
+ cst_trivia: {
23
+ configuration: "cst.trivia", values: %i[leading balanced drop].freeze
24
+ }.freeze
25
+ }.freeze #: Hash[Symbol, definition]
26
+
27
+ # One specified or explicitly unspecified contract field.
28
+ class Entry
29
+ attr_reader :key #: Symbol
30
+ attr_reader :value #: Symbol?
31
+ attr_reader :location #: Location?
32
+ attr_reader :explicit #: bool
33
+
34
+ # @rbs (Symbol key, ?value: Symbol?, ?location: Location?, ?explicit: bool) -> void
35
+ def initialize(key, value: nil, location: nil, explicit: false)
36
+ definition = DEFINITIONS.fetch(key) { raise ArgumentError, "unknown parser contract key #{key.inspect}" }
37
+ validate_state!(key, definition.fetch(:values), value, location, explicit)
38
+
39
+ @key = key
40
+ @value = value
41
+ @location = location
42
+ @explicit = explicit
43
+ freeze
44
+ end
45
+
46
+ # @rbs () -> Hash[Symbol, entry_value]
47
+ def to_h
48
+ { value: @value&.to_s, explicit: @explicit, loc: serialized_location }
49
+ end
50
+
51
+ private
52
+
53
+ # @rbs (Symbol key, Array[Symbol] allowed, Symbol? value, Location? location, bool explicit) -> void
54
+ def validate_state!(key, allowed, value, location, explicit)
55
+ raise ArgumentError, "explicit must be boolean" unless [true, false].include?(explicit)
56
+
57
+ if explicit
58
+ raise ArgumentError, "#{key} must be one of #{allowed.join(', ')}" unless allowed.include?(value)
59
+ unless location.is_a?(Location) && location.file && !location.file.empty?
60
+ raise ArgumentError, "explicit #{key} requires a source location with a file"
61
+ end
62
+
63
+ return
64
+ end
65
+
66
+ raise ArgumentError, "unspecified #{key} cannot carry a value" unless value.nil?
67
+ raise ArgumentError, "unspecified #{key} cannot carry a source location" unless location.nil?
68
+ end
69
+
70
+ # @rbs () -> entry_location?
71
+ def serialized_location
72
+ location = @location
73
+ return unless location
74
+
75
+ { file: location.file, line: location.line, column: location.column }
76
+ end
77
+ end
78
+
79
+ attr_reader :algorithm #: Entry
80
+ attr_reader :entries #: Entry
81
+ attr_reader :cst_trivia #: Entry
82
+
83
+ # @rbs (?algorithm: Entry?, ?entries: Entry?, ?cst_trivia: Entry?) -> void
84
+ def initialize(algorithm: nil, entries: nil, cst_trivia: nil)
85
+ @algorithm = normalize_entry(:algorithm, algorithm)
86
+ @entries = normalize_entry(:entries, entries)
87
+ @cst_trivia = normalize_entry(:cst_trivia, cst_trivia)
88
+ freeze
89
+ end
90
+
91
+ # @rbs () -> Hash[Symbol, Hash[Symbol, entry_value]]
92
+ def to_h
93
+ {
94
+ algorithm: @algorithm.to_h,
95
+ entries: @entries.to_h,
96
+ cst_trivia: @cst_trivia.to_h
97
+ }
98
+ end
99
+
100
+ # Values supplied to the typed resolver; unspecified fields are absent.
101
+ # @rbs () -> Hash[String, Symbol]
102
+ def configuration_values
103
+ specified_entries.to_h do |entry|
104
+ value = entry.value || raise("explicit parser contract entry is missing its value")
105
+ [DEFINITIONS.fetch(entry.key).fetch(:configuration), value]
106
+ end
107
+ end
108
+
109
+ # Source locations supplied to the typed resolver.
110
+ # @rbs () -> Hash[String, Location]
111
+ def configuration_locations
112
+ specified_entries.to_h do |entry|
113
+ location = entry.location || raise("explicit parser contract entry is missing its location")
114
+ [DEFINITIONS.fetch(entry.key).fetch(:configuration), location]
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ # @rbs (Symbol key, Entry? entry) -> Entry
121
+ def normalize_entry(key, entry)
122
+ entry ||= Entry.new(key)
123
+ raise ArgumentError, "#{key} must be a ParserContract::Entry" unless entry.is_a?(Entry)
124
+ raise ArgumentError, "#{key} entry has key #{entry.key.inspect}" unless entry.key == key
125
+
126
+ entry
127
+ end
128
+
129
+ # @rbs () -> Array[Entry]
130
+ def specified_entries
131
+ [@algorithm, @entries, @cst_trivia].select(&:explicit)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -4,38 +4,83 @@ require "json"
4
4
 
5
5
  module Ibex
6
6
  module IR
7
- # Stable JSON serialization for versioned pipeline IR.
7
+ # Stable JSON serialization for the current pipeline IR.
8
+ # rubocop:disable Metrics/ModuleLength -- explicit fields keep serialization changes auditable.
9
+ # rubocop:disable Lint/SelfAssignment -- RBS inline assertions narrow schema-decoded values in place.
8
10
  module Serialize
9
11
  # @rbs!
10
- # private def validate_version: (untyped data) -> untyped
11
- # private def self.validate_version: (untyped data) -> untyped
12
- # private def load_grammar: (untyped data) -> untyped
13
- # private def self.load_grammar: (untyped data) -> untyped
14
- # private def load_automaton: (untyped data) -> untyped
15
- # private def self.load_automaton: (untyped data) -> untyped
16
- # private def load_state: (untyped state, untyped grammar) -> untyped
17
- # private def self.load_state: (untyped state, untyped grammar) -> untyped
18
- # private def symbol_keyed: (untyped values, untyped grammar, ?actions: untyped) -> untyped
19
- # private def self.symbol_keyed: (untyped values, untyped grammar, ?actions: untyped) -> untyped
20
- # private def normalize_action: (untyped value) -> untyped
21
- # private def self.normalize_action: (untyped value) -> untyped
22
- # private def load_production: (untyped production) -> untyped
23
- # private def self.load_production: (untyped production) -> untyped
24
- # private def load_user_code_chunks: (untyped chunks) -> untyped
25
- # private def self.load_user_code_chunks: (untyped chunks) -> untyped
26
- # private def symbolize: (untyped value) -> untyped
27
- # private def self.symbolize: (untyped value) -> untyped
28
-
29
- # @rbs (Grammar | Automaton value) -> String
12
+ # private def validate_version: (Hash[String, IR::serialized_value] data) -> void
13
+ # private def self.validate_version: (Hash[String, IR::serialized_value] data) -> void
14
+ # private def load_grammar: (Hash[String, IR::serialized_value] data) -> Grammar
15
+ # private def self.load_grammar: (Hash[String, IR::serialized_value] data) -> Grammar
16
+ # private def load_symbols: (Hash[String, IR::serialized_value] data) -> Array[GrammarSymbol]
17
+ # private def self.load_symbols: (Hash[String, IR::serialized_value] data) -> Array[GrammarSymbol]
18
+ # private def load_productions: (Hash[String, IR::serialized_value] data) -> Array[Production]
19
+ # private def self.load_productions: (Hash[String, IR::serialized_value] data) -> Array[Production]
20
+ # private def empty_chunks: () -> Hash[String, IR::serialized_value]
21
+ # private def self.empty_chunks: () -> Hash[String, IR::serialized_value]
22
+ # private def empty_parameters: () -> Array[IR::serialized_value]
23
+ # private def self.empty_parameters: () -> Array[IR::serialized_value]
24
+ # private def empty_printers: () -> Array[IR::serialized_value]
25
+ # private def self.empty_printers: () -> Array[IR::serialized_value]
26
+ # private def empty_tests: () -> Array[IR::serialized_value]
27
+ # private def self.empty_tests: () -> Array[IR::serialized_value]
28
+ # private def empty_recovery: () -> Hash[String, IR::serialized_value]
29
+ # private def self.empty_recovery: () -> Hash[String, IR::serialized_value]
30
+ # private def load_automaton: (Hash[String, IR::serialized_value] data) -> Automaton
31
+ # private def self.load_automaton: (Hash[String, IR::serialized_value] data) -> Automaton
32
+ # private def load_lexer: (Hash[String, IR::serialized_value] data) -> Lexer
33
+ # private def self.load_lexer: (Hash[String, IR::serialized_value] data) -> Lexer
34
+ # private def load_state: (Hash[String, IR::serialized_value] state, Grammar grammar) -> AutomatonState
35
+ # private def self.load_state: (Hash[String, IR::serialized_value] state, Grammar grammar) -> AutomatonState
36
+ # private def symbol_keyed: (Hash[String, IR::serialized_value] values, Grammar grammar,
37
+ # ?actions: bool) -> Hash[Integer, IR::serialized_value]
38
+ # private def self.symbol_keyed: (Hash[String, IR::serialized_value] values, Grammar grammar,
39
+ # ?actions: bool) -> Hash[Integer, IR::serialized_value]
40
+ # private def normalize_action: (Hash[String, IR::serialized_value] value) -> parser_action?
41
+ # private def self.normalize_action: (Hash[String, IR::serialized_value] value) -> parser_action?
42
+ # private def load_production: (Hash[String, IR::serialized_value] production) -> Production
43
+ # private def self.load_production: (Hash[String, IR::serialized_value] production) -> Production
44
+ # private def load_user_code_chunks: (Hash[String,
45
+ # Array[Hash[String, IR::serialized_value]]] chunks) -> user_code_chunks
46
+ # private def self.load_user_code_chunks: (Hash[String,
47
+ # Array[Hash[String, IR::serialized_value]]] chunks) -> user_code_chunks
48
+ # private def load_symbol_metadata: (Hash[String, IR::serialized_value] symbol, String field) -> String?
49
+ # private def self.load_symbol_metadata: (Hash[String, IR::serialized_value] symbol, String field) -> String?
50
+ # private def load_grammar_tests: (Array[Hash[String, IR::serialized_value]] tests) -> Array[grammar_test]
51
+ # private def self.load_grammar_tests: (Array[Hash[String, IR::serialized_value]] tests) -> Array[grammar_test]
52
+ # private def symbol_source_position: (Hash[String, IR::serialized_value] symbol) -> String
53
+ # private def self.symbol_source_position: (Hash[String, IR::serialized_value] symbol) -> String
54
+ # private def load_parser_contract: (IR::serialized_value value) -> IR::serialized_value
55
+ # private def self.load_parser_contract: (IR::serialized_value value) -> IR::serialized_value
56
+ # private def symbolize: (IR::serialized_value value) -> IR::serialized_value
57
+ # private def self.symbolize: (IR::serialized_value value) -> IR::serialized_value
58
+
59
+ # @rbs (Grammar | Automaton | Lexer value) -> String
30
60
  def dump(value)
31
- "#{JSON.pretty_generate(value.to_h)}\n"
61
+ normalize = lambda do |entry|
62
+ case entry
63
+ when String
64
+ normalized = entry.dup.force_encoding(Encoding::UTF_8)
65
+ normalized.valid_encoding? ? normalized : normalized.scrub
66
+ when Array
67
+ entry.map { |child| normalize.call(child) }
68
+ when Hash
69
+ entry.to_h { |key, child| [normalize.call(key), normalize.call(child)] }
70
+ else
71
+ entry
72
+ end
73
+ end
74
+ "#{JSON.pretty_generate(normalize.call(value.to_h))}\n"
32
75
  end
33
76
  module_function :dump
34
77
 
35
- # @rbs (String source) -> (Grammar | Automaton)
78
+ # @rbs (String source) -> (Grammar | Automaton | Lexer)
36
79
  def load(source)
37
- data = JSON.parse(source)
38
- type = data.fetch("ibex_ir") { raise Ibex::Error, "(ir):1:1: missing ibex_ir discriminator" }
80
+ data = JSON.parse(source) #: Hash[String, IR::serialized_value]
81
+ type = data.fetch("ibex_ir") #: String
82
+ return load_lexer(data) if type == "lexer"
83
+
39
84
  validate_version(data)
40
85
  return load_grammar(data) if type == "grammar"
41
86
  return load_automaton(data) if type == "automaton"
@@ -46,45 +91,140 @@ module Ibex
46
91
  end
47
92
  module_function :load
48
93
 
49
- # @rbs skip
50
94
  private
51
95
 
52
96
  # @rbs skip
53
97
  def validate_version(data)
54
98
  version = data["schema_version"]
55
- return if version == SCHEMA_VERSION
99
+ return if SUPPORTED_SCHEMA_VERSIONS.include?(version)
56
100
 
57
- raise Ibex::Error, "(ir):1:1: unsupported schema_version #{version.inspect}; expected #{SCHEMA_VERSION}"
101
+ expected = SUPPORTED_SCHEMA_VERSIONS.join(", ")
102
+ raise Ibex::Error,
103
+ "(ir):1:1: unsupported schema_version #{version.inspect}; expected the current format (#{expected})"
58
104
  end
59
105
 
106
+ # rubocop:disable Metrics/AbcSize -- explicit current Grammar IR field mapping is the loader contract.
60
107
  # @rbs skip
61
108
  def load_grammar(data)
62
- empty_chunks = {} #: Hash[String, untyped]
63
- symbols = data.fetch("symbols").map do |symbol|
109
+ data = data #: Hash[String, IR::serialized_value]
110
+ data.fetch("schema_version") #: Integer
111
+ Grammar.new(
112
+ class_name: data.fetch("class_name"), superclass: data["superclass"], start: data.fetch("start"),
113
+ expect: data.fetch("expect"), options: symbolize(data.fetch("options")), symbols: load_symbols(data),
114
+ mode: (data["mode"] || "default").to_sym, starts: data["starts"], expect_rr: data["expect_rr"],
115
+ parser_parameters: symbolize(data.fetch("params", empty_parameters)),
116
+ value_printers: symbolize(data.fetch("printers", empty_printers)),
117
+ grammar_tests: load_grammar_tests(data.fetch("tests", empty_tests)),
118
+ lexer: data["lexer"] && load_lexer(data.fetch("lexer")),
119
+ recovery: symbolize(data.fetch("recovery", empty_recovery)),
120
+ productions: load_productions(data),
121
+ user_code: data.fetch("user_code"), conversions: data.fetch("conversions"),
122
+ warnings: symbolize(data.fetch("warnings")),
123
+ user_code_chunks: load_user_code_chunks(data.fetch("user_code_chunks", empty_chunks)),
124
+ source_provenance: symbolize(data["source_provenance"]),
125
+ parser_contract: load_parser_contract(data.fetch("parser_contract"))
126
+ )
127
+ end
128
+ # rubocop:enable Metrics/AbcSize
129
+
130
+ # @rbs skip
131
+ def load_symbols(data)
132
+ symbols_data = data.fetch("symbols") #: Array[Hash[String, IR::serialized_value]]
133
+ symbols_data.map do |symbol|
64
134
  GrammarSymbol.new(id: symbol.fetch("id"), name: symbol.fetch("name"), kind: symbol.fetch("kind"),
65
135
  reserved: symbol.fetch("reserved"), precedence: symbolize(symbol["prec"]),
66
- location: symbolize(symbol["loc"]))
136
+ location: symbolize(symbol["loc"]),
137
+ display_name: load_symbol_metadata(symbol, "display_name"),
138
+ semantic_type: load_symbol_metadata(symbol, "semantic_type"),
139
+ documentation: symbol["doc"])
67
140
  end
68
- productions = data.fetch("productions").map { |production| load_production(production) }
69
- Grammar.new(class_name: data.fetch("class_name"), superclass: data["superclass"], start: data.fetch("start"),
70
- expect: data.fetch("expect"), options: symbolize(data.fetch("options")), symbols: symbols,
71
- productions: productions, user_code: data.fetch("user_code"),
72
- conversions: data.fetch("conversions"), warnings: symbolize(data.fetch("warnings")),
73
- user_code_chunks: load_user_code_chunks(data.fetch("user_code_chunks", empty_chunks)))
141
+ end
142
+
143
+ # @rbs skip
144
+ def load_productions(data)
145
+ productions_data = data.fetch("productions") #: Array[Hash[String, IR::serialized_value]]
146
+ productions_data.map { |production| load_production(production) }
147
+ end
148
+
149
+ # @rbs skip
150
+ def empty_chunks
151
+ value = {} #: Hash[String, IR::serialized_value]
152
+ value.freeze
153
+ end
154
+
155
+ # @rbs skip
156
+ def empty_parameters
157
+ value = [] #: Array[IR::serialized_value]
158
+ value.freeze
159
+ end
160
+
161
+ # @rbs skip
162
+ def empty_printers
163
+ value = [] #: Array[IR::serialized_value]
164
+ value.freeze
165
+ end
166
+
167
+ # @rbs skip
168
+ def empty_tests
169
+ value = [] #: Array[IR::serialized_value]
170
+ value.freeze
171
+ end
172
+
173
+ # @rbs skip
174
+ def empty_recovery
175
+ value = { "sync_tokens" => [], "on_error_reduce" => [] } #: Hash[String, IR::serialized_value]
176
+ value.freeze
74
177
  end
75
178
 
76
179
  # @rbs skip
77
180
  def load_automaton(data)
78
- grammar = load_grammar(data.fetch("grammar"))
79
- states = data.fetch("states").map { |state| load_state(state, grammar) }
80
- Automaton.new(grammar: grammar, states: states, conflict_summary: symbolize(data.fetch("conflict_summary")),
81
- algorithm: data.fetch("algorithm"), grammar_digest: data.fetch("grammar_digest"))
181
+ data = data #: Hash[String, IR::serialized_value]
182
+ grammar_data = data.fetch("grammar") #: Hash[String, IR::serialized_value]
183
+ grammar = load_grammar(grammar_data)
184
+ states_data = data.fetch("states") #: Array[Hash[String, IR::serialized_value]]
185
+ states = states_data.map { |state| load_state(state, grammar) }
186
+ data.fetch("schema_version") #: Integer
187
+ Automaton.new(
188
+ grammar: grammar, states: states, conflict_summary: symbolize(data.fetch("conflict_summary")),
189
+ algorithm: data.fetch("algorithm"), grammar_digest: data.fetch("grammar_digest"),
190
+ entry_states: data["entry_states"], entry_construction: data.fetch("entry_construction")
191
+ )
192
+ end
193
+
194
+ # @rbs skip
195
+ def load_lexer(data)
196
+ data = data #: Hash[String, IR::serialized_value]
197
+ version = data.fetch("schema_version") #: Integer
198
+ unless SUPPORTED_LEXER_SCHEMA_VERSIONS.include?(version)
199
+ expected = SUPPORTED_LEXER_SCHEMA_VERSIONS.join(", ")
200
+ raise Ibex::Error,
201
+ "(ir):1:1: unsupported lexer schema_version #{version.inspect}; " \
202
+ "expected the current lexer format (#{expected})"
203
+ end
204
+ rules_data = data.fetch("rules") #: Array[Hash[String, IR::serialized_value]]
205
+ rules = rules_data.map do |rule|
206
+ LexerRule.new(
207
+ id: rule.fetch("id"), state: rule.fetch("state"), kind: rule.fetch("kind").to_sym,
208
+ token: rule["token"], pattern: rule.fetch("pattern"), pattern_kind: rule.fetch("pattern_kind").to_sym,
209
+ options: rule.fetch("options"), action: rule["action"], location: symbolize(rule.fetch("loc"))
210
+ )
211
+ end
212
+ Lexer.new(
213
+ states: data.fetch("states"), rules: rules, warnings: symbolize(data.fetch("warnings")),
214
+ schema_version: version, source_provenance: symbolize(data["source_provenance"])
215
+ )
82
216
  end
83
217
 
84
218
  # @rbs skip
85
219
  def load_state(state, grammar)
86
- items = state.fetch("items").map do |item|
87
- lookaheads = item.fetch("lookaheads").map { |name| grammar.symbol(name).id }
220
+ state = state #: Hash[String, IR::serialized_value]
221
+ items_data = state.fetch("items") #: Array[Hash[String, IR::serialized_value]]
222
+ items = items_data.map do |item|
223
+ lookahead_names = item.fetch("lookaheads") #: Array[String]
224
+ lookaheads = lookahead_names.map do |name|
225
+ symbol = grammar.symbol(name) || raise(Ibex::Error, "(ir):1:1: unknown symbol #{name.inspect}")
226
+ symbol.id
227
+ end
88
228
  AutomatonItem.new(production: item.fetch("production"), dot: item.fetch("dot"), lookaheads: lookaheads)
89
229
  end
90
230
  AutomatonState.new(id: state.fetch("id"), items: items,
@@ -97,13 +237,16 @@ module Ibex
97
237
 
98
238
  # @rbs skip
99
239
  def symbol_keyed(values, grammar, actions: false)
240
+ values = values #: Hash[String, IR::serialized_value]
100
241
  values.to_h do |name, value|
101
- [grammar.symbol(name).id, actions ? normalize_action(value) : value]
242
+ symbol = grammar.symbol(name) || raise(Ibex::Error, "(ir):1:1: unknown symbol #{name.inspect}")
243
+ [symbol.id, actions ? normalize_action(value) : value]
102
244
  end
103
245
  end
104
246
 
105
247
  # @rbs skip
106
248
  def normalize_action(value)
249
+ value = value #: IR::serialized_value
107
250
  return nil unless value
108
251
 
109
252
  action = symbolize(value)
@@ -113,19 +256,24 @@ module Ibex
113
256
 
114
257
  # @rbs skip
115
258
  def load_production(production)
259
+ production = production #: Hash[String, IR::serialized_value]
116
260
  action_data = production["action"]
261
+ action_data = action_data #: Hash[String, IR::serialized_value] if action_data
117
262
  action = if action_data
118
263
  Action.new(code: action_data.fetch("code"), location: symbolize(action_data["loc"]),
119
264
  named_refs: symbolize(action_data.fetch("named_refs")),
120
- context_length: action_data.fetch("context_length"))
265
+ context_length: action_data.fetch("context_length"),
266
+ composition: symbolize(action_data["composition"]))
121
267
  end
122
268
  Production.new(id: production.fetch("id"), lhs: production.fetch("lhs"), rhs: production.fetch("rhs"),
123
269
  action: action, precedence_override: production["prec_override"],
124
- origin: symbolize(production.fetch("origin")))
270
+ origin: symbolize(production.fetch("origin")), documentation: production["doc"],
271
+ expansion: symbolize(production["expansion"]), node: symbolize(production["node"]))
125
272
  end
126
273
 
127
274
  # @rbs skip
128
275
  def load_user_code_chunks(chunks)
276
+ chunks = chunks #: Hash[String, Array[Hash[String, IR::serialized_value]]]
129
277
  chunks.to_h do |name, values|
130
278
  loaded = values.map do |value|
131
279
  UserCodeChunk.new(code: value.fetch("code"), location: symbolize(value.fetch("loc")))
@@ -134,21 +282,91 @@ module Ibex
134
282
  end
135
283
  end
136
284
 
285
+ # @rbs skip
286
+ def load_symbol_metadata(symbol, field)
287
+ symbol = symbol #: Hash[String, IR::serialized_value]
288
+ value = symbol[field]
289
+ return nil if value.nil?
290
+
291
+ position = symbol_source_position(symbol)
292
+ raise Ibex::Error, "#{position}: #{field} must be a String or null" unless value.is_a?(String)
293
+ raise Ibex::Error, "#{position}: #{field} must not be empty" if value.strip.empty?
294
+ raise Ibex::Error, "#{position}: #{field} must be a single line" if value.match?(/[\r\n]/)
295
+ raise Ibex::Error, "#{position}: #{field} must not contain control characters" if
296
+ value.match?(/[[:cntrl:]]/)
297
+
298
+ value
299
+ end
300
+
301
+ # @rbs skip
302
+ def symbol_source_position(symbol)
303
+ location = symbol["loc"]
304
+ return "(ir):1:1" unless location.is_a?(Hash)
305
+
306
+ file = location["file"]
307
+ line = location["line"]
308
+ column = location["column"]
309
+ return "(ir):1:1" unless file.is_a?(String) && line.is_a?(Integer) && column.is_a?(Integer)
310
+
311
+ "#{file}:#{line}:#{column}"
312
+ end
313
+
314
+ # @rbs skip
315
+ def load_grammar_tests(tests)
316
+ tests = tests #: Array[IR::serialized_value]
317
+ symbolize(tests).map { |test| test.merge(expectation: test.fetch(:expectation).to_sym) }
318
+ end
319
+
320
+ # @rbs skip
321
+ def load_parser_contract(value)
322
+ value = value #: Hash[String, IR::serialized_value]
323
+
324
+ entries = ParserContract::DEFINITIONS.keys.to_h do |key|
325
+ entry = value.fetch(key.to_s)
326
+ location = entry["loc"]
327
+ loaded_location = if location
328
+ Location.new(
329
+ file: location.fetch("file"), line: location.fetch("line"),
330
+ column: location.fetch("column")
331
+ )
332
+ end
333
+ [
334
+ key,
335
+ ParserContract::Entry.new(
336
+ key, value: entry["value"]&.to_sym, explicit: entry.fetch("explicit"), location: loaded_location
337
+ )
338
+ ]
339
+ end
340
+ ParserContract.new(**entries)
341
+ end
342
+
343
+ # Parsed IR values are recursively heterogeneous until schema validation narrows them.
137
344
  # @rbs skip
138
345
  def symbolize(value)
346
+ value = value #: IR::serialized_value
139
347
  case value
140
348
  when Array then value.map { |item| symbolize(item) }
141
349
  when Hash then value.to_h { |key, item| [key.to_sym, symbolize(item)] }
142
350
  else value
143
351
  end
144
352
  end
145
- module_function :validate_version, :load_grammar, :load_automaton, :load_state, :symbol_keyed,
146
- :normalize_action, :load_production, :load_user_code_chunks, :symbolize
353
+ module_function :validate_version, :load_grammar, :load_symbols, :load_productions,
354
+ :empty_chunks, :empty_parameters, :empty_printers, :empty_tests, :empty_recovery,
355
+ :load_automaton, :load_lexer, :load_state, :symbol_keyed,
356
+ :normalize_action, :load_production, :load_user_code_chunks, :load_symbol_metadata,
357
+ :symbol_source_position, :load_grammar_tests,
358
+ :load_parser_contract, :symbolize
147
359
 
148
360
  class << self
149
- private :validate_version, :load_grammar, :load_automaton, :load_state, :symbol_keyed,
150
- :normalize_action, :load_production, :load_user_code_chunks, :symbolize
361
+ private :validate_version, :load_grammar, :load_symbols, :load_productions,
362
+ :empty_chunks, :empty_parameters, :empty_printers, :empty_tests, :empty_recovery,
363
+ :load_automaton, :load_lexer, :load_state, :symbol_keyed,
364
+ :normalize_action, :load_production, :load_user_code_chunks, :load_symbol_metadata,
365
+ :symbol_source_position, :load_grammar_tests,
366
+ :load_parser_contract, :symbolize
151
367
  end
152
368
  end
369
+ # rubocop:enable Lint/SelfAssignment
370
+ # rubocop:enable Metrics/ModuleLength
153
371
  end
154
372
  end