ibex 0.2.0 → 0.4.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 (461) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -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 +274 -0
  40. data/docs/development.md +196 -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 +1617 -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/impact.md +101 -0
  56. data/docs/ja/bison-import.md +51 -0
  57. data/docs/ja/stable-api.md +53 -0
  58. data/docs/lexer-construction-profile.md +109 -0
  59. data/docs/lexer-migration.md +5 -0
  60. data/docs/maturity.md +129 -0
  61. data/docs/project-site-strategy.md +54 -0
  62. data/docs/racc-migration-evidence.md +45 -0
  63. data/docs/racc-migration.md +11 -0
  64. data/docs/release-readiness.md +126 -68
  65. data/docs/repair-semantics.md +123 -0
  66. data/docs/runtime-abi-evolution.md +310 -0
  67. data/docs/stability.md +145 -34
  68. data/docs/status.md +43 -0
  69. data/docs/syntax-sessions.md +183 -0
  70. data/docs/table-artifact.md +125 -0
  71. data/docs/test-interactions.md +219 -0
  72. data/docs/verification-report.md +137 -0
  73. data/docs/verifier-trust-boundary.md +199 -0
  74. data/docs/workloads.md +132 -0
  75. data/lib/ibex/analysis/digraph.rb +128 -0
  76. data/lib/ibex/analysis/sets.rb +14 -0
  77. data/lib/ibex/analysis.rb +1 -0
  78. data/lib/ibex/bison_import/importer.rb +516 -0
  79. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  80. data/lib/ibex/bison_import.rb +200 -0
  81. data/lib/ibex/bounded_subprocess.rb +171 -0
  82. data/lib/ibex/cli/ambiguity.rb +14 -5
  83. data/lib/ibex/cli/analysis.rb +134 -0
  84. data/lib/ibex/cli/bison_import.rb +121 -0
  85. data/lib/ibex/cli/config.rb +128 -0
  86. data/lib/ibex/cli/diagnostics.rb +31 -11
  87. data/lib/ibex/cli/documentation.rb +11 -8
  88. data/lib/ibex/cli/equiv.rb +169 -0
  89. data/lib/ibex/cli/error_messages.rb +11 -4
  90. data/lib/ibex/cli/explain.rb +14 -5
  91. data/lib/ibex/cli/fix.rb +203 -0
  92. data/lib/ibex/cli/formatting.rb +11 -10
  93. data/lib/ibex/cli/fuzz.rb +200 -0
  94. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  95. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  96. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  97. data/lib/ibex/cli/grammar_tests.rb +32 -14
  98. data/lib/ibex/cli/impact.rb +393 -0
  99. data/lib/ibex/cli/ir_tools.rb +5 -61
  100. data/lib/ibex/cli/outputs.rb +60 -33
  101. data/lib/ibex/cli/reduce.rb +202 -0
  102. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  103. data/lib/ibex/cli/samples.rb +49 -23
  104. data/lib/ibex/cli/verify.rb +116 -0
  105. data/lib/ibex/cli/watch.rb +6 -5
  106. data/lib/ibex/cli.rb +362 -56
  107. data/lib/ibex/codegen/action_locations.rb +1 -1
  108. data/lib/ibex/codegen/action_method_source.rb +5 -6
  109. data/lib/ibex/codegen/action_source.rb +3 -2
  110. data/lib/ibex/codegen/ambiguity.rb +5 -4
  111. data/lib/ibex/codegen/explain.rb +123 -55
  112. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  113. data/lib/ibex/codegen/rbs.rb +15 -7
  114. data/lib/ibex/codegen/report.rb +25 -13
  115. data/lib/ibex/codegen/ruby.rb +28 -64
  116. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  117. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  118. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  119. data/lib/ibex/configuration/explanation.rb +421 -0
  120. data/lib/ibex/configuration/inspector.rb +232 -0
  121. data/lib/ibex/configuration.rb +580 -0
  122. data/lib/ibex/coverage/collector.rb +21 -11
  123. data/lib/ibex/coverage/event_stream.rb +13 -7
  124. data/lib/ibex/coverage/report.rb +26 -18
  125. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  126. data/lib/ibex/delta_reducer.rb +99 -0
  127. data/lib/ibex/diff.rb +141 -0
  128. data/lib/ibex/equiv/machine.rb +135 -0
  129. data/lib/ibex/equiv.rb +373 -0
  130. data/lib/ibex/fix.rb +557 -0
  131. data/lib/ibex/frontend/ast.rb +22 -2
  132. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  133. data/lib/ibex/frontend/diagnostic.rb +1 -1
  134. data/lib/ibex/frontend/formatter.rb +72 -26
  135. data/lib/ibex/frontend/generated_parser.rb +147 -117
  136. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  137. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  138. data/lib/ibex/frontend/generation.rb +1 -1
  139. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  140. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  141. data/lib/ibex/frontend/regenerator.rb +1 -0
  142. data/lib/ibex/frontend/resolution.rb +2 -1
  143. data/lib/ibex/frontend/resolver.rb +1 -1
  144. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  145. data/lib/ibex/frontend/source_cursor.rb +2 -2
  146. data/lib/ibex/frontend/source_span.rb +9 -1
  147. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  148. data/lib/ibex/frontend/token_adapter.rb +10 -0
  149. data/lib/ibex/frontend.rb +1 -0
  150. data/lib/ibex/fuzz.rb +219 -0
  151. data/lib/ibex/generation_input.rb +1 -1
  152. data/lib/ibex/generation_manifest.rb +36 -25
  153. data/lib/ibex/generation_transaction.rb +1 -1
  154. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  155. data/lib/ibex/generation_transaction_validation.rb +2 -2
  156. data/lib/ibex/grammar_tests.rb +1 -1
  157. data/lib/ibex/impact/action_impact.rb +148 -0
  158. data/lib/ibex/impact/automaton_impact.rb +57 -0
  159. data/lib/ibex/impact/coverage_impact.rb +53 -0
  160. data/lib/ibex/impact/graph.rb +132 -0
  161. data/lib/ibex/impact/propagation.rb +147 -0
  162. data/lib/ibex/impact/report.rb +273 -0
  163. data/lib/ibex/impact/seeds.rb +69 -0
  164. data/lib/ibex/impact/severity.rb +139 -0
  165. data/lib/ibex/impact.rb +16 -0
  166. data/lib/ibex/ir/automaton_ir.rb +61 -19
  167. data/lib/ibex/ir/grammar_ir.rb +76 -45
  168. data/lib/ibex/ir/lexer_ir.rb +5 -5
  169. data/lib/ibex/ir/parser_contract.rb +135 -0
  170. data/lib/ibex/ir/serialize.rb +203 -76
  171. data/lib/ibex/ir/validator/automaton.rb +64 -34
  172. data/lib/ibex/ir/validator/base.rb +51 -33
  173. data/lib/ibex/ir/validator/grammar.rb +113 -83
  174. data/lib/ibex/ir/validator/lexer.rb +2 -2
  175. data/lib/ibex/ir/validator.rb +2 -1
  176. data/lib/ibex/ir.rb +16 -3
  177. data/lib/ibex/lalr/build_metrics.rb +50 -2
  178. data/lib/ibex/lalr/builder.rb +191 -56
  179. data/lib/ibex/lalr/conflict_search.rb +15 -4
  180. data/lib/ibex/lalr/counterexample.rb +19 -14
  181. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  182. data/lib/ibex/lalr/goto_follows.rb +229 -0
  183. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  184. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  185. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  186. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  187. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  188. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  189. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  190. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  191. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  192. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  193. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  194. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  195. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  196. data/lib/ibex/lalr.rb +52 -1
  197. data/lib/ibex/location.rb +3 -3
  198. data/lib/ibex/lsp/document_handlers.rb +9 -7
  199. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  200. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  201. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  202. data/lib/ibex/lsp/position_codec.rb +6 -2
  203. data/lib/ibex/lsp/request_handlers.rb +3 -2
  204. data/lib/ibex/lsp/request_support.rb +14 -7
  205. data/lib/ibex/lsp/server.rb +13 -11
  206. data/lib/ibex/lsp/symbol_index.rb +13 -13
  207. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  208. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  209. data/lib/ibex/lsp/transport.rb +13 -3
  210. data/lib/ibex/lsp/workspace.rb +5 -4
  211. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  212. data/lib/ibex/lsp.rb +1 -0
  213. data/lib/ibex/messages/en.yml +28 -0
  214. data/lib/ibex/messages/ja.yml +28 -0
  215. data/lib/ibex/messages.rb +68 -0
  216. data/lib/ibex/metrics.rb +175 -0
  217. data/lib/ibex/normalize/declarations.rb +2 -0
  218. data/lib/ibex/normalize/diagnostics.rb +63 -38
  219. data/lib/ibex/normalize/expander.rb +5 -4
  220. data/lib/ibex/normalize/expression.rb +8 -6
  221. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  222. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  223. data/lib/ibex/normalize/lexer.rb +3 -3
  224. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  225. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  226. data/lib/ibex/normalize/parameters.rb +31 -4
  227. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  228. data/lib/ibex/normalize.rb +10 -20
  229. data/lib/ibex/racc_migration/report.rb +6 -3
  230. data/lib/ibex/rake_task.rb +1 -1
  231. data/lib/ibex/samples.rb +43 -13
  232. data/lib/ibex/table_artifact/builder.rb +266 -0
  233. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  234. data/lib/ibex/table_artifact/document.rb +39 -0
  235. data/lib/ibex/table_artifact/executor.rb +187 -0
  236. data/lib/ibex/table_artifact/serializer.rb +57 -0
  237. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  238. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  239. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  240. data/lib/ibex/table_artifact/validator.rb +253 -0
  241. data/lib/ibex/table_artifact.rb +88 -0
  242. data/lib/ibex/table_simulation/result.rb +6 -2
  243. data/lib/ibex/table_simulation/step.rb +3 -1
  244. data/lib/ibex/tables.rb +14 -0
  245. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  246. data/lib/ibex/verification_report/builder.rb +159 -0
  247. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  248. data/lib/ibex/verification_report/logical_path.rb +68 -0
  249. data/lib/ibex/verification_report/validator.rb +329 -0
  250. data/lib/ibex/verification_report.rb +69 -0
  251. data/lib/ibex/verify/action_correspondence.rb +138 -0
  252. data/lib/ibex/verify/language_witness.rb +295 -0
  253. data/lib/ibex/verify/reference_collection.rb +190 -0
  254. data/lib/ibex/verify/result.rb +73 -0
  255. data/lib/ibex/verify/verifier.rb +598 -0
  256. data/lib/ibex/verify.rb +15 -0
  257. data/lib/ibex/version.rb +1 -1
  258. data/lib/ibex/watch/runner.rb +10 -1
  259. data/lib/ibex/watch/source_snapshot.rb +13 -8
  260. data/lib/ibex.rb +11 -0
  261. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  262. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  263. data/schema/bison-import-v1.schema.json +106 -0
  264. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  265. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  266. data/schema/construction-profile-v1.schema.json +779 -0
  267. data/schema/diff-v1.schema.json +41 -0
  268. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  269. data/schema/equiv-v1.schema.json +64 -0
  270. data/schema/error-ux-review-v1.schema.json +609 -0
  271. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  272. data/schema/error-ux-round2-v1.schema.json +519 -0
  273. data/schema/explain-v1.schema.json +63 -1
  274. data/schema/fix-v1.schema.json +64 -0
  275. data/schema/fix-v2.schema.json +66 -0
  276. data/schema/fix-v3.schema.json +101 -0
  277. data/schema/fuzz-regression-v1.schema.json +79 -0
  278. data/schema/fuzz-v1.schema.json +114 -0
  279. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  280. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  281. data/schema/grammar-ir.schema.json +271 -0
  282. data/schema/ielr-benchmark-v1.schema.json +85 -0
  283. data/schema/impact-v1.schema.json +208 -0
  284. data/schema/lexer-profile-v1.schema.json +491 -0
  285. data/schema/metrics-v1.schema.json +60 -0
  286. data/schema/reduce-v1.schema.json +22 -0
  287. data/schema/reduce-v2.schema.json +63 -0
  288. data/schema/table-artifact-v1.schema.json +377 -0
  289. data/schema/verification-report-v1.schema.json +222 -0
  290. data/schema/verify-v1.schema.json +42 -0
  291. data/sig/ibex/analysis/digraph.rbs +19 -0
  292. data/sig/ibex/analysis/sets.rbs +10 -0
  293. data/sig/ibex/bison_import/importer.rbs +140 -0
  294. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  295. data/sig/ibex/bison_import.rbs +95 -0
  296. data/sig/ibex/bounded_subprocess.rbs +76 -0
  297. data/sig/ibex/cli/ambiguity.rbs +6 -0
  298. data/sig/ibex/cli/analysis.rbs +43 -0
  299. data/sig/ibex/cli/bison_import.rbs +32 -0
  300. data/sig/ibex/cli/config.rbs +35 -0
  301. data/sig/ibex/cli/diagnostics.rbs +16 -3
  302. data/sig/ibex/cli/documentation.rbs +5 -1
  303. data/sig/ibex/cli/equiv.rbs +49 -0
  304. data/sig/ibex/cli/error_messages.rbs +6 -0
  305. data/sig/ibex/cli/explain.rbs +6 -0
  306. data/sig/ibex/cli/fix.rbs +53 -0
  307. data/sig/ibex/cli/formatting.rbs +5 -1
  308. data/sig/ibex/cli/fuzz.rbs +47 -0
  309. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  310. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  311. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  312. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  313. data/sig/ibex/cli/impact.rbs +95 -0
  314. data/sig/ibex/cli/ir_tools.rbs +7 -19
  315. data/sig/ibex/cli/outputs.rbs +9 -3
  316. data/sig/ibex/cli/reduce.rbs +60 -0
  317. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  318. data/sig/ibex/cli/samples.rbs +8 -0
  319. data/sig/ibex/cli/verify.rbs +28 -0
  320. data/sig/ibex/cli/watch.rbs +2 -2
  321. data/sig/ibex/cli.rbs +79 -5
  322. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  323. data/sig/ibex/codegen/explain.rbs +45 -25
  324. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  325. data/sig/ibex/codegen/rbs.rbs +12 -10
  326. data/sig/ibex/codegen/report.rbs +12 -12
  327. data/sig/ibex/codegen/ruby.rbs +18 -15
  328. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  329. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  330. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  331. data/sig/ibex/configuration/explanation.rbs +195 -0
  332. data/sig/ibex/configuration/inspector.rbs +53 -0
  333. data/sig/ibex/configuration.rbs +242 -0
  334. data/sig/ibex/coverage/collector.rbs +16 -14
  335. data/sig/ibex/coverage/event_stream.rbs +12 -10
  336. data/sig/ibex/coverage/report.rbs +20 -18
  337. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  338. data/sig/ibex/delta_reducer.rbs +38 -0
  339. data/sig/ibex/diff.rbs +47 -0
  340. data/sig/ibex/equiv/machine.rbs +54 -0
  341. data/sig/ibex/equiv.rbs +129 -0
  342. data/sig/ibex/fix.rbs +138 -0
  343. data/sig/ibex/frontend/ast.rbs +33 -7
  344. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  345. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  346. data/sig/ibex/frontend/formatter.rbs +38 -30
  347. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  348. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  349. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  350. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  351. data/sig/ibex/frontend/resolution.rbs +3 -2
  352. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  353. data/sig/ibex/frontend/source_span.rbs +5 -2
  354. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  355. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  356. data/sig/ibex/fuzz.rbs +71 -0
  357. data/sig/ibex/generation_input.rbs +2 -2
  358. data/sig/ibex/generation_manifest.rbs +35 -32
  359. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  360. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  361. data/sig/ibex/grammar_tests.rbs +2 -2
  362. data/sig/ibex/impact/action_impact.rbs +58 -0
  363. data/sig/ibex/impact/automaton_impact.rbs +37 -0
  364. data/sig/ibex/impact/coverage_impact.rbs +28 -0
  365. data/sig/ibex/impact/graph.rbs +67 -0
  366. data/sig/ibex/impact/propagation.rbs +56 -0
  367. data/sig/ibex/impact/report.rbs +107 -0
  368. data/sig/ibex/impact/seeds.rbs +36 -0
  369. data/sig/ibex/impact/severity.rbs +55 -0
  370. data/sig/ibex/impact.rbs +6 -0
  371. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  372. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  373. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  374. data/sig/ibex/ir/parser_contract.rbs +69 -0
  375. data/sig/ibex/ir/serialize.rbs +63 -28
  376. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  377. data/sig/ibex/ir/validator/base.rbs +35 -31
  378. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  379. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  380. data/sig/ibex/ir.rbs +9 -3
  381. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  382. data/sig/ibex/lalr/builder.rbs +75 -24
  383. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  384. data/sig/ibex/lalr/counterexample.rbs +17 -14
  385. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  386. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  387. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  388. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  389. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  390. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  391. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  392. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  393. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  394. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  395. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  396. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  397. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  398. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  399. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  400. data/sig/ibex/lalr.rbs +11 -1
  401. data/sig/ibex/location.rbs +6 -6
  402. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  403. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  404. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  405. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  406. data/sig/ibex/lsp/position_codec.rbs +8 -4
  407. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  408. data/sig/ibex/lsp/request_support.rbs +8 -8
  409. data/sig/ibex/lsp/server.rbs +16 -16
  410. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  411. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  412. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  413. data/sig/ibex/lsp/transport.rbs +18 -6
  414. data/sig/ibex/lsp/workspace.rbs +3 -2
  415. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  416. data/sig/ibex/messages.rbs +26 -0
  417. data/sig/ibex/metrics.rbs +50 -0
  418. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  419. data/sig/ibex/normalize/expander.rbs +2 -2
  420. data/sig/ibex/normalize/expression.rbs +10 -8
  421. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  422. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  423. data/sig/ibex/normalize/lexer.rbs +4 -4
  424. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  425. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  426. data/sig/ibex/normalize/parameters.rbs +13 -8
  427. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  428. data/sig/ibex/normalize.rbs +11 -5
  429. data/sig/ibex/racc_migration/report.rbs +8 -6
  430. data/sig/ibex/rake_task.rbs +1 -1
  431. data/sig/ibex/samples.rbs +13 -4
  432. data/sig/ibex/table_artifact/builder.rbs +93 -0
  433. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  434. data/sig/ibex/table_artifact/document.rbs +27 -0
  435. data/sig/ibex/table_artifact/executor.rbs +66 -0
  436. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  437. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  438. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  439. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  440. data/sig/ibex/table_artifact/validator.rbs +66 -0
  441. data/sig/ibex/table_artifact.rbs +32 -0
  442. data/sig/ibex/table_simulation/result.rbs +8 -4
  443. data/sig/ibex/table_simulation/step.rbs +4 -2
  444. data/sig/ibex/tables.rbs +10 -9
  445. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  446. data/sig/ibex/verification_report/builder.rbs +53 -0
  447. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  448. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  449. data/sig/ibex/verification_report/validator.rbs +114 -0
  450. data/sig/ibex/verification_report.rbs +44 -0
  451. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  452. data/sig/ibex/verify/language_witness.rbs +112 -0
  453. data/sig/ibex/verify/reference_collection.rbs +63 -0
  454. data/sig/ibex/verify/result.rbs +52 -0
  455. data/sig/ibex/verify/verifier.rbs +170 -0
  456. data/sig/ibex/verify.rbs +6 -0
  457. data/sig/ibex/watch/runner.rbs +12 -2
  458. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  459. metadata +254 -12
  460. data/lib/ibex/ir/migration.rb +0 -120
  461. data/sig/ibex/ir/migration.rbs +0 -34
@@ -16,7 +16,7 @@ module Ibex
16
16
  freeze
17
17
  end
18
18
 
19
- # @rbs (Grammar grammar) -> Hash[Symbol, untyped]
19
+ # @rbs (Grammar grammar) -> Hash[Symbol, Object?]
20
20
  def to_h(grammar)
21
21
  { production: @production, dot: @dot,
22
22
  lookaheads: @lookaheads.map do |id|
@@ -50,7 +50,7 @@ module Ibex
50
50
  freeze
51
51
  end
52
52
 
53
- # @rbs (Grammar grammar) -> Hash[Symbol, untyped]
53
+ # @rbs (Grammar grammar) -> Hash[Symbol, Object?]
54
54
  def to_h(grammar)
55
55
  { id: @id, items: @items.map { |item| item.to_h(grammar) },
56
56
  transitions: named_keys(@transitions, grammar), actions: named_keys(@actions, grammar),
@@ -59,7 +59,7 @@ module Ibex
59
59
 
60
60
  private
61
61
 
62
- # @rbs (Hash[Integer, untyped] values, Grammar grammar) -> Hash[String, untyped]
62
+ # @rbs (Hash[Integer, Object?] values, Grammar grammar) -> Hash[String, Object?]
63
63
  def named_keys(values, grammar)
64
64
  values.to_h do |symbol_id, value|
65
65
  symbol = grammar.symbol_by_id(symbol_id) || raise(Ibex::Error, "missing grammar symbol id #{symbol_id}")
@@ -77,42 +77,55 @@ module Ibex
77
77
  attr_reader :entry_states #: Hash[String, Integer]
78
78
  attr_reader :conflict_summary #: conflict_summary
79
79
  attr_reader :schema_version #: Integer
80
+ attr_reader :entry_construction #: String
80
81
 
81
82
  # @rbs (grammar: Grammar, states: Array[AutomatonState], conflict_summary: conflict_summary,
82
- # ?algorithm: String, ?grammar_digest: String?, ?schema_version: Integer,
83
- # ?entry_states: Hash[String, Integer]?) -> void
83
+ # ?algorithm: String, ?grammar_digest: String?, ?entry_states: Hash[String, Integer]?,
84
+ # ?entry_construction: String) -> void
84
85
  def initialize(grammar:, states:, conflict_summary:, algorithm: "lalr1", grammar_digest: nil,
85
- schema_version: SCHEMA_VERSION, entry_states: nil)
86
- unless SUPPORTED_SCHEMA_VERSIONS.include?(schema_version)
87
- raise Ibex::Error, "unsupported automaton schema_version #{schema_version.inspect}"
88
- end
86
+ entry_states: nil, entry_construction: "shared")
87
+ initialize_current(
88
+ grammar: grammar, states: states, conflict_summary: conflict_summary, algorithm: algorithm,
89
+ grammar_digest: grammar_digest, entry_states: entry_states, entry_construction: entry_construction
90
+ )
91
+ end
89
92
 
90
- grammar = Migration.to_v2(grammar) if schema_version >= 2 && grammar.schema_version != schema_version
91
- raise Ibex::Error, "automaton migration did not produce a grammar" unless grammar.is_a?(Grammar)
92
- unless grammar.schema_version == schema_version
93
- raise Ibex::Error,
94
- "automaton schema_version #{schema_version} requires Grammar IR v#{schema_version}, " \
95
- "got v#{grammar.schema_version}"
93
+ # @rbs (grammar: Grammar, states: Array[AutomatonState], conflict_summary: conflict_summary,
94
+ # algorithm: String, grammar_digest: String?, entry_states: Hash[String, Integer]?,
95
+ # entry_construction: String) -> void
96
+ def initialize_current(grammar:, states:, conflict_summary:, algorithm:, grammar_digest:, entry_states:,
97
+ entry_construction:)
98
+ unless grammar.schema_version == SCHEMA_VERSION
99
+ raise Ibex::Error, "automaton requires the current Grammar IR format"
96
100
  end
97
101
 
98
102
  @algorithm = algorithm.freeze
99
103
  @grammar = grammar
100
- @grammar_digest = (grammar_digest || digest_for(grammar)).freeze
104
+ expected_digest = digest_for(grammar)
105
+ if grammar_digest && grammar_digest != expected_digest
106
+ raise Ibex::Error,
107
+ "(ir):1:1: $.grammar_digest does not match the embedded grammar; expected #{expected_digest.inspect}"
108
+ end
109
+ @grammar_digest = (grammar_digest || expected_digest).freeze
101
110
  @states = states.freeze
102
111
  @entry_states = IR.deep_freeze(entry_states || { grammar.start => 0 })
103
112
  validate_entry_states
104
113
  @conflict_summary = IR.deep_freeze(conflict_summary)
105
- @schema_version = schema_version
114
+ @schema_version = SCHEMA_VERSION
115
+ @entry_construction = validate_entry_construction(entry_construction)
116
+ validate_parser_contract
106
117
  freeze
107
118
  end
119
+ private :initialize_current
108
120
 
109
- # @rbs () -> Hash[Symbol, untyped]
121
+ # @rbs () -> Hash[Symbol, Object?]
110
122
  def to_h
111
123
  value = { ibex_ir: "automaton", schema_version: @schema_version, algorithm: @algorithm,
112
124
  grammar_digest: @grammar_digest, grammar: @grammar.to_h,
113
125
  states: @states.map { |state| state.to_h(@grammar) },
114
- conflict_summary: @conflict_summary } #: Hash[Symbol, untyped]
126
+ conflict_summary: @conflict_summary } #: Hash[Symbol, Object?]
115
127
  value[:entry_states] = @entry_states unless @entry_states == { @grammar.start => 0 }
128
+ value[:entry_construction] = @entry_construction
116
129
  value
117
130
  end
118
131
 
@@ -137,6 +150,35 @@ module Ibex
137
150
  require "digest"
138
151
  "sha256:#{Digest::SHA256.hexdigest(IR::Serialize.dump(grammar))}"
139
152
  end
153
+
154
+ # @rbs (String value) -> String
155
+ def validate_entry_construction(value)
156
+ raise Ibex::Error, "entry construction must be shared or isolated" unless %w[shared isolated].include?(value)
157
+
158
+ value.dup.freeze
159
+ end
160
+
161
+ # @rbs () -> void
162
+ def validate_parser_contract
163
+ contract = @grammar.parser_contract
164
+ validate_parser_algorithm(contract)
165
+ validate_parser_entries(contract)
166
+ end
167
+
168
+ # @rbs (ParserContract contract) -> void
169
+ def validate_parser_algorithm(contract)
170
+ selected_algorithm = { "lalr1" => :lalr, "ielr1" => :ielr }.fetch(@algorithm, @algorithm.to_sym)
171
+ return unless contract.algorithm.explicit && contract.algorithm.value != selected_algorithm
172
+
173
+ raise Ibex::Error, "automaton algorithm conflicts with the embedded parser contract"
174
+ end
175
+
176
+ # @rbs (ParserContract contract) -> void
177
+ def validate_parser_entries(contract)
178
+ return unless contract.entries.explicit && contract.entries.value.to_s != @entry_construction
179
+
180
+ raise Ibex::Error, "automaton entry construction conflicts with the embedded parser contract"
181
+ end
140
182
  end
141
183
  end
142
184
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "parser_contract"
4
+
3
5
  module Ibex
4
6
  module IR
5
- SCHEMA_VERSION = 2
6
- SUPPORTED_SCHEMA_VERSIONS = [1, 2].freeze #: Array[Integer]
7
+ # Grammar IR has one active wire format. A future incompatible format
8
+ # change may advance this number, but the runtime never treats old
9
+ # formats as an alternate compatibility surface.
10
+ SCHEMA_VERSION = 1
11
+ SUPPORTED_SCHEMA_VERSIONS = [SCHEMA_VERSION].freeze #: Array[Integer]
7
12
 
8
- # @rbs (untyped value) -> untyped
13
+ # @rbs (Object? value) -> Object?
9
14
  def deep_freeze(value)
10
15
  case value
11
16
  when Array then value.each { |item| deep_freeze(item) }
@@ -52,13 +57,13 @@ module Ibex
52
57
  # @rbs () -> bool
53
58
  def nonterminal? = @kind == :nonterminal
54
59
 
55
- # @rbs (?schema_version: Integer) -> Hash[Symbol, untyped]
56
- def to_h(schema_version: SCHEMA_VERSION)
60
+ # @rbs () -> Hash[Symbol, Object?]
61
+ def to_h
57
62
  value = { id: @id, name: @name, kind: @kind, reserved: @reserved,
58
- prec: @precedence, loc: @location } #: Hash[Symbol, untyped]
63
+ prec: @precedence, loc: @location } #: Hash[Symbol, Object?]
59
64
  value[:display_name] = @display_name if @display_name
60
65
  value[:semantic_type] = @semantic_type if @semantic_type
61
- value[:doc] = @documentation if schema_version >= 2
66
+ value[:doc] = @documentation
62
67
  value
63
68
  end
64
69
  end
@@ -82,11 +87,11 @@ module Ibex
82
87
  freeze
83
88
  end
84
89
 
85
- # @rbs (?schema_version: Integer) -> Hash[Symbol, untyped]
86
- def to_h(schema_version: SCHEMA_VERSION)
90
+ # @rbs () -> Hash[Symbol, Object?]
91
+ def to_h
87
92
  value = { code: @code, loc: @location, named_refs: @named_refs,
88
- context_length: @context_length } #: Hash[Symbol, untyped]
89
- value[:composition] = @composition if schema_version >= 2
93
+ context_length: @context_length } #: Hash[Symbol, Object?]
94
+ value[:composition] = @composition
90
95
  value
91
96
  end
92
97
  end
@@ -98,13 +103,13 @@ module Ibex
98
103
  attr_reader :rhs #: Array[Integer]
99
104
  attr_reader :action #: Action?
100
105
  attr_reader :precedence_override #: Integer?
101
- attr_reader :origin #: Hash[Symbol, untyped]
106
+ attr_reader :origin #: Hash[Symbol, Object?]
102
107
  attr_reader :documentation #: String?
103
108
  attr_reader :expansion #: production_expansion?
104
109
  attr_reader :node #: node_annotation?
105
110
 
106
111
  # @rbs (id: Integer, lhs: Integer, rhs: Array[Integer], action: Action?, precedence_override: Integer?,
107
- # origin: Hash[Symbol, untyped], ?documentation: String?, ?expansion: production_expansion?,
112
+ # origin: Hash[Symbol, Object?], ?documentation: String?, ?expansion: production_expansion?,
108
113
  # ?node: node_annotation?) -> void
109
114
  def initialize(id:, lhs:, rhs:, action:, precedence_override:, origin:, documentation: nil, expansion: nil,
110
115
  node: nil)
@@ -120,15 +125,13 @@ module Ibex
120
125
  freeze
121
126
  end
122
127
 
123
- # @rbs (?schema_version: Integer) -> Hash[Symbol, untyped]
124
- def to_h(schema_version: SCHEMA_VERSION)
125
- value = { id: @id, lhs: @lhs, rhs: @rhs, action: @action&.to_h(schema_version: schema_version),
126
- prec_override: @precedence_override, origin: @origin } #: Hash[Symbol, untyped]
127
- if schema_version >= 2
128
- value[:doc] = @documentation
129
- value[:expansion] = @expansion
130
- value[:node] = @node if @node
131
- end
128
+ # @rbs () -> Hash[Symbol, Object?]
129
+ def to_h
130
+ value = { id: @id, lhs: @lhs, rhs: @rhs, action: @action&.to_h,
131
+ prec_override: @precedence_override, origin: @origin } #: Hash[Symbol, Object?]
132
+ value[:doc] = @documentation
133
+ value[:expansion] = @expansion
134
+ value[:node] = @node if @node
132
135
  value
133
136
  end
134
137
  end
@@ -145,7 +148,7 @@ module Ibex
145
148
  freeze
146
149
  end
147
150
 
148
- # @rbs () -> Hash[Symbol, untyped]
151
+ # @rbs () -> Hash[Symbol, Object?]
149
152
  def to_h
150
153
  { code: @code, loc: @location }
151
154
  end
@@ -174,25 +177,47 @@ module Ibex
174
177
  attr_reader :warnings #: Array[grammar_warning]
175
178
  attr_reader :schema_version #: Integer
176
179
  attr_reader :source_provenance #: source_provenance?
177
- attr_reader :migration #: migration_metadata?
180
+ attr_reader :parser_contract #: ParserContract
178
181
 
179
182
  # @rbs (class_name: String, superclass: String?, start: String, expect: Integer, ?expect_rr: Integer?,
180
183
  # options: grammar_options,
181
184
  # symbols: Array[GrammarSymbol], productions: Array[Production], user_code: Hash[String, String],
182
185
  # conversions: Hash[String, String], warnings: Array[grammar_warning], ?user_code_chunks: user_code_chunks?,
183
- # ?schema_version: Integer, ?source_provenance: source_provenance?,
184
- # ?migration: migration_metadata?, ?parser_parameters: Array[parser_parameter],
186
+ # ?parser_parameters: Array[parser_parameter],
185
187
  # ?value_printers: Array[value_printer], ?grammar_tests: Array[grammar_test],
186
188
  # ?recovery: recovery_policy?, ?lexer: Lexer?,
187
- # ?mode: grammar_mode, ?starts: Array[String]?) -> void
189
+ # ?mode: grammar_mode, ?starts: Array[String]?, ?parser_contract: ParserContract,
190
+ # ?source_provenance: source_provenance?) -> void
188
191
  # rubocop:disable Metrics/AbcSize, Metrics/ParameterLists
189
- # Immutable versioned IR is constructed from explicit public fields.
192
+ # Immutable current IR is constructed from explicit public fields.
190
193
  def initialize(class_name:, superclass:, start:, expect:, options:, symbols:, productions:, user_code:,
191
- conversions:, warnings:, user_code_chunks: nil, schema_version: SCHEMA_VERSION,
192
- source_provenance: nil, migration: nil, expect_rr: nil, parser_parameters: [], value_printers: [],
193
- grammar_tests: [], recovery: nil, lexer: nil, mode: :default, starts: nil)
194
+ conversions:, warnings:, user_code_chunks: nil,
195
+ source_provenance: nil, expect_rr: nil, parser_parameters: [], value_printers: [],
196
+ grammar_tests: [], recovery: nil, lexer: nil, mode: :default, starts: nil,
197
+ parser_contract: ParserContract.new)
198
+ initialize_current(
199
+ class_name: class_name, superclass: superclass, start: start, expect: expect, options: options,
200
+ symbols: symbols, productions: productions, user_code: user_code, conversions: conversions,
201
+ warnings: warnings, user_code_chunks: user_code_chunks,
202
+ source_provenance: source_provenance, expect_rr: expect_rr,
203
+ parser_parameters: parser_parameters, value_printers: value_printers, grammar_tests: grammar_tests,
204
+ recovery: recovery, lexer: lexer, mode: mode, starts: starts, parser_contract: parser_contract
205
+ )
206
+ end
207
+
208
+ # @rbs (class_name: String, superclass: String?, start: String, expect: Integer, options: grammar_options,
209
+ # symbols: Array[GrammarSymbol], productions: Array[Production], user_code: Hash[String, String],
210
+ # conversions: Hash[String, String], warnings: Array[grammar_warning], user_code_chunks: user_code_chunks?,
211
+ # source_provenance: source_provenance?, expect_rr: Integer?, parser_parameters: Array[parser_parameter],
212
+ # value_printers: Array[value_printer], grammar_tests: Array[grammar_test], recovery: recovery_policy?,
213
+ # lexer: Lexer?, mode: grammar_mode, starts: Array[String]?, parser_contract: ParserContract) -> void
214
+ def initialize_current(class_name:, superclass:, start:, expect:, options:, symbols:, productions:, user_code:,
215
+ conversions:, warnings:, user_code_chunks:, source_provenance:, expect_rr:,
216
+ parser_parameters:, value_printers:, grammar_tests:, recovery:, lexer:, mode:, starts:,
217
+ parser_contract:)
194
218
  validate_mode(mode)
195
219
  normalized_starts = validate_starts(start, starts, mode)
220
+ validate_current_metadata(parser_contract)
196
221
 
197
222
  @class_name = class_name.freeze
198
223
  @superclass = superclass&.freeze
@@ -214,14 +239,15 @@ module Ibex
214
239
  validate_user_code_chunks
215
240
  @conversions = IR.deep_freeze(conversions)
216
241
  @warnings = IR.deep_freeze(warnings)
217
- @schema_version = schema_version
242
+ @schema_version = SCHEMA_VERSION
218
243
  @source_provenance = IR.deep_freeze(source_provenance)
219
- @migration = IR.deep_freeze(migration)
244
+ @parser_contract = IR.deep_freeze(parser_contract)
220
245
  @symbols_by_name = @symbols.to_h { |symbol| [symbol.name, symbol] }.freeze
221
246
  @symbols_by_id = @symbols.to_h { |symbol| [symbol.id, symbol] }.freeze
222
247
  freeze
223
248
  end
224
249
  # rubocop:enable Metrics/AbcSize, Metrics/ParameterLists
250
+ private :initialize_current
225
251
 
226
252
  # @rbs (String name) -> GrammarSymbol?
227
253
  def symbol(name) = @symbols_by_name[name]
@@ -232,14 +258,14 @@ module Ibex
232
258
  # @rbs () -> Array[GrammarSymbol]
233
259
  def nonterminals = @symbols.select(&:nonterminal?)
234
260
 
235
- # @rbs () -> Hash[Symbol, untyped]
261
+ # @rbs () -> Hash[Symbol, Object?]
236
262
  def to_h
237
263
  value = { ibex_ir: "grammar", schema_version: @schema_version, class_name: @class_name, superclass: @superclass,
238
264
  start: @start, expect: @expect, options: @options,
239
- symbols: @symbols.map { |symbol| symbol.to_h(schema_version: @schema_version) },
240
- productions: @productions.map { |production| production.to_h(schema_version: @schema_version) },
265
+ symbols: @symbols.map(&:to_h),
266
+ productions: @productions.map(&:to_h),
241
267
  user_code: @user_code, conversions: @conversions,
242
- warnings: @warnings } #: Hash[Symbol, untyped]
268
+ warnings: @warnings } #: Hash[Symbol, Object?]
243
269
  append_optional_metadata(value)
244
270
  value
245
271
  end
@@ -262,30 +288,28 @@ module Ibex
262
288
  values
263
289
  end
264
290
 
265
- # @rbs (Hash[Symbol, untyped] value) -> void
291
+ # @rbs (Hash[Symbol, Object?] value) -> void
266
292
  def append_optional_metadata(value)
267
293
  append_parser_metadata(value)
268
294
  append_recovery_metadata(value)
269
295
  value[:user_code_chunks] = @user_code_chunks.transform_values { |chunks| chunks.map(&:to_h) } \
270
296
  unless @user_code_chunks.empty?
271
- return unless @schema_version >= 2
272
-
273
297
  value[:source_provenance] = @source_provenance
274
- value[:migration] = @migration
298
+ value[:parser_contract] = @parser_contract.to_h
275
299
  end
276
300
 
277
- # @rbs (Hash[Symbol, untyped] value) -> void
301
+ # @rbs (Hash[Symbol, Object?] value) -> void
278
302
  def append_parser_metadata(value)
279
303
  value[:expect_rr] = @expect_rr unless @expect_rr.nil?
280
304
  value[:mode] = @mode if @mode == :extended
281
305
  value[:starts] = @starts if @starts.length > 1
282
306
  value[:params] = @parser_parameters unless @parser_parameters.empty?
283
307
  value[:printers] = @value_printers unless @value_printers.empty?
284
- value[:tests] = @grammar_tests unless @grammar_tests.empty? || @schema_version < 2
285
- value[:lexer] = @lexer.to_h if @lexer && @schema_version >= 2
308
+ value[:tests] = @grammar_tests unless @grammar_tests.empty?
309
+ value[:lexer] = @lexer.to_h if @lexer
286
310
  end
287
311
 
288
- # @rbs (Hash[Symbol, untyped] value) -> void
312
+ # @rbs (Hash[Symbol, Object?] value) -> void
289
313
  def append_recovery_metadata(value)
290
314
  return if @recovery[:sync_tokens].empty? && @recovery[:on_error_reduce].empty?
291
315
 
@@ -300,6 +324,13 @@ module Ibex
300
324
  raise Ibex::Error, "(ir):1:1: user-code chunks do not match the concatenated #{name} section"
301
325
  end
302
326
  end
327
+
328
+ # @rbs (ParserContract parser_contract) -> void
329
+ def validate_current_metadata(parser_contract)
330
+ return if parser_contract.is_a?(ParserContract)
331
+
332
+ raise ArgumentError, "parser_contract must be a ParserContract"
333
+ end
303
334
  end
304
335
  end
305
336
  end
@@ -32,7 +32,7 @@ module Ibex
32
32
  freeze
33
33
  end
34
34
 
35
- # @rbs () -> Hash[Symbol, untyped]
35
+ # @rbs () -> Hash[Symbol, lexer_rule_document_value]
36
36
  def to_h
37
37
  {
38
38
  id: @id, state: @state, kind: @kind, token: @token, pattern: @pattern,
@@ -41,15 +41,15 @@ module Ibex
41
41
  end
42
42
  end
43
43
 
44
- # Independently versioned lexer contract embedded by Grammar IR v2.
44
+ # Independently versioned lexer contract embedded by the current Grammar IR.
45
45
  class Lexer
46
46
  attr_reader :states #: Array[String]
47
47
  attr_reader :rules #: Array[LexerRule]
48
- attr_reader :warnings #: Array[Hash[Symbol, untyped]]
48
+ attr_reader :warnings #: Array[lexer_warning]
49
49
  attr_reader :schema_version #: Integer
50
50
  attr_reader :source_provenance #: source_provenance?
51
51
 
52
- # @rbs (states: Array[String], rules: Array[LexerRule], warnings: Array[Hash[Symbol, untyped]],
52
+ # @rbs (states: Array[String], rules: Array[LexerRule], warnings: Array[lexer_warning],
53
53
  # ?schema_version: Integer, ?source_provenance: source_provenance?) -> void
54
54
  def initialize(states:, rules:, warnings:, schema_version: LEXER_SCHEMA_VERSION, source_provenance: nil)
55
55
  raise ArgumentError, "lexer states must start with INITIAL" unless states.first == "INITIAL"
@@ -63,7 +63,7 @@ module Ibex
63
63
  freeze
64
64
  end
65
65
 
66
- # @rbs () -> Hash[Symbol, untyped]
66
+ # @rbs () -> Hash[Symbol, lexer_document_value]
67
67
  def to_h
68
68
  {
69
69
  ibex_ir: "lexer", schema_version: @schema_version, initial_state: "INITIAL",
@@ -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