ibex 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -123
  3. data/docs/architecture.md +477 -31
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +106 -0
  12. data/docs/cst.md +237 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +262 -0
  40. data/docs/development.md +306 -0
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +26 -0
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1581 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +114 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +629 -18
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/ja/bison-import.md +51 -0
  56. data/docs/ja/stable-api.md +53 -0
  57. data/docs/lexer-construction-profile.md +109 -0
  58. data/docs/lexer-migration.md +56 -0
  59. data/docs/maturity.md +128 -0
  60. data/docs/project-site-strategy.md +54 -0
  61. data/docs/racc-migration-evidence.md +45 -0
  62. data/docs/racc-migration.md +45 -6
  63. data/docs/release-readiness.md +221 -0
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +234 -0
  67. data/docs/status.md +43 -0
  68. data/docs/syntax-sessions.md +183 -0
  69. data/docs/table-artifact.md +125 -0
  70. data/docs/test-interactions.md +219 -0
  71. data/docs/verification-report.md +137 -0
  72. data/docs/verifier-trust-boundary.md +199 -0
  73. data/docs/workloads.md +132 -0
  74. data/examples/README.md +60 -0
  75. data/examples/calculator.y +44 -0
  76. data/examples/csv.y +32 -0
  77. data/examples/ini.y +70 -0
  78. data/examples/json.y +48 -0
  79. data/examples/tiny_language.y +75 -0
  80. data/lib/ibex/analysis/digraph.rb +128 -0
  81. data/lib/ibex/analysis/sets.rb +5 -4
  82. data/lib/ibex/analysis.rb +1 -0
  83. data/lib/ibex/artifact_set.rb +63 -0
  84. data/lib/ibex/bison_import/importer.rb +516 -0
  85. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  86. data/lib/ibex/bison_import.rb +200 -0
  87. data/lib/ibex/bounded_subprocess.rb +171 -0
  88. data/lib/ibex/cli/ambiguity.rb +75 -0
  89. data/lib/ibex/cli/analysis.rb +134 -0
  90. data/lib/ibex/cli/bison_import.rb +121 -0
  91. data/lib/ibex/cli/config.rb +128 -0
  92. data/lib/ibex/cli/counterexample_options.rb +6 -2
  93. data/lib/ibex/cli/coverage.rb +173 -0
  94. data/lib/ibex/cli/debug.rb +106 -0
  95. data/lib/ibex/cli/diagnostics.rb +136 -0
  96. data/lib/ibex/cli/documentation.rb +70 -0
  97. data/lib/ibex/cli/equiv.rb +169 -0
  98. data/lib/ibex/cli/error_messages.rb +184 -0
  99. data/lib/ibex/cli/explain.rb +85 -0
  100. data/lib/ibex/cli/fix.rb +203 -0
  101. data/lib/ibex/cli/formatting.rb +387 -0
  102. data/lib/ibex/cli/fuzz.rb +200 -0
  103. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  104. data/lib/ibex/cli/generation_artifacts.rb +189 -0
  105. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  106. data/lib/ibex/cli/grammar_tests.rb +140 -0
  107. data/lib/ibex/cli/ir_tools.rb +128 -0
  108. data/lib/ibex/cli/lsp.rb +33 -0
  109. data/lib/ibex/cli/outputs.rb +133 -23
  110. data/lib/ibex/cli/racc_migration.rb +87 -0
  111. data/lib/ibex/cli/reduce.rb +202 -0
  112. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  113. data/lib/ibex/cli/samples.rb +118 -0
  114. data/lib/ibex/cli/verify.rb +116 -0
  115. data/lib/ibex/cli/watch.rb +104 -0
  116. data/lib/ibex/cli.rb +825 -55
  117. data/lib/ibex/codegen/action_locations.rb +103 -0
  118. data/lib/ibex/codegen/action_method_source.rb +209 -0
  119. data/lib/ibex/codegen/action_source.rb +119 -0
  120. data/lib/ibex/codegen/ambiguity.rb +174 -0
  121. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  122. data/lib/ibex/codegen/documentation.rb +170 -0
  123. data/lib/ibex/codegen/explain.rb +380 -0
  124. data/lib/ibex/codegen/generated_action_abi.rb +293 -0
  125. data/lib/ibex/codegen/html.rb +94 -10
  126. data/lib/ibex/codegen/mermaid.rb +43 -0
  127. data/lib/ibex/codegen/railroad.rb +197 -0
  128. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  129. data/lib/ibex/codegen/rbs.rb +331 -2
  130. data/lib/ibex/codegen/report.rb +67 -15
  131. data/lib/ibex/codegen/ruby.rb +305 -66
  132. data/lib/ibex/codegen/ruby_actions.rb +146 -0
  133. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  134. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  135. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  136. data/lib/ibex/codegen/ruby_syntax.rb +96 -0
  137. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  138. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  139. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  140. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  141. data/lib/ibex/configuration/explanation.rb +421 -0
  142. data/lib/ibex/configuration/inspector.rb +232 -0
  143. data/lib/ibex/configuration.rb +580 -0
  144. data/lib/ibex/coverage/collector.rb +198 -0
  145. data/lib/ibex/coverage/event_stream.rb +103 -0
  146. data/lib/ibex/coverage/report.rb +267 -0
  147. data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
  148. data/lib/ibex/coverage.rb +13 -0
  149. data/lib/ibex/delta_reducer.rb +99 -0
  150. data/lib/ibex/diff.rb +140 -0
  151. data/lib/ibex/equiv/machine.rb +135 -0
  152. data/lib/ibex/equiv.rb +373 -0
  153. data/lib/ibex/error_messages/parser.rb +159 -0
  154. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  155. data/lib/ibex/error_messages/renderer.rb +65 -0
  156. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  157. data/lib/ibex/error_messages/update.rb +169 -0
  158. data/lib/ibex/error_messages.rb +165 -0
  159. data/lib/ibex/fix.rb +557 -0
  160. data/lib/ibex/frontend/ast.rb +166 -7
  161. data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
  162. data/lib/ibex/frontend/diagnostic.rb +81 -0
  163. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  164. data/lib/ibex/frontend/dsl.rb +66 -7
  165. data/lib/ibex/frontend/formatter.rb +453 -0
  166. data/lib/ibex/frontend/generated_parser.rb +644 -190
  167. data/lib/ibex/frontend/generated_parser_base.rb +170 -32
  168. data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
  169. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  170. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  171. data/lib/ibex/frontend/generation.rb +33 -0
  172. data/lib/ibex/frontend/lexer.rb +162 -10
  173. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  174. data/lib/ibex/frontend/parser/declarations.rb +262 -11
  175. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  176. data/lib/ibex/frontend/parser/rules.rb +43 -6
  177. data/lib/ibex/frontend/parser.rb +182 -4
  178. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  179. data/lib/ibex/frontend/regenerator.rb +27 -1
  180. data/lib/ibex/frontend/resolution.rb +70 -0
  181. data/lib/ibex/frontend/resolver.rb +217 -0
  182. data/lib/ibex/frontend/rule_documentation.rb +104 -0
  183. data/lib/ibex/frontend/source_cursor.rb +133 -9
  184. data/lib/ibex/frontend/source_document.rb +229 -0
  185. data/lib/ibex/frontend/source_loader.rb +150 -0
  186. data/lib/ibex/frontend/source_span.rb +89 -0
  187. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  188. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  189. data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
  190. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  191. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  192. data/lib/ibex/frontend/token_adapter.rb +18 -3
  193. data/lib/ibex/frontend.rb +14 -2
  194. data/lib/ibex/fuzz.rb +219 -0
  195. data/lib/ibex/generation_input.rb +57 -0
  196. data/lib/ibex/generation_manifest.rb +211 -0
  197. data/lib/ibex/generation_transaction.rb +261 -0
  198. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  199. data/lib/ibex/generation_transaction_validation.rb +196 -0
  200. data/lib/ibex/grammar_tests.rb +206 -0
  201. data/lib/ibex/ir/automaton_ir.rb +86 -11
  202. data/lib/ibex/ir/grammar_ir.rb +170 -26
  203. data/lib/ibex/ir/lexer_ir.rb +76 -0
  204. data/lib/ibex/ir/parser_contract.rb +135 -0
  205. data/lib/ibex/ir/serialize.rb +268 -50
  206. data/lib/ibex/ir/validator/automaton.rb +375 -0
  207. data/lib/ibex/ir/validator/base.rb +147 -0
  208. data/lib/ibex/ir/validator/grammar.rb +634 -0
  209. data/lib/ibex/ir/validator/lexer.rb +113 -0
  210. data/lib/ibex/ir/validator.rb +63 -0
  211. data/lib/ibex/ir.rb +71 -5
  212. data/lib/ibex/lalr/build_metrics.rb +71 -0
  213. data/lib/ibex/lalr/builder.rb +514 -52
  214. data/lib/ibex/lalr/conflict.rb +1 -0
  215. data/lib/ibex/lalr/conflict_search.rb +26 -9
  216. data/lib/ibex/lalr/counterexample.rb +38 -18
  217. data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
  218. data/lib/ibex/lalr/goto_follows.rb +229 -0
  219. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  220. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  221. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  222. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  223. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  224. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  225. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  226. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  227. data/lib/ibex/lalr/ielr_partition.rb +166 -0
  228. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  229. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  230. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  231. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  232. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  233. data/lib/ibex/lalr.rb +59 -1
  234. data/lib/ibex/location.rb +129 -0
  235. data/lib/ibex/lsp/document_handlers.rb +68 -0
  236. data/lib/ibex/lsp/document_store.rb +264 -0
  237. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  238. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  239. data/lib/ibex/lsp/initialization_handlers.rb +80 -0
  240. data/lib/ibex/lsp/navigation_handlers.rb +70 -0
  241. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  242. data/lib/ibex/lsp/position_codec.rb +113 -0
  243. data/lib/ibex/lsp/protocol_error.rb +33 -0
  244. data/lib/ibex/lsp/request_handlers.rb +46 -0
  245. data/lib/ibex/lsp/request_support.rb +94 -0
  246. data/lib/ibex/lsp/server.rb +148 -0
  247. data/lib/ibex/lsp/symbol_index.rb +241 -0
  248. data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
  249. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  250. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  251. data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
  252. data/lib/ibex/lsp/transport.rb +128 -0
  253. data/lib/ibex/lsp/workspace.rb +128 -0
  254. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  255. data/lib/ibex/lsp.rb +33 -0
  256. data/lib/ibex/messages/en.yml +28 -0
  257. data/lib/ibex/messages/ja.yml +28 -0
  258. data/lib/ibex/messages.rb +68 -0
  259. data/lib/ibex/metrics.rb +175 -0
  260. data/lib/ibex/normalize/declarations.rb +142 -7
  261. data/lib/ibex/normalize/diagnostics.rb +94 -24
  262. data/lib/ibex/normalize/expander.rb +64 -59
  263. data/lib/ibex/normalize/expression.rb +63 -40
  264. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  265. data/lib/ibex/normalize/inline_expansion.rb +465 -0
  266. data/lib/ibex/normalize/inline_validation.rb +174 -0
  267. data/lib/ibex/normalize/lexer.rb +131 -0
  268. data/lib/ibex/normalize/named_references.rb +60 -0
  269. data/lib/ibex/normalize/nodes.rb +46 -0
  270. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
  271. data/lib/ibex/normalize/parameter_lowering.rb +143 -0
  272. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  273. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  274. data/lib/ibex/normalize/parameters.rb +226 -0
  275. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  276. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  277. data/lib/ibex/normalize.rb +172 -17
  278. data/lib/ibex/racc_migration/checker.rb +122 -0
  279. data/lib/ibex/racc_migration/harness.rb +177 -0
  280. data/lib/ibex/racc_migration/report.rb +97 -0
  281. data/lib/ibex/racc_migration.rb +12 -0
  282. data/lib/ibex/rake_task.rb +116 -0
  283. data/lib/ibex/samples.rb +216 -0
  284. data/lib/ibex/table_artifact/builder.rb +266 -0
  285. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  286. data/lib/ibex/table_artifact/document.rb +39 -0
  287. data/lib/ibex/table_artifact/executor.rb +187 -0
  288. data/lib/ibex/table_artifact/serializer.rb +57 -0
  289. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  290. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  291. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  292. data/lib/ibex/table_artifact/validator.rb +253 -0
  293. data/lib/ibex/table_artifact.rb +88 -0
  294. data/lib/ibex/table_simulation/result.rb +55 -0
  295. data/lib/ibex/table_simulation/simulator.rb +253 -0
  296. data/lib/ibex/table_simulation/step.rb +62 -0
  297. data/lib/ibex/table_simulation/text.rb +31 -0
  298. data/lib/ibex/table_simulation.rb +13 -0
  299. data/lib/ibex/tables.rb +22 -69
  300. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  301. data/lib/ibex/verification_report/builder.rb +159 -0
  302. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  303. data/lib/ibex/verification_report/logical_path.rb +68 -0
  304. data/lib/ibex/verification_report/validator.rb +329 -0
  305. data/lib/ibex/verification_report.rb +69 -0
  306. data/lib/ibex/verify/action_correspondence.rb +138 -0
  307. data/lib/ibex/verify/language_witness.rb +295 -0
  308. data/lib/ibex/verify/reference_collection.rb +190 -0
  309. data/lib/ibex/verify/result.rb +73 -0
  310. data/lib/ibex/verify/verifier.rb +598 -0
  311. data/lib/ibex/verify.rb +15 -0
  312. data/lib/ibex/version.rb +1 -1
  313. data/lib/ibex/watch/runner.rb +181 -0
  314. data/lib/ibex/watch/source_snapshot.rb +98 -0
  315. data/lib/ibex/watch.rb +11 -0
  316. data/lib/ibex.rb +35 -1
  317. data/schema/automaton-ir-definitions.schema.json +401 -0
  318. data/schema/automaton-ir.schema.json +65 -0
  319. data/schema/benchmark-v1.schema.json +212 -0
  320. data/schema/benchmark-v2.schema.json +61 -0
  321. data/schema/bison-import-v1.schema.json +106 -0
  322. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  323. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  324. data/schema/construction-profile-v1.schema.json +779 -0
  325. data/schema/cst-v1.json +170 -0
  326. data/schema/diff-v1.schema.json +41 -0
  327. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  328. data/schema/equiv-v1.schema.json +64 -0
  329. data/schema/error-ux-review-v1.schema.json +609 -0
  330. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  331. data/schema/error-ux-round2-v1.schema.json +519 -0
  332. data/schema/error-ux-v1.schema.json +258 -0
  333. data/schema/explain-v1.schema.json +495 -0
  334. data/schema/fix-v1.schema.json +64 -0
  335. data/schema/fix-v2.schema.json +66 -0
  336. data/schema/fix-v3.schema.json +101 -0
  337. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  338. data/schema/fuzz-regression-v1.schema.json +79 -0
  339. data/schema/fuzz-v1.schema.json +114 -0
  340. data/schema/generation-manifest-v1.schema.json +115 -0
  341. data/schema/grammar-ir-extensions.schema.json +734 -0
  342. data/schema/grammar-ir-foundation.schema.json +426 -0
  343. data/schema/grammar-ir.schema.json +271 -0
  344. data/schema/ielr-benchmark-v1.schema.json +85 -0
  345. data/schema/lexer-ir-v1.schema.json +215 -0
  346. data/schema/lexer-profile-v1.schema.json +491 -0
  347. data/schema/metrics-v1.schema.json +60 -0
  348. data/schema/migration-check-v1.schema.json +60 -0
  349. data/schema/performance-comparison-v1.schema.json +395 -0
  350. data/schema/public-performance-comparison-v1.schema.json +506 -0
  351. data/schema/public-performance-profile-v1.schema.json +360 -0
  352. data/schema/reduce-v1.schema.json +22 -0
  353. data/schema/reduce-v2.schema.json +63 -0
  354. data/schema/runtime-coverage-v1.schema.json +86 -0
  355. data/schema/runtime-event-v1.schema.json +308 -0
  356. data/schema/table-artifact-v1.schema.json +377 -0
  357. data/schema/table-simulation-v1.schema.json +70 -0
  358. data/schema/verification-report-v1.schema.json +222 -0
  359. data/schema/verify-v1.schema.json +42 -0
  360. data/sig/ibex/analysis/digraph.rbs +19 -0
  361. data/sig/ibex/artifact_set.rbs +37 -0
  362. data/sig/ibex/bison_import/importer.rbs +140 -0
  363. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  364. data/sig/ibex/bison_import.rbs +95 -0
  365. data/sig/ibex/bounded_subprocess.rbs +76 -0
  366. data/sig/ibex/cli/ambiguity.rbs +28 -0
  367. data/sig/ibex/cli/analysis.rbs +43 -0
  368. data/sig/ibex/cli/bison_import.rbs +32 -0
  369. data/sig/ibex/cli/config.rbs +35 -0
  370. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  371. data/sig/ibex/cli/coverage.rbs +53 -0
  372. data/sig/ibex/cli/debug.rbs +28 -0
  373. data/sig/ibex/cli/diagnostics.rbs +51 -0
  374. data/sig/ibex/cli/documentation.rbs +29 -0
  375. data/sig/ibex/cli/equiv.rbs +49 -0
  376. data/sig/ibex/cli/error_messages.rbs +63 -0
  377. data/sig/ibex/cli/explain.rbs +31 -0
  378. data/sig/ibex/cli/fix.rbs +53 -0
  379. data/sig/ibex/cli/formatting.rbs +107 -0
  380. data/sig/ibex/cli/fuzz.rbs +47 -0
  381. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  382. data/sig/ibex/cli/generation_artifacts.rbs +69 -0
  383. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  384. data/sig/ibex/cli/grammar_tests.rbs +48 -0
  385. data/sig/ibex/cli/ir_tools.rbs +39 -0
  386. data/sig/ibex/cli/lsp.rbs +14 -0
  387. data/sig/ibex/cli/outputs.rbs +26 -3
  388. data/sig/ibex/cli/racc_migration.rbs +30 -0
  389. data/sig/ibex/cli/reduce.rbs +60 -0
  390. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  391. data/sig/ibex/cli/samples.rbs +38 -0
  392. data/sig/ibex/cli/verify.rbs +28 -0
  393. data/sig/ibex/cli/watch.rbs +43 -0
  394. data/sig/ibex/cli.rbs +182 -9
  395. data/sig/ibex/codegen/action_locations.rbs +45 -0
  396. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  397. data/sig/ibex/codegen/action_source.rbs +50 -0
  398. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  399. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  400. data/sig/ibex/codegen/documentation.rbs +50 -0
  401. data/sig/ibex/codegen/explain.rbs +105 -0
  402. data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
  403. data/sig/ibex/codegen/html.rbs +18 -2
  404. data/sig/ibex/codegen/mermaid.rbs +16 -0
  405. data/sig/ibex/codegen/railroad.rbs +82 -0
  406. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  407. data/sig/ibex/codegen/rbs.rbs +86 -4
  408. data/sig/ibex/codegen/report.rbs +16 -8
  409. data/sig/ibex/codegen/ruby.rbs +105 -28
  410. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  411. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  412. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  413. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  414. data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
  415. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  416. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  417. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  418. data/sig/ibex/configuration/explanation.rbs +195 -0
  419. data/sig/ibex/configuration/inspector.rbs +53 -0
  420. data/sig/ibex/configuration.rbs +242 -0
  421. data/sig/ibex/coverage/collector.rbs +78 -0
  422. data/sig/ibex/coverage/event_stream.rbs +44 -0
  423. data/sig/ibex/coverage/report.rbs +102 -0
  424. data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
  425. data/sig/ibex/coverage.rbs +7 -0
  426. data/sig/ibex/delta_reducer.rbs +38 -0
  427. data/sig/ibex/diff.rbs +47 -0
  428. data/sig/ibex/equiv/machine.rbs +54 -0
  429. data/sig/ibex/equiv.rbs +129 -0
  430. data/sig/ibex/error_messages/parser.rbs +58 -0
  431. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  432. data/sig/ibex/error_messages/renderer.rbs +23 -0
  433. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  434. data/sig/ibex/error_messages/update.rbs +43 -0
  435. data/sig/ibex/error_messages.rbs +85 -0
  436. data/sig/ibex/fix.rbs +138 -0
  437. data/sig/ibex/frontend/ast.rbs +237 -22
  438. data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
  439. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  440. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  441. data/sig/ibex/frontend/dsl.rbs +33 -4
  442. data/sig/ibex/frontend/formatter.rbs +143 -0
  443. data/sig/ibex/frontend/generated_parser.rbs +228 -68
  444. data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
  445. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  446. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  447. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  448. data/sig/ibex/frontend/generation.rbs +6 -0
  449. data/sig/ibex/frontend/lexer.rbs +49 -2
  450. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  451. data/sig/ibex/frontend/parser/declarations.rbs +57 -0
  452. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  453. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  454. data/sig/ibex/frontend/parser.rbs +66 -0
  455. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  456. data/sig/ibex/frontend/regenerator.rbs +11 -0
  457. data/sig/ibex/frontend/resolution.rbs +34 -0
  458. data/sig/ibex/frontend/resolver.rbs +91 -0
  459. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  460. data/sig/ibex/frontend/source_cursor.rbs +38 -5
  461. data/sig/ibex/frontend/source_document.rbs +119 -0
  462. data/sig/ibex/frontend/source_loader.rbs +66 -0
  463. data/sig/ibex/frontend/source_span.rbs +56 -0
  464. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  465. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  466. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
  467. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  468. data/sig/ibex/frontend/token_adapter.rbs +11 -2
  469. data/sig/ibex/frontend.rbs +1 -1
  470. data/sig/ibex/fuzz.rbs +71 -0
  471. data/sig/ibex/generation_input.rbs +37 -0
  472. data/sig/ibex/generation_manifest.rbs +70 -0
  473. data/sig/ibex/generation_transaction.rbs +82 -0
  474. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  475. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  476. data/sig/ibex/grammar_tests.rbs +93 -0
  477. data/sig/ibex/ir/automaton_ir.rbs +35 -10
  478. data/sig/ibex/ir/grammar_ir.rbs +96 -22
  479. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  480. data/sig/ibex/ir/parser_contract.rbs +69 -0
  481. data/sig/ibex/ir/serialize.rbs +75 -23
  482. data/sig/ibex/ir/validator/automaton.rbs +112 -0
  483. data/sig/ibex/ir/validator/base.rbs +69 -0
  484. data/sig/ibex/ir/validator/grammar.rbs +195 -0
  485. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  486. data/sig/ibex/ir/validator.rbs +16 -0
  487. data/sig/ibex/ir.rbs +45 -5
  488. data/sig/ibex/lalr/build_metrics.rbs +60 -0
  489. data/sig/ibex/lalr/builder.rbs +150 -19
  490. data/sig/ibex/lalr/conflict_search.rbs +12 -5
  491. data/sig/ibex/lalr/counterexample.rbs +20 -14
  492. data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
  493. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  494. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  495. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  496. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  497. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  498. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  499. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  500. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  501. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  502. data/sig/ibex/lalr/ielr_partition.rbs +71 -0
  503. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  504. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  505. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  506. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  507. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  508. data/sig/ibex/lalr.rbs +17 -1
  509. data/sig/ibex/location.rbs +67 -0
  510. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  511. data/sig/ibex/lsp/document_store.rbs +94 -0
  512. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  513. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  514. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  515. data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
  516. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  517. data/sig/ibex/lsp/position_codec.rbs +44 -0
  518. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  519. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  520. data/sig/ibex/lsp/request_support.rbs +40 -0
  521. data/sig/ibex/lsp/server.rbs +55 -0
  522. data/sig/ibex/lsp/symbol_index.rbs +77 -0
  523. data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
  524. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  525. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  526. data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
  527. data/sig/ibex/lsp/transport.rbs +47 -0
  528. data/sig/ibex/lsp/workspace.rbs +42 -0
  529. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  530. data/sig/ibex/lsp.rbs +7 -0
  531. data/sig/ibex/messages.rbs +26 -0
  532. data/sig/ibex/metrics.rbs +50 -0
  533. data/sig/ibex/normalize/declarations.rbs +31 -0
  534. data/sig/ibex/normalize/diagnostics.rbs +13 -4
  535. data/sig/ibex/normalize/expander.rbs +22 -16
  536. data/sig/ibex/normalize/expression.rbs +11 -9
  537. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  538. data/sig/ibex/normalize/inline_expansion.rbs +129 -0
  539. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  540. data/sig/ibex/normalize/lexer.rbs +37 -0
  541. data/sig/ibex/normalize/named_references.rbs +20 -0
  542. data/sig/ibex/normalize/nodes.rbs +14 -0
  543. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
  544. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  545. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  546. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  547. data/sig/ibex/normalize/parameters.rbs +51 -0
  548. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  549. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  550. data/sig/ibex/normalize.rbs +129 -18
  551. data/sig/ibex/racc_migration/checker.rbs +36 -0
  552. data/sig/ibex/racc_migration/harness.rbs +16 -0
  553. data/sig/ibex/racc_migration/report.rbs +55 -0
  554. data/sig/ibex/racc_migration.rbs +8 -0
  555. data/sig/ibex/rake_task.rbs +51 -0
  556. data/sig/ibex/samples.rbs +60 -0
  557. data/sig/ibex/table_artifact/builder.rbs +93 -0
  558. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  559. data/sig/ibex/table_artifact/document.rbs +27 -0
  560. data/sig/ibex/table_artifact/executor.rbs +66 -0
  561. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  562. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  563. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  564. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  565. data/sig/ibex/table_artifact/validator.rbs +66 -0
  566. data/sig/ibex/table_artifact.rbs +32 -0
  567. data/sig/ibex/table_simulation/result.rbs +36 -0
  568. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  569. data/sig/ibex/table_simulation/step.rbs +42 -0
  570. data/sig/ibex/table_simulation/text.rbs +14 -0
  571. data/sig/ibex/table_simulation.rbs +7 -0
  572. data/sig/ibex/tables.rbs +10 -35
  573. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  574. data/sig/ibex/verification_report/builder.rbs +53 -0
  575. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  576. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  577. data/sig/ibex/verification_report/validator.rbs +114 -0
  578. data/sig/ibex/verification_report.rbs +44 -0
  579. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  580. data/sig/ibex/verify/language_witness.rbs +112 -0
  581. data/sig/ibex/verify/reference_collection.rbs +63 -0
  582. data/sig/ibex/verify/result.rbs +52 -0
  583. data/sig/ibex/verify/verifier.rbs +170 -0
  584. data/sig/ibex/verify.rbs +6 -0
  585. data/sig/ibex/watch/runner.rbs +58 -0
  586. data/sig/ibex/watch/source_snapshot.rbs +46 -0
  587. data/sig/ibex/watch.rbs +7 -0
  588. data/sig/ibex.rbs +2 -0
  589. metadata +524 -19
  590. data/.rubocop.yml +0 -43
  591. data/CHANGELOG.md +0 -30
  592. data/Rakefile +0 -25
  593. data/Steepfile +0 -10
  594. data/docs/compat-notes.md +0 -37
  595. data/docs/lexer-coverage.md +0 -14
  596. data/docs/phase10-extensions.md +0 -27
  597. data/gemfiles/Gemfile +0 -7
  598. data/gemfiles/Gemfile.lock +0 -98
  599. data/lib/ibex/frontend/grammar.y +0 -156
  600. data/lib/ibex/runtime/parser.rb +0 -360
  601. data/lib/ibex/runtime.rb +0 -8
  602. data/sig/ibex/runtime/parser.rbs +0 -167
  603. data/sig/ibex/runtime.rbs +0 -6
@@ -1,18 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "generated_action_abi"
4
+ require_relative "cst_metadata"
5
+
3
6
  module Ibex
4
7
  module Codegen
5
8
  # Generates an RBS declaration for the public surface of a generated parser.
9
+ # rubocop:disable Metrics/ClassLength -- one generator owns the complete parser signature.
6
10
  class RBS
11
+ # @rbs!
12
+ # type syntax_definition = { name: String, kind: Integer, fields: Hash[String, CSTMetadata::field_slot] }
13
+
7
14
  # @rbs @automaton: IR::Automaton
8
15
  # @rbs @grammar: IR::Grammar
9
16
  # @rbs @superclass: String
17
+ # @rbs @omit_action_call: bool
18
+ # @rbs @generated_action_abi: GeneratedActionABI::Cache
10
19
 
11
- # @rbs (IR::Automaton automaton, ?superclass: String?) -> void
12
- def initialize(automaton, superclass: nil)
20
+ # @rbs (IR::Automaton automaton, ?superclass: String?, ?omit_action_call: bool?) -> void
21
+ def initialize(automaton, superclass: nil, omit_action_call: nil)
13
22
  @automaton = automaton
14
23
  @grammar = automaton.grammar
15
24
  @superclass = superclass || @grammar.superclass || "Ibex::Runtime::Parser"
25
+ @omit_action_call = omit_action_call.nil? ? @grammar.options[:omit_action_call] : omit_action_call
26
+ @generated_action_abi = GeneratedActionABI::Cache.new
16
27
  end
17
28
 
18
29
  # @rbs () -> String
@@ -21,7 +32,12 @@ module Ibex
21
32
  modules, class_name = class_parts
22
33
  modules.each { |name| lines << "module #{name}" }
23
34
  lines << "class #{class_name} < #{@superclass}"
35
+ append_ast_contract(lines)
36
+ append_syntax_contract(lines)
24
37
  append_contract(lines)
38
+ append_lexer_contract(lines)
39
+ append_value_printer_signatures(lines)
40
+ append_actions(lines)
25
41
  lines << "end"
26
42
  modules.reverse_each { lines << "end" }
27
43
  "#{lines.join("\n")}\n"
@@ -29,14 +45,326 @@ module Ibex
29
45
 
30
46
  private
31
47
 
48
+ # @rbs (Array[String] lines) -> void
49
+ def append_ast_contract(lines)
50
+ definitions = ast_node_definitions
51
+ return if definitions.empty?
52
+
53
+ lines << " module AST"
54
+ definitions.each_value { |node| append_ast_node_contract(lines, node) }
55
+ append_visitor_contract(lines, definitions)
56
+ append_listener_contract(lines, definitions)
57
+ lines.push(" end", "")
58
+ end
59
+
60
+ # @rbs (Array[String] lines) -> void
61
+ def append_syntax_contract(lines)
62
+ definitions = syntax_node_definitions
63
+ return if definitions.empty? || @grammar.options[:cst] != true
64
+
65
+ lines << " module Syntax"
66
+ definitions.each_value { |definition| append_syntax_node_contract(lines, definition) }
67
+ lines.push(" end", "")
68
+ end
69
+
70
+ # @rbs () -> Hash[String, syntax_definition]
71
+ def syntax_node_definitions
72
+ metadata = CSTMetadata.new(@grammar).build
73
+ slots = metadata.fetch(:slots)
74
+ definitions = {} #: Hash[String, syntax_definition]
75
+ @grammar.productions.each do |production|
76
+ node = production.node
77
+ next unless node
78
+
79
+ slot = slots.fetch(production.id)
80
+ name = node.fetch(:name)
81
+ previous = definitions[name]
82
+ fields = previous ? merge_syntax_fields(previous.fetch(:fields), slot.fetch(:fields)) : slot.fetch(:fields)
83
+ definition = { name: name, kind: slot.fetch(:node_kind), fields: fields }.freeze #: syntax_definition
84
+ definitions[name] = definition
85
+ end
86
+ definitions
87
+ end
88
+
89
+ # @rbs (Hash[String, CSTMetadata::field_slot] left, Hash[String, CSTMetadata::field_slot] right) -> Hash[String, CSTMetadata::field_slot]
90
+ def merge_syntax_fields(left, right)
91
+ left.to_h do |name, left_slot|
92
+ right_slot = right.fetch(name)
93
+ left_index = left_slot.is_a?(Hash) ? left_slot.fetch(:index) : left_slot
94
+ right_index = right_slot.is_a?(Hash) ? right_slot.fetch(:index) : right_slot
95
+ raise Ibex::Error, "inconsistent CST slot for #{name}" unless left_index == right_index
96
+
97
+ [name, left_slot == right_slot ? left_slot : left_index]
98
+ end.freeze
99
+ end
100
+
101
+ # @rbs (Array[String] lines, syntax_definition definition) -> void
102
+ def append_syntax_node_contract(lines, definition)
103
+ name = definition.fetch(:name)
104
+ fields = definition.fetch(:fields)
105
+ lines.push(
106
+ " class #{name} < Ibex::Runtime::CST::TypedNode",
107
+ " KIND: Integer",
108
+ " def self.cast: (Ibex::Runtime::CST::SyntaxNode node) -> #{name}?"
109
+ )
110
+ fields.each_with_index do |(field, _slot), index|
111
+ lines << " def #{field}: () -> #{syntax_field_type(name, index)}"
112
+ end
113
+ append_repetition_contracts(lines, fields)
114
+ lines << " end"
115
+ end
116
+
117
+ # @rbs (String node_name, Integer index) -> String
118
+ def syntax_field_type(node_name, index)
119
+ symbol_ids = @grammar.productions.filter_map do |production|
120
+ production.rhs.fetch(index) if production.node&.fetch(:name) == node_name
121
+ end
122
+ types = symbol_ids.map do |symbol_id|
123
+ symbol = @grammar.symbols.fetch(symbol_id)
124
+ symbol.terminal? ? "Ibex::Runtime::CST::SyntaxToken" : "Ibex::Runtime::CST::SyntaxNode"
125
+ end.uniq
126
+ types.one? ? types.fetch(0) : "(#{types.join(' | ')})"
127
+ end
128
+
129
+ # @rbs (Array[String] lines, Hash[String, CSTMetadata::field_slot] fields) -> void
130
+ def append_repetition_contracts(lines, fields)
131
+ repeated = fields.select { |_field, slot| slot.is_a?(Hash) && slot[:extraction] }
132
+ element = "Enumerator[Ibex::Runtime::CST::SyntaxNode | Ibex::Runtime::CST::SyntaxToken, void]"
133
+ repeated.each do |field, slot|
134
+ next unless slot.is_a?(Hash)
135
+
136
+ lines << " def each_#{field}_element: () -> #{element}"
137
+ lines << " def each_#{field}_separator: () -> #{element}" if slot.fetch(:extraction) == :separated_list
138
+ end
139
+ return unless repeated.one?
140
+
141
+ _field, slot = repeated.first
142
+ return unless slot.is_a?(Hash)
143
+
144
+ lines << " def each_element: () -> #{element}"
145
+ lines << " def each_separator: () -> #{element}" if slot.fetch(:extraction) == :separated_list
146
+ end
147
+
148
+ # @rbs () -> Hash[String, IR::node_annotation]
149
+ def ast_node_definitions
150
+ @grammar.productions.filter_map(&:node).to_h { |node| [node.fetch(:name), node] }
151
+ end
152
+
153
+ # @rbs (Array[String] lines, IR::node_annotation node) -> void
154
+ def append_ast_node_contract(lines, node)
155
+ name = node.fetch(:name)
156
+ fields = node.fetch(:fields)
157
+ types = ast_node_field_types(name, fields.length)
158
+ lines << " class #{name} < Data"
159
+ fields.each_with_index { |field, index| lines << " attr_reader #{field}: #{types.fetch(index)}" }
160
+ keywords = fields.each_with_index.map { |field, index| "#{field}: #{types.fetch(index)}" }
161
+ lines << " def self.new: (#{keywords.join(', ')}) -> instance"
162
+ lines << " def initialize: (#{keywords.join(', ')}) -> void"
163
+ lines << " end"
164
+ end
165
+
166
+ # @rbs (String name, Integer length) -> Array[String]
167
+ def ast_node_field_types(name, length)
168
+ productions = @grammar.productions.select { |production| production.node&.fetch(:name) == name }
169
+ Array.new(length) do |index|
170
+ types = productions.map { |production| semantic_type(production.rhs.fetch(index)) }.uniq
171
+ types.length == 1 ? types.fetch(0) : "(#{types.join(' | ')})"
172
+ end
173
+ end
174
+
175
+ # @rbs (Array[String] lines, Hash[String, IR::node_annotation] definitions) -> void
176
+ def append_visitor_contract(lines, definitions)
177
+ lines.push(" class Visitor", " def visit: (untyped node) -> untyped")
178
+ definitions.each_value do |node|
179
+ name = node.fetch(:name)
180
+ lines << " def visit_#{ast_method_name(name)}: (#{name} node) -> untyped"
181
+ end
182
+ lines.push(" def visit_children: (untyped node) -> untyped", " end")
183
+ end
184
+
185
+ # @rbs (Array[String] lines, Hash[String, IR::node_annotation] definitions) -> void
186
+ def append_listener_contract(lines, definitions)
187
+ lines.push(" class Listener", " def walk: (untyped node) -> untyped",
188
+ " def enter: (untyped node) -> void", " def exit: (untyped node) -> void")
189
+ definitions.each_value do |node|
190
+ name = node.fetch(:name)
191
+ method = ast_method_name(name)
192
+ lines << " def enter_#{method}: (#{name} node) -> void"
193
+ lines << " def exit_#{method}: (#{name} node) -> void"
194
+ end
195
+ lines.push(" def listener_children: (untyped node) -> Array[untyped]", " end")
196
+ end
197
+
198
+ # @rbs (String name) -> String
199
+ def ast_method_name(name)
200
+ name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
201
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
202
+ .downcase
203
+ end
204
+
32
205
  # @rbs (Array[String] lines) -> void
33
206
  def append_contract(lines)
34
207
  lines.push(" PARSER_TABLE_FORMAT_VERSION: Integer",
208
+ " GRAMMAR_DIGEST: String", " STATE_COUNT: Integer", " PRODUCTION_COUNT: Integer",
35
209
  " TOKEN_IDS: Hash[untyped, Integer]", " TOKEN_NAMES: Hash[Integer, String]",
36
210
  " ACTIONS: untyped", " GOTOS: untyped", " DEFAULT_ACTIONS: Array[untyped]",
211
+ " EAGER_REDUCTIONS: Hash[Integer, [:reduce, Integer]]",
37
212
  " PRODUCTIONS: Array[Hash[Symbol, untyped]]",
213
+ " ERROR_MESSAGES: Hash[Integer, String | { id: String, message: String }]",
38
214
  " PARSER_TABLES: Hash[Symbol, untyped]", " DEBUG_ENABLED: bool", "",
39
215
  " def self.parser_tables: () -> Hash[Symbol, untyped]")
216
+ lines << " SYMBOL_NAMES: Hash[Integer, String]" if @grammar.options[:cst] == true
217
+ lines << " CST_METADATA: Hash[Symbol, untyped]" if @grammar.options[:cst] == true
218
+ lines << " CST_KIND_MODEL: Ibex::Runtime::CST::Kind" if @grammar.options[:cst] == true
219
+ append_entry_contract(lines)
220
+ append_parameter_contract(lines)
221
+ end
222
+
223
+ # @rbs (Array[String] lines) -> void
224
+ def append_entry_contract(lines)
225
+ return unless @grammar.starts.length > 1
226
+
227
+ lines << " ENTRY_STATES: Hash[Symbol, Integer]"
228
+ @grammar.starts.each { |name| lines << " def parse_#{name}: () -> untyped" }
229
+ end
230
+
231
+ # @rbs (Array[String] lines) -> void
232
+ def append_parameter_contract(lines)
233
+ parameters = @grammar.parser_parameters
234
+ return if parameters.empty?
235
+
236
+ parameters.each do |parameter|
237
+ lines << " @#{parameter[:name]}: #{parameter[:semantic_type] || 'untyped'}"
238
+ end
239
+ keywords = parameters.map do |parameter|
240
+ "#{parameter[:name]}: #{parameter[:semantic_type] || 'untyped'}"
241
+ end
242
+ lines << ""
243
+ lines << " def initialize: (#{keywords.join(', ')}, **untyped) -> void"
244
+ end
245
+
246
+ # @rbs (Array[String] lines) -> void
247
+ def append_lexer_contract(lines)
248
+ lexer = @grammar.lexer
249
+ return unless lexer
250
+
251
+ lines.push(
252
+ " LEXER_STATES: Array[String]",
253
+ " LEXER_RULES_BY_STATE: Hash[Symbol, Array[Hash[Symbol, untyped]]]",
254
+ "",
255
+ " def lex: (String | IO | Fiber source, ?file: String) -> self",
256
+ " def parse: (String | IO | Fiber source, ?file: String) -> untyped",
257
+ " def lexer_state: () -> Symbol",
258
+ " def lexer_state=: (Symbol | String state) -> Symbol",
259
+ " def next_token: () -> [untyped, untyped, Hash[Symbol, untyped]]"
260
+ )
261
+ if @grammar.options[:cst] == true
262
+ lines << " def parse_with_syntax: (String | IO | Fiber source, ?file: String) -> " \
263
+ "Ibex::Runtime::CST::ParseResult"
264
+ end
265
+ lexer.rules.each do |rule|
266
+ lines << " private def _ibex_lexer_action_#{rule.id}: (String lexeme) -> untyped" if rule.action
267
+ end
268
+ end
269
+
270
+ # @rbs (Array[String] lines) -> void
271
+ def append_value_printer_signatures(lines)
272
+ @grammar.value_printers.each do |printer|
273
+ symbol = @grammar.symbol(printer[:symbol]) || raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
274
+ lines << ""
275
+ lines << " private def _ibex_value_printer_#{symbol.id}: " \
276
+ "(#{symbol.semantic_type || 'untyped'} value) -> untyped"
277
+ end
278
+ end
279
+
280
+ # @rbs (Array[String] lines) -> void
281
+ def append_actions(lines)
282
+ actions = @grammar.productions.select { |production| action_method?(production) }
283
+ return if actions.empty?
284
+
285
+ lines << ""
286
+ actions.each do |production|
287
+ append_action_signature(lines, production)
288
+ append_composed_fragment_signatures(lines, production) if composed_action?(production)
289
+ end
290
+ end
291
+
292
+ # @rbs (Array[String] lines, IR::Production production) -> void
293
+ def append_action_signature(lines, production)
294
+ parameters = production.rhs.map { |symbol_id| semantic_type(symbol_id) }.join(", ")
295
+ result = production.node ? "AST::#{production.node.fetch(:name)}" : semantic_type(production.lhs)
296
+ if @generated_action_abi.positional_values?(production)
297
+ lines << " private def _ibex_action_#{production.id}: (#{parameters}) -> #{result}"
298
+ return
299
+ end
300
+ if @generated_action_abi.values_only?(production)
301
+ lines << " private def _ibex_action_#{production.id}: ([#{parameters}]) -> #{result}"
302
+ return
303
+ end
304
+
305
+ locations = Array.new(production.rhs.length, "untyped").join(", ")
306
+ lookahead = composed_action?(production) ? ", untyped" : ""
307
+ lines << " private def _ibex_action_#{production.id}: " \
308
+ "([#{parameters}], Array[untyped], [#{locations}], Array[untyped], " \
309
+ "Ibex::Runtime::LocationSpan?#{lookahead}) -> #{result}"
310
+ end
311
+
312
+ # @rbs (Array[String] lines, IR::Production production) -> void
313
+ def append_composed_fragment_signatures(lines, production)
314
+ plan = production.action&.composition&.dig(:plan)
315
+ raise Ibex::Error, "missing action composition plan" unless plan
316
+
317
+ plan.fetch(:steps).each_with_index do |step, index|
318
+ next unless step[:code]
319
+
320
+ inputs = step.fetch(:inputs).map do |slot|
321
+ composition_slot_type(production, plan, slot, index)
322
+ end
323
+ locations = Array.new(inputs.length, "untyped").join(", ")
324
+ result = step[:result_type] || "untyped"
325
+ lines << " private def _ibex_inline_fragment_#{production.id}_#{index}: " \
326
+ "([#{inputs.join(', ')}], Array[untyped], [#{locations}], Array[untyped], " \
327
+ "Ibex::Runtime::LocationSpan?) -> #{result}"
328
+ end
329
+ end
330
+
331
+ # @rbs (IR::Production production, IR::action_composition_plan plan, Integer slot, Integer step_index) -> String
332
+ def composition_slot_type(production, plan, slot, step_index)
333
+ physical = plan.fetch(:physical)
334
+ return semantic_type(production.rhs.fetch(slot)) if slot < physical
335
+
336
+ prior_index = slot - physical
337
+ raise Ibex::Error, "invalid composed action slot #{slot}" if prior_index >= step_index
338
+
339
+ plan.fetch(:steps).fetch(prior_index)[:result_type] || "untyped"
340
+ end
341
+
342
+ # @rbs (IR::Production production) -> bool
343
+ def action_method?(production)
344
+ !!(production.node || production.action || !@omit_action_call)
345
+ end
346
+
347
+ # @rbs (IR::Production production) -> bool
348
+ def composed_action?(production)
349
+ production.action&.composition&.dig(:plan, :version) == 1
350
+ end
351
+
352
+ # @rbs (Integer symbol_id) -> String
353
+ def semantic_type(symbol_id)
354
+ symbol = @grammar.symbol_by_id(symbol_id) || raise(Ibex::Error, "missing grammar symbol id #{symbol_id}")
355
+ symbol.semantic_type || inferred_ast_type(symbol_id) || "untyped"
356
+ end
357
+
358
+ # @rbs (Integer symbol_id) -> String?
359
+ def inferred_ast_type(symbol_id)
360
+ productions = @grammar.productions.select { |production| production.lhs == symbol_id }
361
+ return if productions.empty? || productions.any? { |production| production.node.nil? }
362
+
363
+ names = productions.map { |production| production.node&.fetch(:name) }.compact.uniq
364
+ return if names.empty?
365
+
366
+ types = names.map { |name| "AST::#{name}" }
367
+ types.length == 1 ? types.fetch(0) : "(#{types.join(' | ')})"
40
368
  end
41
369
 
42
370
  # @rbs () -> [Array[String], String]
@@ -50,5 +378,6 @@ module Ibex
50
378
  @automaton.grammar_digest.delete_prefix("sha256:").chars.first(12).join
51
379
  end
52
380
  end
381
+ # rubocop:enable Metrics/ClassLength
53
382
  end
54
383
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../lalr"
3
4
  require_relative "symbol_labels"
4
5
 
5
6
  module Ibex
@@ -11,23 +12,25 @@ module Ibex
11
12
  # Array[String] lines,
12
13
  # IR::AutomatonState state,
13
14
  # IR::Grammar grammar,
14
- # Array[IR::counterexample] examples,
15
+ # Array[LALR::search_counterexample] examples,
15
16
  # Hash[Integer, String] labels
16
17
  # ) -> void
17
18
  # private def self.append_state: (
18
19
  # Array[String] lines,
19
20
  # IR::AutomatonState state,
20
21
  # IR::Grammar grammar,
21
- # Array[IR::counterexample] examples,
22
+ # Array[LALR::search_counterexample] examples,
22
23
  # Hash[Integer, String] labels
23
24
  # ) -> void
24
- # private def append_counterexample: (Array[String] lines, IR::counterexample example, IR::Grammar grammar,
25
+ # private def append_counterexample: (Array[String] lines, LALR::search_counterexample example,
26
+ # IR::Grammar grammar,
25
27
  # Hash[Integer, String] labels) -> void
26
- # private def self.append_counterexample: (Array[String] lines, IR::counterexample example, IR::Grammar grammar,
28
+ # private def self.append_counterexample: (Array[String] lines, LALR::search_counterexample example,
29
+ # IR::Grammar grammar,
27
30
  # Hash[Integer, String] labels) -> void
28
- # private def append_tree: (Array[String] lines, untyped tree, String indentation, IR::Grammar grammar,
31
+ # private def append_tree: (Array[String] lines, Object? tree, String indentation, IR::Grammar grammar,
29
32
  # Hash[Integer, String] labels) -> void
30
- # private def self.append_tree: (Array[String] lines, untyped tree, String indentation, IR::Grammar grammar,
33
+ # private def self.append_tree: (Array[String] lines, Object? tree, String indentation, IR::Grammar grammar,
31
34
  # Hash[Integer, String] labels) -> void
32
35
  # private def format_item: (IR::AutomatonItem item, IR::Grammar grammar, Hash[Integer, String] labels) -> String
33
36
  # private def self.format_item: (IR::AutomatonItem item, IR::Grammar grammar,
@@ -36,15 +39,24 @@ module Ibex
36
39
  # private def self.format_action: (IR::parser_action action) -> String
37
40
  # private def symbol_name: (Hash[Integer, String] labels, Integer id) -> String
38
41
  # private def self.symbol_name: (Hash[Integer, String] labels, Integer id) -> String
39
- # private def tree_label: (IR::Grammar grammar, Hash[Integer, String] labels, untyped value) -> untyped
40
- # private def self.tree_label: (IR::Grammar grammar, Hash[Integer, String] labels, untyped value) -> untyped
42
+ # private def tree_label: (IR::Grammar grammar, Hash[Integer, String] labels, Object? value) -> Object?
43
+ # private def self.tree_label: (IR::Grammar grammar, Hash[Integer, String] labels, Object? value) -> Object?
44
+ # private def display_conflict: (IR::conflict conflict, IR::Grammar grammar,
45
+ # Hash[Integer, String] labels) -> Hash[Symbol, Object?]
46
+ # private def self.display_conflict: (IR::conflict conflict, IR::Grammar grammar,
47
+ # Hash[Integer, String] labels) -> Hash[Symbol, Object?]
48
+ # private def format_value: (Object? value) -> String
49
+ # private def self.format_value: (Object? value) -> String
41
50
 
42
51
  # @rbs (IR::Automaton automaton, ?max_tokens: Integer, ?max_configurations: Integer) -> String
43
52
  def render(automaton, max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS,
44
53
  max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS)
45
54
  grammar = automaton.grammar
46
55
  labels = SymbolLabels.build(grammar)
47
- lines = ["Algorithm: #{automaton.algorithm}", "States: #{automaton.states.length}", ""]
56
+ entries = automaton.entry_states.map { |name, state| "#{name}=#{state}" }.join(", ")
57
+ lines = ["Algorithm: #{automaton.algorithm}", "States: #{automaton.states.length}"]
58
+ lines << "Entries: #{entries}" if automaton.entry_states.length > 1
59
+ lines << ""
48
60
  examples = LALR::Counterexample.new(
49
61
  automaton, max_tokens: max_tokens, max_configurations: max_configurations
50
62
  ).all.group_by { |example| example[:state] }
@@ -69,16 +81,29 @@ module Ibex
69
81
  end
70
82
  lines << " default: #{format_action(state.default_action)}" if state.default_action
71
83
  state.gotos.each { |symbol_id, target| lines << " goto #{symbol_name(labels, symbol_id)}: #{target}" }
72
- state.conflicts.each { |conflict| lines << " conflict: #{conflict.inspect}" }
84
+ state.conflicts.each do |conflict|
85
+ lines << " conflict: #{format_value(display_conflict(conflict, grammar, labels))}"
86
+ end
73
87
  examples.each { |example| append_counterexample(lines, example, grammar, labels) }
74
88
  lines << ""
75
89
  end
76
90
 
77
91
  # @rbs skip
78
92
  def append_counterexample(lines, example, grammar, labels)
79
- label = example[:unifying] ? "unifying counterexample" : "nonunifying witness"
80
- sentence = example[:sentence].dup.insert(example[:lookahead_index], "•").join(" ")
93
+ label = if example[:unifying]
94
+ "unifying counterexample"
95
+ elsif example[:inconclusive]
96
+ "inconclusive reachability witness"
97
+ else
98
+ "nonunifying witness"
99
+ end
100
+ sentence = example[:sentence].map { |name| tree_label(grammar, labels, name) }
101
+ sentence = sentence.dup.insert(example[:lookahead_index], "•").join(" ")
81
102
  lines << " #{label}: #{sentence}"
103
+ if example[:inconclusive]
104
+ search = example.fetch(:search)
105
+ lines << " search exhausted after #{search.fetch(:explored)} configurations; no classification was made"
106
+ end
82
107
  example[:interpretations].each do |interpretation|
83
108
  lines << " #{interpretation[:kind]} derivation:"
84
109
  append_tree(lines, interpretation[:tree], " ", grammar, labels)
@@ -106,7 +131,8 @@ module Ibex
106
131
  # @rbs skip
107
132
  def format_item(item, grammar, labels)
108
133
  if item.production == LALR::Builder::AUGMENTED_PRODUCTION
109
- rhs = [grammar.start]
134
+ start = grammar.symbol(grammar.start)
135
+ rhs = [grammar.starts.one? && start ? symbol_name(labels, start.id) : "<entry>"]
110
136
  lhs = "$accept"
111
137
  else
112
138
  production = grammar.productions.fetch(item.production)
@@ -137,12 +163,38 @@ module Ibex
137
163
  symbol = grammar.symbol(value.to_s)
138
164
  symbol ? symbol_name(labels, symbol.id) : value
139
165
  end
166
+
167
+ # @rbs skip
168
+ def display_conflict(conflict, grammar, labels)
169
+ symbol = grammar.symbol(conflict[:symbol])
170
+ return conflict unless symbol
171
+
172
+ conflict.merge(symbol: symbol_name(labels, symbol.id))
173
+ end
174
+
175
+ # Keep reports byte-identical across Ruby versions whose Hash#inspect
176
+ # formatting differs for symbol keys.
177
+ # @rbs skip
178
+ def format_value(value)
179
+ case value
180
+ when Hash
181
+ entries = value.map do |key, item|
182
+ label = key.is_a?(Symbol) ? "#{key}:" : "#{format_value(key)} =>"
183
+ "#{label} #{format_value(item)}"
184
+ end
185
+ "{#{entries.join(', ')}}"
186
+ when Array
187
+ "[#{value.map { |item| format_value(item) }.join(', ')}]"
188
+ else
189
+ value.inspect
190
+ end
191
+ end
140
192
  module_function :append_state, :append_counterexample, :append_tree, :format_item, :format_action, :symbol_name,
141
- :tree_label
193
+ :tree_label, :display_conflict, :format_value
142
194
 
143
195
  class << self
144
196
  private :append_state, :append_counterexample, :append_tree, :format_item, :format_action, :symbol_name,
145
- :tree_label
197
+ :tree_label, :display_conflict, :format_value
146
198
  end
147
199
  end
148
200
  end