ibex 0.2.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 (437) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +95 -272
  3. data/docs/architecture.md +187 -35
  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 +3 -4
  12. data/docs/cst.md +24 -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 +179 -2
  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 +2 -1
  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 +54 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +184 -13
  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 +5 -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 +11 -0
  63. data/docs/release-readiness.md +126 -68
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +144 -34
  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/lib/ibex/analysis/digraph.rb +128 -0
  75. data/lib/ibex/analysis.rb +1 -0
  76. data/lib/ibex/bison_import/importer.rb +516 -0
  77. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  78. data/lib/ibex/bison_import.rb +200 -0
  79. data/lib/ibex/bounded_subprocess.rb +171 -0
  80. data/lib/ibex/cli/ambiguity.rb +14 -5
  81. data/lib/ibex/cli/analysis.rb +134 -0
  82. data/lib/ibex/cli/bison_import.rb +121 -0
  83. data/lib/ibex/cli/config.rb +128 -0
  84. data/lib/ibex/cli/diagnostics.rb +31 -11
  85. data/lib/ibex/cli/documentation.rb +11 -8
  86. data/lib/ibex/cli/equiv.rb +169 -0
  87. data/lib/ibex/cli/error_messages.rb +11 -4
  88. data/lib/ibex/cli/explain.rb +14 -5
  89. data/lib/ibex/cli/fix.rb +203 -0
  90. data/lib/ibex/cli/formatting.rb +11 -10
  91. data/lib/ibex/cli/fuzz.rb +200 -0
  92. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  93. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  94. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  95. data/lib/ibex/cli/grammar_tests.rb +32 -14
  96. data/lib/ibex/cli/ir_tools.rb +5 -61
  97. data/lib/ibex/cli/outputs.rb +60 -33
  98. data/lib/ibex/cli/reduce.rb +202 -0
  99. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  100. data/lib/ibex/cli/samples.rb +49 -23
  101. data/lib/ibex/cli/verify.rb +116 -0
  102. data/lib/ibex/cli/watch.rb +6 -5
  103. data/lib/ibex/cli.rb +357 -56
  104. data/lib/ibex/codegen/action_locations.rb +1 -1
  105. data/lib/ibex/codegen/action_method_source.rb +5 -6
  106. data/lib/ibex/codegen/action_source.rb +3 -2
  107. data/lib/ibex/codegen/ambiguity.rb +5 -4
  108. data/lib/ibex/codegen/explain.rb +123 -55
  109. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  110. data/lib/ibex/codegen/rbs.rb +15 -7
  111. data/lib/ibex/codegen/report.rb +25 -13
  112. data/lib/ibex/codegen/ruby.rb +28 -64
  113. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  114. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  115. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  116. data/lib/ibex/configuration/explanation.rb +421 -0
  117. data/lib/ibex/configuration/inspector.rb +232 -0
  118. data/lib/ibex/configuration.rb +580 -0
  119. data/lib/ibex/coverage/collector.rb +21 -11
  120. data/lib/ibex/coverage/event_stream.rb +13 -7
  121. data/lib/ibex/coverage/report.rb +26 -18
  122. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  123. data/lib/ibex/delta_reducer.rb +99 -0
  124. data/lib/ibex/diff.rb +140 -0
  125. data/lib/ibex/equiv/machine.rb +135 -0
  126. data/lib/ibex/equiv.rb +373 -0
  127. data/lib/ibex/fix.rb +557 -0
  128. data/lib/ibex/frontend/ast.rb +22 -2
  129. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  130. data/lib/ibex/frontend/diagnostic.rb +1 -1
  131. data/lib/ibex/frontend/formatter.rb +72 -26
  132. data/lib/ibex/frontend/generated_parser.rb +147 -117
  133. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  134. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  135. data/lib/ibex/frontend/generation.rb +1 -1
  136. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  137. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  138. data/lib/ibex/frontend/regenerator.rb +1 -0
  139. data/lib/ibex/frontend/resolution.rb +2 -1
  140. data/lib/ibex/frontend/resolver.rb +1 -1
  141. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  142. data/lib/ibex/frontend/source_cursor.rb +2 -2
  143. data/lib/ibex/frontend/source_span.rb +9 -1
  144. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  145. data/lib/ibex/frontend/token_adapter.rb +10 -0
  146. data/lib/ibex/frontend.rb +1 -0
  147. data/lib/ibex/fuzz.rb +219 -0
  148. data/lib/ibex/generation_input.rb +1 -1
  149. data/lib/ibex/generation_manifest.rb +36 -25
  150. data/lib/ibex/generation_transaction.rb +1 -1
  151. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  152. data/lib/ibex/generation_transaction_validation.rb +2 -2
  153. data/lib/ibex/grammar_tests.rb +1 -1
  154. data/lib/ibex/ir/automaton_ir.rb +61 -19
  155. data/lib/ibex/ir/grammar_ir.rb +76 -45
  156. data/lib/ibex/ir/lexer_ir.rb +5 -5
  157. data/lib/ibex/ir/parser_contract.rb +135 -0
  158. data/lib/ibex/ir/serialize.rb +203 -76
  159. data/lib/ibex/ir/validator/automaton.rb +64 -34
  160. data/lib/ibex/ir/validator/base.rb +51 -33
  161. data/lib/ibex/ir/validator/grammar.rb +113 -83
  162. data/lib/ibex/ir/validator/lexer.rb +2 -2
  163. data/lib/ibex/ir/validator.rb +2 -1
  164. data/lib/ibex/ir.rb +16 -3
  165. data/lib/ibex/lalr/build_metrics.rb +50 -2
  166. data/lib/ibex/lalr/builder.rb +191 -56
  167. data/lib/ibex/lalr/conflict_search.rb +15 -4
  168. data/lib/ibex/lalr/counterexample.rb +19 -14
  169. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  170. data/lib/ibex/lalr/goto_follows.rb +229 -0
  171. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  172. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  173. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  174. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  175. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  176. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  177. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  178. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  179. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  180. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  181. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  182. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  183. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  184. data/lib/ibex/lalr.rb +52 -1
  185. data/lib/ibex/location.rb +3 -3
  186. data/lib/ibex/lsp/document_handlers.rb +9 -7
  187. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  188. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  189. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  190. data/lib/ibex/lsp/position_codec.rb +6 -2
  191. data/lib/ibex/lsp/request_handlers.rb +3 -2
  192. data/lib/ibex/lsp/request_support.rb +14 -7
  193. data/lib/ibex/lsp/server.rb +13 -11
  194. data/lib/ibex/lsp/symbol_index.rb +13 -13
  195. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  196. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  197. data/lib/ibex/lsp/transport.rb +13 -3
  198. data/lib/ibex/lsp/workspace.rb +5 -4
  199. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  200. data/lib/ibex/lsp.rb +1 -0
  201. data/lib/ibex/messages/en.yml +28 -0
  202. data/lib/ibex/messages/ja.yml +28 -0
  203. data/lib/ibex/messages.rb +68 -0
  204. data/lib/ibex/metrics.rb +175 -0
  205. data/lib/ibex/normalize/declarations.rb +2 -0
  206. data/lib/ibex/normalize/diagnostics.rb +63 -38
  207. data/lib/ibex/normalize/expander.rb +5 -4
  208. data/lib/ibex/normalize/expression.rb +8 -6
  209. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  210. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  211. data/lib/ibex/normalize/lexer.rb +3 -3
  212. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  213. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  214. data/lib/ibex/normalize/parameters.rb +31 -4
  215. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  216. data/lib/ibex/normalize.rb +10 -20
  217. data/lib/ibex/racc_migration/report.rb +6 -3
  218. data/lib/ibex/rake_task.rb +1 -1
  219. data/lib/ibex/samples.rb +43 -13
  220. data/lib/ibex/table_artifact/builder.rb +266 -0
  221. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  222. data/lib/ibex/table_artifact/document.rb +39 -0
  223. data/lib/ibex/table_artifact/executor.rb +187 -0
  224. data/lib/ibex/table_artifact/serializer.rb +57 -0
  225. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  226. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  227. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  228. data/lib/ibex/table_artifact/validator.rb +253 -0
  229. data/lib/ibex/table_artifact.rb +88 -0
  230. data/lib/ibex/table_simulation/result.rb +6 -2
  231. data/lib/ibex/table_simulation/step.rb +3 -1
  232. data/lib/ibex/tables.rb +14 -0
  233. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  234. data/lib/ibex/verification_report/builder.rb +159 -0
  235. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  236. data/lib/ibex/verification_report/logical_path.rb +68 -0
  237. data/lib/ibex/verification_report/validator.rb +329 -0
  238. data/lib/ibex/verification_report.rb +69 -0
  239. data/lib/ibex/verify/action_correspondence.rb +138 -0
  240. data/lib/ibex/verify/language_witness.rb +295 -0
  241. data/lib/ibex/verify/reference_collection.rb +190 -0
  242. data/lib/ibex/verify/result.rb +73 -0
  243. data/lib/ibex/verify/verifier.rb +598 -0
  244. data/lib/ibex/verify.rb +15 -0
  245. data/lib/ibex/version.rb +1 -1
  246. data/lib/ibex/watch/runner.rb +10 -1
  247. data/lib/ibex/watch/source_snapshot.rb +13 -8
  248. data/lib/ibex.rb +10 -0
  249. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  250. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  251. data/schema/bison-import-v1.schema.json +106 -0
  252. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  253. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  254. data/schema/construction-profile-v1.schema.json +779 -0
  255. data/schema/diff-v1.schema.json +41 -0
  256. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  257. data/schema/equiv-v1.schema.json +64 -0
  258. data/schema/error-ux-review-v1.schema.json +609 -0
  259. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  260. data/schema/error-ux-round2-v1.schema.json +519 -0
  261. data/schema/explain-v1.schema.json +63 -1
  262. data/schema/fix-v1.schema.json +64 -0
  263. data/schema/fix-v2.schema.json +66 -0
  264. data/schema/fix-v3.schema.json +101 -0
  265. data/schema/fuzz-regression-v1.schema.json +79 -0
  266. data/schema/fuzz-v1.schema.json +114 -0
  267. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  268. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  269. data/schema/grammar-ir.schema.json +271 -0
  270. data/schema/ielr-benchmark-v1.schema.json +85 -0
  271. data/schema/lexer-profile-v1.schema.json +491 -0
  272. data/schema/metrics-v1.schema.json +60 -0
  273. data/schema/reduce-v1.schema.json +22 -0
  274. data/schema/reduce-v2.schema.json +63 -0
  275. data/schema/table-artifact-v1.schema.json +377 -0
  276. data/schema/verification-report-v1.schema.json +222 -0
  277. data/schema/verify-v1.schema.json +42 -0
  278. data/sig/ibex/analysis/digraph.rbs +19 -0
  279. data/sig/ibex/bison_import/importer.rbs +140 -0
  280. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  281. data/sig/ibex/bison_import.rbs +95 -0
  282. data/sig/ibex/bounded_subprocess.rbs +76 -0
  283. data/sig/ibex/cli/ambiguity.rbs +6 -0
  284. data/sig/ibex/cli/analysis.rbs +43 -0
  285. data/sig/ibex/cli/bison_import.rbs +32 -0
  286. data/sig/ibex/cli/config.rbs +35 -0
  287. data/sig/ibex/cli/diagnostics.rbs +16 -3
  288. data/sig/ibex/cli/documentation.rbs +5 -1
  289. data/sig/ibex/cli/equiv.rbs +49 -0
  290. data/sig/ibex/cli/error_messages.rbs +6 -0
  291. data/sig/ibex/cli/explain.rbs +6 -0
  292. data/sig/ibex/cli/fix.rbs +53 -0
  293. data/sig/ibex/cli/formatting.rbs +5 -1
  294. data/sig/ibex/cli/fuzz.rbs +47 -0
  295. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  296. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  297. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  298. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  299. data/sig/ibex/cli/ir_tools.rbs +7 -19
  300. data/sig/ibex/cli/outputs.rbs +9 -3
  301. data/sig/ibex/cli/reduce.rbs +60 -0
  302. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  303. data/sig/ibex/cli/samples.rbs +8 -0
  304. data/sig/ibex/cli/verify.rbs +28 -0
  305. data/sig/ibex/cli/watch.rbs +2 -2
  306. data/sig/ibex/cli.rbs +79 -5
  307. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  308. data/sig/ibex/codegen/explain.rbs +45 -25
  309. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  310. data/sig/ibex/codegen/rbs.rbs +12 -10
  311. data/sig/ibex/codegen/report.rbs +12 -12
  312. data/sig/ibex/codegen/ruby.rbs +18 -15
  313. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  314. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  315. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  316. data/sig/ibex/configuration/explanation.rbs +195 -0
  317. data/sig/ibex/configuration/inspector.rbs +53 -0
  318. data/sig/ibex/configuration.rbs +242 -0
  319. data/sig/ibex/coverage/collector.rbs +16 -14
  320. data/sig/ibex/coverage/event_stream.rbs +12 -10
  321. data/sig/ibex/coverage/report.rbs +20 -18
  322. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  323. data/sig/ibex/delta_reducer.rbs +38 -0
  324. data/sig/ibex/diff.rbs +47 -0
  325. data/sig/ibex/equiv/machine.rbs +54 -0
  326. data/sig/ibex/equiv.rbs +129 -0
  327. data/sig/ibex/fix.rbs +138 -0
  328. data/sig/ibex/frontend/ast.rbs +33 -7
  329. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  330. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  331. data/sig/ibex/frontend/formatter.rbs +38 -30
  332. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  333. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  334. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  335. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  336. data/sig/ibex/frontend/resolution.rbs +3 -2
  337. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  338. data/sig/ibex/frontend/source_span.rbs +5 -2
  339. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  340. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  341. data/sig/ibex/fuzz.rbs +71 -0
  342. data/sig/ibex/generation_input.rbs +2 -2
  343. data/sig/ibex/generation_manifest.rbs +35 -32
  344. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  345. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  346. data/sig/ibex/grammar_tests.rbs +2 -2
  347. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  348. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  349. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  350. data/sig/ibex/ir/parser_contract.rbs +69 -0
  351. data/sig/ibex/ir/serialize.rbs +63 -28
  352. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  353. data/sig/ibex/ir/validator/base.rbs +35 -31
  354. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  355. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  356. data/sig/ibex/ir.rbs +9 -3
  357. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  358. data/sig/ibex/lalr/builder.rbs +75 -24
  359. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  360. data/sig/ibex/lalr/counterexample.rbs +17 -14
  361. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  362. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  363. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  364. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  365. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  366. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  367. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  368. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  369. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  370. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  371. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  372. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  373. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  374. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  375. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  376. data/sig/ibex/lalr.rbs +11 -1
  377. data/sig/ibex/location.rbs +6 -6
  378. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  379. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  380. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  381. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  382. data/sig/ibex/lsp/position_codec.rbs +8 -4
  383. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  384. data/sig/ibex/lsp/request_support.rbs +8 -8
  385. data/sig/ibex/lsp/server.rbs +16 -16
  386. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  387. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  388. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  389. data/sig/ibex/lsp/transport.rbs +18 -6
  390. data/sig/ibex/lsp/workspace.rbs +3 -2
  391. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  392. data/sig/ibex/messages.rbs +26 -0
  393. data/sig/ibex/metrics.rbs +50 -0
  394. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  395. data/sig/ibex/normalize/expander.rbs +2 -2
  396. data/sig/ibex/normalize/expression.rbs +10 -8
  397. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  398. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  399. data/sig/ibex/normalize/lexer.rbs +4 -4
  400. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  401. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  402. data/sig/ibex/normalize/parameters.rbs +13 -8
  403. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  404. data/sig/ibex/normalize.rbs +11 -5
  405. data/sig/ibex/racc_migration/report.rbs +8 -6
  406. data/sig/ibex/rake_task.rbs +1 -1
  407. data/sig/ibex/samples.rbs +13 -4
  408. data/sig/ibex/table_artifact/builder.rbs +93 -0
  409. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  410. data/sig/ibex/table_artifact/document.rbs +27 -0
  411. data/sig/ibex/table_artifact/executor.rbs +66 -0
  412. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  413. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  414. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  415. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  416. data/sig/ibex/table_artifact/validator.rbs +66 -0
  417. data/sig/ibex/table_artifact.rbs +32 -0
  418. data/sig/ibex/table_simulation/result.rbs +8 -4
  419. data/sig/ibex/table_simulation/step.rbs +4 -2
  420. data/sig/ibex/tables.rbs +10 -9
  421. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  422. data/sig/ibex/verification_report/builder.rbs +53 -0
  423. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  424. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  425. data/sig/ibex/verification_report/validator.rbs +114 -0
  426. data/sig/ibex/verification_report.rbs +44 -0
  427. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  428. data/sig/ibex/verify/language_witness.rbs +112 -0
  429. data/sig/ibex/verify/reference_collection.rbs +63 -0
  430. data/sig/ibex/verify/result.rbs +52 -0
  431. data/sig/ibex/verify/verifier.rbs +170 -0
  432. data/sig/ibex/verify.rbs +6 -0
  433. data/sig/ibex/watch/runner.rbs +12 -2
  434. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  435. metadata +232 -12
  436. data/lib/ibex/ir/migration.rb +0 -120
  437. data/sig/ibex/ir/migration.rbs +0 -34
@@ -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,47 +4,81 @@ require "json"
4
4
 
5
5
  module Ibex
6
6
  module IR
7
- # Stable JSON serialization for versioned pipeline IR.
8
- # rubocop:disable Metrics/ModuleLength -- explicit versioned fields keep serialization changes auditable.
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.
9
10
  module Serialize
10
11
  # @rbs!
11
- # private def validate_version: (untyped data) -> untyped
12
- # private def self.validate_version: (untyped data) -> untyped
13
- # private def load_grammar: (untyped data) -> untyped
14
- # private def self.load_grammar: (untyped data) -> untyped
15
- # private def load_automaton: (untyped data) -> untyped
16
- # private def self.load_automaton: (untyped data) -> untyped
17
- # private def load_lexer: (untyped data) -> untyped
18
- # private def self.load_lexer: (untyped data) -> untyped
19
- # private def load_state: (untyped state, untyped grammar) -> untyped
20
- # private def self.load_state: (untyped state, untyped grammar) -> untyped
21
- # private def symbol_keyed: (untyped values, untyped grammar, ?actions: untyped) -> untyped
22
- # private def self.symbol_keyed: (untyped values, untyped grammar, ?actions: untyped) -> untyped
23
- # private def normalize_action: (untyped value) -> untyped
24
- # private def self.normalize_action: (untyped value) -> untyped
25
- # private def load_production: (untyped production, Integer schema_version) -> untyped
26
- # private def self.load_production: (untyped production, Integer schema_version) -> untyped
27
- # private def load_user_code_chunks: (untyped chunks) -> untyped
28
- # private def self.load_user_code_chunks: (untyped chunks) -> untyped
29
- # private def load_symbol_metadata: (untyped symbol, String field) -> String?
30
- # private def self.load_symbol_metadata: (untyped symbol, String field) -> String?
31
- # private def load_grammar_tests: (untyped tests) -> untyped
32
- # private def self.load_grammar_tests: (untyped tests) -> untyped
33
- # private def symbol_source_position: (untyped symbol) -> String
34
- # private def self.symbol_source_position: (untyped symbol) -> String
35
- # private def symbolize: (untyped value) -> untyped
36
- # private def self.symbolize: (untyped value) -> untyped
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
37
58
 
38
59
  # @rbs (Grammar | Automaton | Lexer value) -> String
39
60
  def dump(value)
40
- "#{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"
41
75
  end
42
76
  module_function :dump
43
77
 
44
78
  # @rbs (String source) -> (Grammar | Automaton | Lexer)
45
79
  def load(source)
46
- data = JSON.parse(source)
47
- 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
48
82
  return load_lexer(data) if type == "lexer"
49
83
 
50
84
  validate_version(data)
@@ -57,7 +91,6 @@ module Ibex
57
91
  end
58
92
  module_function :load
59
93
 
60
- # @rbs skip
61
94
  private
62
95
 
63
96
  # @rbs skip
@@ -66,18 +99,38 @@ module Ibex
66
99
  return if SUPPORTED_SCHEMA_VERSIONS.include?(version)
67
100
 
68
101
  expected = SUPPORTED_SCHEMA_VERSIONS.join(", ")
69
- raise Ibex::Error, "(ir):1:1: unsupported schema_version #{version.inspect}; expected one of #{expected}"
102
+ raise Ibex::Error,
103
+ "(ir):1:1: unsupported schema_version #{version.inspect}; expected the current format (#{expected})"
70
104
  end
71
105
 
106
+ # rubocop:disable Metrics/AbcSize -- explicit current Grammar IR field mapping is the loader contract.
72
107
  # @rbs skip
73
- def load_grammar(data) # rubocop:disable Metrics/AbcSize -- explicit fields preserve the public IR contract.
74
- empty_chunks = {} #: Hash[String, untyped]
75
- empty_parameters = [] #: Array[untyped]
76
- empty_printers = [] #: Array[untyped]
77
- empty_tests = [] #: Array[untyped]
78
- empty_recovery = { "sync_tokens" => [], "on_error_reduce" => [] } #: Hash[String, untyped]
79
- schema_version = data.fetch("schema_version")
80
- symbols = data.fetch("symbols").map do |symbol|
108
+ def load_grammar(data)
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|
81
134
  GrammarSymbol.new(id: symbol.fetch("id"), name: symbol.fetch("name"), kind: symbol.fetch("kind"),
82
135
  reserved: symbol.fetch("reserved"), precedence: symbolize(symbol["prec"]),
83
136
  location: symbolize(symbol["loc"]),
@@ -85,42 +138,71 @@ module Ibex
85
138
  semantic_type: load_symbol_metadata(symbol, "semantic_type"),
86
139
  documentation: symbol["doc"])
87
140
  end
88
- productions = data.fetch("productions").map { |production| load_production(production, schema_version) }
89
- Grammar.new(class_name: data.fetch("class_name"), superclass: data["superclass"], start: data.fetch("start"),
90
- expect: data.fetch("expect"), options: symbolize(data.fetch("options")), symbols: symbols,
91
- mode: (data["mode"] || "default").to_sym,
92
- starts: data["starts"],
93
- expect_rr: data["expect_rr"],
94
- parser_parameters: symbolize(data.fetch("params", empty_parameters)),
95
- value_printers: symbolize(data.fetch("printers", empty_printers)),
96
- grammar_tests: load_grammar_tests(data.fetch("tests", empty_tests)),
97
- lexer: data["lexer"] && load_lexer(data.fetch("lexer")),
98
- recovery: symbolize(data.fetch("recovery", empty_recovery)),
99
- productions: productions, user_code: data.fetch("user_code"),
100
- conversions: data.fetch("conversions"), warnings: symbolize(data.fetch("warnings")),
101
- user_code_chunks: load_user_code_chunks(data.fetch("user_code_chunks", empty_chunks)),
102
- schema_version: schema_version, source_provenance: symbolize(data["source_provenance"]),
103
- migration: symbolize(data["migration"]))
104
- end # rubocop:enable Metrics/AbcSize
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
177
+ end
105
178
 
106
179
  # @rbs skip
107
180
  def load_automaton(data)
108
- grammar = load_grammar(data.fetch("grammar"))
109
- states = data.fetch("states").map { |state| load_state(state, grammar) }
110
- Automaton.new(grammar: grammar, states: states, conflict_summary: symbolize(data.fetch("conflict_summary")),
111
- algorithm: data.fetch("algorithm"), grammar_digest: data.fetch("grammar_digest"),
112
- schema_version: data.fetch("schema_version"), entry_states: data["entry_states"])
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
+ )
113
192
  end
114
193
 
115
194
  # @rbs skip
116
195
  def load_lexer(data)
117
- version = data.fetch("schema_version")
196
+ data = data #: Hash[String, IR::serialized_value]
197
+ version = data.fetch("schema_version") #: Integer
118
198
  unless SUPPORTED_LEXER_SCHEMA_VERSIONS.include?(version)
119
199
  expected = SUPPORTED_LEXER_SCHEMA_VERSIONS.join(", ")
120
200
  raise Ibex::Error,
121
- "(ir):1:1: unsupported lexer schema_version #{version.inspect}; expected one of #{expected}"
201
+ "(ir):1:1: unsupported lexer schema_version #{version.inspect}; " \
202
+ "expected the current lexer format (#{expected})"
122
203
  end
123
- rules = data.fetch("rules").map do |rule|
204
+ rules_data = data.fetch("rules") #: Array[Hash[String, IR::serialized_value]]
205
+ rules = rules_data.map do |rule|
124
206
  LexerRule.new(
125
207
  id: rule.fetch("id"), state: rule.fetch("state"), kind: rule.fetch("kind").to_sym,
126
208
  token: rule["token"], pattern: rule.fetch("pattern"), pattern_kind: rule.fetch("pattern_kind").to_sym,
@@ -135,8 +217,14 @@ module Ibex
135
217
 
136
218
  # @rbs skip
137
219
  def load_state(state, grammar)
138
- items = state.fetch("items").map do |item|
139
- 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
140
228
  AutomatonItem.new(production: item.fetch("production"), dot: item.fetch("dot"), lookaheads: lookaheads)
141
229
  end
142
230
  AutomatonState.new(id: state.fetch("id"), items: items,
@@ -149,13 +237,16 @@ module Ibex
149
237
 
150
238
  # @rbs skip
151
239
  def symbol_keyed(values, grammar, actions: false)
240
+ values = values #: Hash[String, IR::serialized_value]
152
241
  values.to_h do |name, value|
153
- [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]
154
244
  end
155
245
  end
156
246
 
157
247
  # @rbs skip
158
248
  def normalize_action(value)
249
+ value = value #: IR::serialized_value
159
250
  return nil unless value
160
251
 
161
252
  action = symbolize(value)
@@ -164,8 +255,10 @@ module Ibex
164
255
  end
165
256
 
166
257
  # @rbs skip
167
- def load_production(production, schema_version)
258
+ def load_production(production)
259
+ production = production #: Hash[String, IR::serialized_value]
168
260
  action_data = production["action"]
261
+ action_data = action_data #: Hash[String, IR::serialized_value] if action_data
169
262
  action = if action_data
170
263
  Action.new(code: action_data.fetch("code"), location: symbolize(action_data["loc"]),
171
264
  named_refs: symbolize(action_data.fetch("named_refs")),
@@ -175,12 +268,12 @@ module Ibex
175
268
  Production.new(id: production.fetch("id"), lhs: production.fetch("lhs"), rhs: production.fetch("rhs"),
176
269
  action: action, precedence_override: production["prec_override"],
177
270
  origin: symbolize(production.fetch("origin")), documentation: production["doc"],
178
- expansion: schema_version >= 2 ? symbolize(production["expansion"]) : nil,
179
- node: schema_version >= 2 ? symbolize(production["node"]) : nil)
271
+ expansion: symbolize(production["expansion"]), node: symbolize(production["node"]))
180
272
  end
181
273
 
182
274
  # @rbs skip
183
275
  def load_user_code_chunks(chunks)
276
+ chunks = chunks #: Hash[String, Array[Hash[String, IR::serialized_value]]]
184
277
  chunks.to_h do |name, values|
185
278
  loaded = values.map do |value|
186
279
  UserCodeChunk.new(code: value.fetch("code"), location: symbolize(value.fetch("loc")))
@@ -191,6 +284,7 @@ module Ibex
191
284
 
192
285
  # @rbs skip
193
286
  def load_symbol_metadata(symbol, field)
287
+ symbol = symbol #: Hash[String, IR::serialized_value]
194
288
  value = symbol[field]
195
289
  return nil if value.nil?
196
290
 
@@ -219,27 +313,60 @@ module Ibex
219
313
 
220
314
  # @rbs skip
221
315
  def load_grammar_tests(tests)
316
+ tests = tests #: Array[IR::serialized_value]
222
317
  symbolize(tests).map { |test| test.merge(expectation: test.fetch(:expectation).to_sym) }
223
318
  end
224
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.
225
344
  # @rbs skip
226
345
  def symbolize(value)
346
+ value = value #: IR::serialized_value
227
347
  case value
228
348
  when Array then value.map { |item| symbolize(item) }
229
349
  when Hash then value.to_h { |key, item| [key.to_sym, symbolize(item)] }
230
350
  else value
231
351
  end
232
352
  end
233
- module_function :validate_version, :load_grammar, :load_automaton, :load_lexer, :load_state, :symbol_keyed,
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,
234
356
  :normalize_action, :load_production, :load_user_code_chunks, :load_symbol_metadata,
235
- :symbol_source_position, :load_grammar_tests, :symbolize
357
+ :symbol_source_position, :load_grammar_tests,
358
+ :load_parser_contract, :symbolize
236
359
 
237
360
  class << self
238
- private :validate_version, :load_grammar, :load_automaton, :load_lexer, :load_state, :symbol_keyed,
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,
239
364
  :normalize_action, :load_production, :load_user_code_chunks, :load_symbol_metadata,
240
- :symbol_source_position, :load_grammar_tests, :symbolize
365
+ :symbol_source_position, :load_grammar_tests,
366
+ :load_parser_contract, :symbolize
241
367
  end
242
368
  end
369
+ # rubocop:enable Lint/SelfAssignment
243
370
  # rubocop:enable Metrics/ModuleLength
244
371
  end
245
372
  end