ibex 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -123
  3. data/docs/architecture.md +477 -31
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +106 -0
  12. data/docs/cst.md +237 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +262 -0
  40. data/docs/development.md +306 -0
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +26 -0
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1581 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +114 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +629 -18
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/ja/bison-import.md +51 -0
  56. data/docs/ja/stable-api.md +53 -0
  57. data/docs/lexer-construction-profile.md +109 -0
  58. data/docs/lexer-migration.md +56 -0
  59. data/docs/maturity.md +128 -0
  60. data/docs/project-site-strategy.md +54 -0
  61. data/docs/racc-migration-evidence.md +45 -0
  62. data/docs/racc-migration.md +45 -6
  63. data/docs/release-readiness.md +221 -0
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +234 -0
  67. data/docs/status.md +43 -0
  68. data/docs/syntax-sessions.md +183 -0
  69. data/docs/table-artifact.md +125 -0
  70. data/docs/test-interactions.md +219 -0
  71. data/docs/verification-report.md +137 -0
  72. data/docs/verifier-trust-boundary.md +199 -0
  73. data/docs/workloads.md +132 -0
  74. data/examples/README.md +60 -0
  75. data/examples/calculator.y +44 -0
  76. data/examples/csv.y +32 -0
  77. data/examples/ini.y +70 -0
  78. data/examples/json.y +48 -0
  79. data/examples/tiny_language.y +75 -0
  80. data/lib/ibex/analysis/digraph.rb +128 -0
  81. data/lib/ibex/analysis/sets.rb +5 -4
  82. data/lib/ibex/analysis.rb +1 -0
  83. data/lib/ibex/artifact_set.rb +63 -0
  84. data/lib/ibex/bison_import/importer.rb +516 -0
  85. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  86. data/lib/ibex/bison_import.rb +200 -0
  87. data/lib/ibex/bounded_subprocess.rb +171 -0
  88. data/lib/ibex/cli/ambiguity.rb +75 -0
  89. data/lib/ibex/cli/analysis.rb +134 -0
  90. data/lib/ibex/cli/bison_import.rb +121 -0
  91. data/lib/ibex/cli/config.rb +128 -0
  92. data/lib/ibex/cli/counterexample_options.rb +6 -2
  93. data/lib/ibex/cli/coverage.rb +173 -0
  94. data/lib/ibex/cli/debug.rb +106 -0
  95. data/lib/ibex/cli/diagnostics.rb +136 -0
  96. data/lib/ibex/cli/documentation.rb +70 -0
  97. data/lib/ibex/cli/equiv.rb +169 -0
  98. data/lib/ibex/cli/error_messages.rb +184 -0
  99. data/lib/ibex/cli/explain.rb +85 -0
  100. data/lib/ibex/cli/fix.rb +203 -0
  101. data/lib/ibex/cli/formatting.rb +387 -0
  102. data/lib/ibex/cli/fuzz.rb +200 -0
  103. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  104. data/lib/ibex/cli/generation_artifacts.rb +189 -0
  105. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  106. data/lib/ibex/cli/grammar_tests.rb +140 -0
  107. data/lib/ibex/cli/ir_tools.rb +128 -0
  108. data/lib/ibex/cli/lsp.rb +33 -0
  109. data/lib/ibex/cli/outputs.rb +133 -23
  110. data/lib/ibex/cli/racc_migration.rb +87 -0
  111. data/lib/ibex/cli/reduce.rb +202 -0
  112. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  113. data/lib/ibex/cli/samples.rb +118 -0
  114. data/lib/ibex/cli/verify.rb +116 -0
  115. data/lib/ibex/cli/watch.rb +104 -0
  116. data/lib/ibex/cli.rb +825 -55
  117. data/lib/ibex/codegen/action_locations.rb +103 -0
  118. data/lib/ibex/codegen/action_method_source.rb +209 -0
  119. data/lib/ibex/codegen/action_source.rb +119 -0
  120. data/lib/ibex/codegen/ambiguity.rb +174 -0
  121. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  122. data/lib/ibex/codegen/documentation.rb +170 -0
  123. data/lib/ibex/codegen/explain.rb +380 -0
  124. data/lib/ibex/codegen/generated_action_abi.rb +293 -0
  125. data/lib/ibex/codegen/html.rb +94 -10
  126. data/lib/ibex/codegen/mermaid.rb +43 -0
  127. data/lib/ibex/codegen/railroad.rb +197 -0
  128. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  129. data/lib/ibex/codegen/rbs.rb +331 -2
  130. data/lib/ibex/codegen/report.rb +67 -15
  131. data/lib/ibex/codegen/ruby.rb +305 -66
  132. data/lib/ibex/codegen/ruby_actions.rb +146 -0
  133. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  134. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  135. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  136. data/lib/ibex/codegen/ruby_syntax.rb +96 -0
  137. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  138. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  139. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  140. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  141. data/lib/ibex/configuration/explanation.rb +421 -0
  142. data/lib/ibex/configuration/inspector.rb +232 -0
  143. data/lib/ibex/configuration.rb +580 -0
  144. data/lib/ibex/coverage/collector.rb +198 -0
  145. data/lib/ibex/coverage/event_stream.rb +103 -0
  146. data/lib/ibex/coverage/report.rb +267 -0
  147. data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
  148. data/lib/ibex/coverage.rb +13 -0
  149. data/lib/ibex/delta_reducer.rb +99 -0
  150. data/lib/ibex/diff.rb +140 -0
  151. data/lib/ibex/equiv/machine.rb +135 -0
  152. data/lib/ibex/equiv.rb +373 -0
  153. data/lib/ibex/error_messages/parser.rb +159 -0
  154. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  155. data/lib/ibex/error_messages/renderer.rb +65 -0
  156. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  157. data/lib/ibex/error_messages/update.rb +169 -0
  158. data/lib/ibex/error_messages.rb +165 -0
  159. data/lib/ibex/fix.rb +557 -0
  160. data/lib/ibex/frontend/ast.rb +166 -7
  161. data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
  162. data/lib/ibex/frontend/diagnostic.rb +81 -0
  163. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  164. data/lib/ibex/frontend/dsl.rb +66 -7
  165. data/lib/ibex/frontend/formatter.rb +453 -0
  166. data/lib/ibex/frontend/generated_parser.rb +644 -190
  167. data/lib/ibex/frontend/generated_parser_base.rb +170 -32
  168. data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
  169. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  170. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  171. data/lib/ibex/frontend/generation.rb +33 -0
  172. data/lib/ibex/frontend/lexer.rb +162 -10
  173. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  174. data/lib/ibex/frontend/parser/declarations.rb +262 -11
  175. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  176. data/lib/ibex/frontend/parser/rules.rb +43 -6
  177. data/lib/ibex/frontend/parser.rb +182 -4
  178. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  179. data/lib/ibex/frontend/regenerator.rb +27 -1
  180. data/lib/ibex/frontend/resolution.rb +70 -0
  181. data/lib/ibex/frontend/resolver.rb +217 -0
  182. data/lib/ibex/frontend/rule_documentation.rb +104 -0
  183. data/lib/ibex/frontend/source_cursor.rb +133 -9
  184. data/lib/ibex/frontend/source_document.rb +229 -0
  185. data/lib/ibex/frontend/source_loader.rb +150 -0
  186. data/lib/ibex/frontend/source_span.rb +89 -0
  187. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  188. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  189. data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
  190. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  191. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  192. data/lib/ibex/frontend/token_adapter.rb +18 -3
  193. data/lib/ibex/frontend.rb +14 -2
  194. data/lib/ibex/fuzz.rb +219 -0
  195. data/lib/ibex/generation_input.rb +57 -0
  196. data/lib/ibex/generation_manifest.rb +211 -0
  197. data/lib/ibex/generation_transaction.rb +261 -0
  198. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  199. data/lib/ibex/generation_transaction_validation.rb +196 -0
  200. data/lib/ibex/grammar_tests.rb +206 -0
  201. data/lib/ibex/ir/automaton_ir.rb +86 -11
  202. data/lib/ibex/ir/grammar_ir.rb +170 -26
  203. data/lib/ibex/ir/lexer_ir.rb +76 -0
  204. data/lib/ibex/ir/parser_contract.rb +135 -0
  205. data/lib/ibex/ir/serialize.rb +268 -50
  206. data/lib/ibex/ir/validator/automaton.rb +375 -0
  207. data/lib/ibex/ir/validator/base.rb +147 -0
  208. data/lib/ibex/ir/validator/grammar.rb +634 -0
  209. data/lib/ibex/ir/validator/lexer.rb +113 -0
  210. data/lib/ibex/ir/validator.rb +63 -0
  211. data/lib/ibex/ir.rb +71 -5
  212. data/lib/ibex/lalr/build_metrics.rb +71 -0
  213. data/lib/ibex/lalr/builder.rb +514 -52
  214. data/lib/ibex/lalr/conflict.rb +1 -0
  215. data/lib/ibex/lalr/conflict_search.rb +26 -9
  216. data/lib/ibex/lalr/counterexample.rb +38 -18
  217. data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
  218. data/lib/ibex/lalr/goto_follows.rb +229 -0
  219. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  220. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  221. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  222. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  223. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  224. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  225. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  226. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  227. data/lib/ibex/lalr/ielr_partition.rb +166 -0
  228. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  229. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  230. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  231. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  232. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  233. data/lib/ibex/lalr.rb +59 -1
  234. data/lib/ibex/location.rb +129 -0
  235. data/lib/ibex/lsp/document_handlers.rb +68 -0
  236. data/lib/ibex/lsp/document_store.rb +264 -0
  237. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  238. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  239. data/lib/ibex/lsp/initialization_handlers.rb +80 -0
  240. data/lib/ibex/lsp/navigation_handlers.rb +70 -0
  241. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  242. data/lib/ibex/lsp/position_codec.rb +113 -0
  243. data/lib/ibex/lsp/protocol_error.rb +33 -0
  244. data/lib/ibex/lsp/request_handlers.rb +46 -0
  245. data/lib/ibex/lsp/request_support.rb +94 -0
  246. data/lib/ibex/lsp/server.rb +148 -0
  247. data/lib/ibex/lsp/symbol_index.rb +241 -0
  248. data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
  249. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  250. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  251. data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
  252. data/lib/ibex/lsp/transport.rb +128 -0
  253. data/lib/ibex/lsp/workspace.rb +128 -0
  254. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  255. data/lib/ibex/lsp.rb +33 -0
  256. data/lib/ibex/messages/en.yml +28 -0
  257. data/lib/ibex/messages/ja.yml +28 -0
  258. data/lib/ibex/messages.rb +68 -0
  259. data/lib/ibex/metrics.rb +175 -0
  260. data/lib/ibex/normalize/declarations.rb +142 -7
  261. data/lib/ibex/normalize/diagnostics.rb +94 -24
  262. data/lib/ibex/normalize/expander.rb +64 -59
  263. data/lib/ibex/normalize/expression.rb +63 -40
  264. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  265. data/lib/ibex/normalize/inline_expansion.rb +465 -0
  266. data/lib/ibex/normalize/inline_validation.rb +174 -0
  267. data/lib/ibex/normalize/lexer.rb +131 -0
  268. data/lib/ibex/normalize/named_references.rb +60 -0
  269. data/lib/ibex/normalize/nodes.rb +46 -0
  270. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
  271. data/lib/ibex/normalize/parameter_lowering.rb +143 -0
  272. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  273. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  274. data/lib/ibex/normalize/parameters.rb +226 -0
  275. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  276. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  277. data/lib/ibex/normalize.rb +172 -17
  278. data/lib/ibex/racc_migration/checker.rb +122 -0
  279. data/lib/ibex/racc_migration/harness.rb +177 -0
  280. data/lib/ibex/racc_migration/report.rb +97 -0
  281. data/lib/ibex/racc_migration.rb +12 -0
  282. data/lib/ibex/rake_task.rb +116 -0
  283. data/lib/ibex/samples.rb +216 -0
  284. data/lib/ibex/table_artifact/builder.rb +266 -0
  285. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  286. data/lib/ibex/table_artifact/document.rb +39 -0
  287. data/lib/ibex/table_artifact/executor.rb +187 -0
  288. data/lib/ibex/table_artifact/serializer.rb +57 -0
  289. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  290. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  291. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  292. data/lib/ibex/table_artifact/validator.rb +253 -0
  293. data/lib/ibex/table_artifact.rb +88 -0
  294. data/lib/ibex/table_simulation/result.rb +55 -0
  295. data/lib/ibex/table_simulation/simulator.rb +253 -0
  296. data/lib/ibex/table_simulation/step.rb +62 -0
  297. data/lib/ibex/table_simulation/text.rb +31 -0
  298. data/lib/ibex/table_simulation.rb +13 -0
  299. data/lib/ibex/tables.rb +22 -69
  300. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  301. data/lib/ibex/verification_report/builder.rb +159 -0
  302. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  303. data/lib/ibex/verification_report/logical_path.rb +68 -0
  304. data/lib/ibex/verification_report/validator.rb +329 -0
  305. data/lib/ibex/verification_report.rb +69 -0
  306. data/lib/ibex/verify/action_correspondence.rb +138 -0
  307. data/lib/ibex/verify/language_witness.rb +295 -0
  308. data/lib/ibex/verify/reference_collection.rb +190 -0
  309. data/lib/ibex/verify/result.rb +73 -0
  310. data/lib/ibex/verify/verifier.rb +598 -0
  311. data/lib/ibex/verify.rb +15 -0
  312. data/lib/ibex/version.rb +1 -1
  313. data/lib/ibex/watch/runner.rb +181 -0
  314. data/lib/ibex/watch/source_snapshot.rb +98 -0
  315. data/lib/ibex/watch.rb +11 -0
  316. data/lib/ibex.rb +35 -1
  317. data/schema/automaton-ir-definitions.schema.json +401 -0
  318. data/schema/automaton-ir.schema.json +65 -0
  319. data/schema/benchmark-v1.schema.json +212 -0
  320. data/schema/benchmark-v2.schema.json +61 -0
  321. data/schema/bison-import-v1.schema.json +106 -0
  322. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  323. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  324. data/schema/construction-profile-v1.schema.json +779 -0
  325. data/schema/cst-v1.json +170 -0
  326. data/schema/diff-v1.schema.json +41 -0
  327. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  328. data/schema/equiv-v1.schema.json +64 -0
  329. data/schema/error-ux-review-v1.schema.json +609 -0
  330. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  331. data/schema/error-ux-round2-v1.schema.json +519 -0
  332. data/schema/error-ux-v1.schema.json +258 -0
  333. data/schema/explain-v1.schema.json +495 -0
  334. data/schema/fix-v1.schema.json +64 -0
  335. data/schema/fix-v2.schema.json +66 -0
  336. data/schema/fix-v3.schema.json +101 -0
  337. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  338. data/schema/fuzz-regression-v1.schema.json +79 -0
  339. data/schema/fuzz-v1.schema.json +114 -0
  340. data/schema/generation-manifest-v1.schema.json +115 -0
  341. data/schema/grammar-ir-extensions.schema.json +734 -0
  342. data/schema/grammar-ir-foundation.schema.json +426 -0
  343. data/schema/grammar-ir.schema.json +271 -0
  344. data/schema/ielr-benchmark-v1.schema.json +85 -0
  345. data/schema/lexer-ir-v1.schema.json +215 -0
  346. data/schema/lexer-profile-v1.schema.json +491 -0
  347. data/schema/metrics-v1.schema.json +60 -0
  348. data/schema/migration-check-v1.schema.json +60 -0
  349. data/schema/performance-comparison-v1.schema.json +395 -0
  350. data/schema/public-performance-comparison-v1.schema.json +506 -0
  351. data/schema/public-performance-profile-v1.schema.json +360 -0
  352. data/schema/reduce-v1.schema.json +22 -0
  353. data/schema/reduce-v2.schema.json +63 -0
  354. data/schema/runtime-coverage-v1.schema.json +86 -0
  355. data/schema/runtime-event-v1.schema.json +308 -0
  356. data/schema/table-artifact-v1.schema.json +377 -0
  357. data/schema/table-simulation-v1.schema.json +70 -0
  358. data/schema/verification-report-v1.schema.json +222 -0
  359. data/schema/verify-v1.schema.json +42 -0
  360. data/sig/ibex/analysis/digraph.rbs +19 -0
  361. data/sig/ibex/artifact_set.rbs +37 -0
  362. data/sig/ibex/bison_import/importer.rbs +140 -0
  363. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  364. data/sig/ibex/bison_import.rbs +95 -0
  365. data/sig/ibex/bounded_subprocess.rbs +76 -0
  366. data/sig/ibex/cli/ambiguity.rbs +28 -0
  367. data/sig/ibex/cli/analysis.rbs +43 -0
  368. data/sig/ibex/cli/bison_import.rbs +32 -0
  369. data/sig/ibex/cli/config.rbs +35 -0
  370. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  371. data/sig/ibex/cli/coverage.rbs +53 -0
  372. data/sig/ibex/cli/debug.rbs +28 -0
  373. data/sig/ibex/cli/diagnostics.rbs +51 -0
  374. data/sig/ibex/cli/documentation.rbs +29 -0
  375. data/sig/ibex/cli/equiv.rbs +49 -0
  376. data/sig/ibex/cli/error_messages.rbs +63 -0
  377. data/sig/ibex/cli/explain.rbs +31 -0
  378. data/sig/ibex/cli/fix.rbs +53 -0
  379. data/sig/ibex/cli/formatting.rbs +107 -0
  380. data/sig/ibex/cli/fuzz.rbs +47 -0
  381. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  382. data/sig/ibex/cli/generation_artifacts.rbs +69 -0
  383. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  384. data/sig/ibex/cli/grammar_tests.rbs +48 -0
  385. data/sig/ibex/cli/ir_tools.rbs +39 -0
  386. data/sig/ibex/cli/lsp.rbs +14 -0
  387. data/sig/ibex/cli/outputs.rbs +26 -3
  388. data/sig/ibex/cli/racc_migration.rbs +30 -0
  389. data/sig/ibex/cli/reduce.rbs +60 -0
  390. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  391. data/sig/ibex/cli/samples.rbs +38 -0
  392. data/sig/ibex/cli/verify.rbs +28 -0
  393. data/sig/ibex/cli/watch.rbs +43 -0
  394. data/sig/ibex/cli.rbs +182 -9
  395. data/sig/ibex/codegen/action_locations.rbs +45 -0
  396. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  397. data/sig/ibex/codegen/action_source.rbs +50 -0
  398. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  399. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  400. data/sig/ibex/codegen/documentation.rbs +50 -0
  401. data/sig/ibex/codegen/explain.rbs +105 -0
  402. data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
  403. data/sig/ibex/codegen/html.rbs +18 -2
  404. data/sig/ibex/codegen/mermaid.rbs +16 -0
  405. data/sig/ibex/codegen/railroad.rbs +82 -0
  406. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  407. data/sig/ibex/codegen/rbs.rbs +86 -4
  408. data/sig/ibex/codegen/report.rbs +16 -8
  409. data/sig/ibex/codegen/ruby.rbs +105 -28
  410. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  411. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  412. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  413. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  414. data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
  415. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  416. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  417. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  418. data/sig/ibex/configuration/explanation.rbs +195 -0
  419. data/sig/ibex/configuration/inspector.rbs +53 -0
  420. data/sig/ibex/configuration.rbs +242 -0
  421. data/sig/ibex/coverage/collector.rbs +78 -0
  422. data/sig/ibex/coverage/event_stream.rbs +44 -0
  423. data/sig/ibex/coverage/report.rbs +102 -0
  424. data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
  425. data/sig/ibex/coverage.rbs +7 -0
  426. data/sig/ibex/delta_reducer.rbs +38 -0
  427. data/sig/ibex/diff.rbs +47 -0
  428. data/sig/ibex/equiv/machine.rbs +54 -0
  429. data/sig/ibex/equiv.rbs +129 -0
  430. data/sig/ibex/error_messages/parser.rbs +58 -0
  431. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  432. data/sig/ibex/error_messages/renderer.rbs +23 -0
  433. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  434. data/sig/ibex/error_messages/update.rbs +43 -0
  435. data/sig/ibex/error_messages.rbs +85 -0
  436. data/sig/ibex/fix.rbs +138 -0
  437. data/sig/ibex/frontend/ast.rbs +237 -22
  438. data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
  439. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  440. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  441. data/sig/ibex/frontend/dsl.rbs +33 -4
  442. data/sig/ibex/frontend/formatter.rbs +143 -0
  443. data/sig/ibex/frontend/generated_parser.rbs +228 -68
  444. data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
  445. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  446. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  447. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  448. data/sig/ibex/frontend/generation.rbs +6 -0
  449. data/sig/ibex/frontend/lexer.rbs +49 -2
  450. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  451. data/sig/ibex/frontend/parser/declarations.rbs +57 -0
  452. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  453. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  454. data/sig/ibex/frontend/parser.rbs +66 -0
  455. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  456. data/sig/ibex/frontend/regenerator.rbs +11 -0
  457. data/sig/ibex/frontend/resolution.rbs +34 -0
  458. data/sig/ibex/frontend/resolver.rbs +91 -0
  459. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  460. data/sig/ibex/frontend/source_cursor.rbs +38 -5
  461. data/sig/ibex/frontend/source_document.rbs +119 -0
  462. data/sig/ibex/frontend/source_loader.rbs +66 -0
  463. data/sig/ibex/frontend/source_span.rbs +56 -0
  464. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  465. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  466. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
  467. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  468. data/sig/ibex/frontend/token_adapter.rbs +11 -2
  469. data/sig/ibex/frontend.rbs +1 -1
  470. data/sig/ibex/fuzz.rbs +71 -0
  471. data/sig/ibex/generation_input.rbs +37 -0
  472. data/sig/ibex/generation_manifest.rbs +70 -0
  473. data/sig/ibex/generation_transaction.rbs +82 -0
  474. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  475. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  476. data/sig/ibex/grammar_tests.rbs +93 -0
  477. data/sig/ibex/ir/automaton_ir.rbs +35 -10
  478. data/sig/ibex/ir/grammar_ir.rbs +96 -22
  479. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  480. data/sig/ibex/ir/parser_contract.rbs +69 -0
  481. data/sig/ibex/ir/serialize.rbs +75 -23
  482. data/sig/ibex/ir/validator/automaton.rbs +112 -0
  483. data/sig/ibex/ir/validator/base.rbs +69 -0
  484. data/sig/ibex/ir/validator/grammar.rbs +195 -0
  485. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  486. data/sig/ibex/ir/validator.rbs +16 -0
  487. data/sig/ibex/ir.rbs +45 -5
  488. data/sig/ibex/lalr/build_metrics.rbs +60 -0
  489. data/sig/ibex/lalr/builder.rbs +150 -19
  490. data/sig/ibex/lalr/conflict_search.rbs +12 -5
  491. data/sig/ibex/lalr/counterexample.rbs +20 -14
  492. data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
  493. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  494. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  495. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  496. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  497. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  498. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  499. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  500. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  501. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  502. data/sig/ibex/lalr/ielr_partition.rbs +71 -0
  503. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  504. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  505. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  506. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  507. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  508. data/sig/ibex/lalr.rbs +17 -1
  509. data/sig/ibex/location.rbs +67 -0
  510. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  511. data/sig/ibex/lsp/document_store.rbs +94 -0
  512. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  513. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  514. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  515. data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
  516. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  517. data/sig/ibex/lsp/position_codec.rbs +44 -0
  518. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  519. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  520. data/sig/ibex/lsp/request_support.rbs +40 -0
  521. data/sig/ibex/lsp/server.rbs +55 -0
  522. data/sig/ibex/lsp/symbol_index.rbs +77 -0
  523. data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
  524. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  525. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  526. data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
  527. data/sig/ibex/lsp/transport.rbs +47 -0
  528. data/sig/ibex/lsp/workspace.rbs +42 -0
  529. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  530. data/sig/ibex/lsp.rbs +7 -0
  531. data/sig/ibex/messages.rbs +26 -0
  532. data/sig/ibex/metrics.rbs +50 -0
  533. data/sig/ibex/normalize/declarations.rbs +31 -0
  534. data/sig/ibex/normalize/diagnostics.rbs +13 -4
  535. data/sig/ibex/normalize/expander.rbs +22 -16
  536. data/sig/ibex/normalize/expression.rbs +11 -9
  537. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  538. data/sig/ibex/normalize/inline_expansion.rbs +129 -0
  539. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  540. data/sig/ibex/normalize/lexer.rbs +37 -0
  541. data/sig/ibex/normalize/named_references.rbs +20 -0
  542. data/sig/ibex/normalize/nodes.rbs +14 -0
  543. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
  544. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  545. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  546. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  547. data/sig/ibex/normalize/parameters.rbs +51 -0
  548. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  549. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  550. data/sig/ibex/normalize.rbs +129 -18
  551. data/sig/ibex/racc_migration/checker.rbs +36 -0
  552. data/sig/ibex/racc_migration/harness.rbs +16 -0
  553. data/sig/ibex/racc_migration/report.rbs +55 -0
  554. data/sig/ibex/racc_migration.rbs +8 -0
  555. data/sig/ibex/rake_task.rbs +51 -0
  556. data/sig/ibex/samples.rbs +60 -0
  557. data/sig/ibex/table_artifact/builder.rbs +93 -0
  558. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  559. data/sig/ibex/table_artifact/document.rbs +27 -0
  560. data/sig/ibex/table_artifact/executor.rbs +66 -0
  561. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  562. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  563. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  564. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  565. data/sig/ibex/table_artifact/validator.rbs +66 -0
  566. data/sig/ibex/table_artifact.rbs +32 -0
  567. data/sig/ibex/table_simulation/result.rbs +36 -0
  568. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  569. data/sig/ibex/table_simulation/step.rbs +42 -0
  570. data/sig/ibex/table_simulation/text.rbs +14 -0
  571. data/sig/ibex/table_simulation.rbs +7 -0
  572. data/sig/ibex/tables.rbs +10 -35
  573. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  574. data/sig/ibex/verification_report/builder.rbs +53 -0
  575. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  576. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  577. data/sig/ibex/verification_report/validator.rbs +114 -0
  578. data/sig/ibex/verification_report.rbs +44 -0
  579. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  580. data/sig/ibex/verify/language_witness.rbs +112 -0
  581. data/sig/ibex/verify/reference_collection.rbs +63 -0
  582. data/sig/ibex/verify/result.rbs +52 -0
  583. data/sig/ibex/verify/verifier.rbs +170 -0
  584. data/sig/ibex/verify.rbs +6 -0
  585. data/sig/ibex/watch/runner.rbs +58 -0
  586. data/sig/ibex/watch/source_snapshot.rbs +46 -0
  587. data/sig/ibex/watch.rbs +7 -0
  588. data/sig/ibex.rbs +2 -0
  589. metadata +524 -19
  590. data/.rubocop.yml +0 -43
  591. data/CHANGELOG.md +0 -30
  592. data/Rakefile +0 -25
  593. data/Steepfile +0 -10
  594. data/docs/compat-notes.md +0 -37
  595. data/docs/lexer-coverage.md +0 -14
  596. data/docs/phase10-extensions.md +0 -27
  597. data/gemfiles/Gemfile +0 -7
  598. data/gemfiles/Gemfile.lock +0 -98
  599. data/lib/ibex/frontend/grammar.y +0 -156
  600. data/lib/ibex/runtime/parser.rb +0 -360
  601. data/lib/ibex/runtime.rb +0 -8
  602. data/sig/ibex/runtime/parser.rbs +0 -167
  603. data/sig/ibex/runtime.rbs +0 -6
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "rake/tasklib"
5
+ require_relative "cli"
6
+
7
+ # @rbs!
8
+ # module Rake
9
+ # class TaskLib
10
+ # def initialize: () -> void
11
+ # end
12
+ #
13
+ # class Task
14
+ # def self.define_task: (Hash[String | Symbol, String | Array[String]]) -> Task
15
+ # | (Hash[String | Symbol, String | Array[String]]) {
16
+ # (Object?, Object?) -> void
17
+ # } -> Task
18
+ # end
19
+ #
20
+ # class FileTask < Task
21
+ # end
22
+ # end
23
+
24
+ module Ibex
25
+ # Declares grammar-to-parser generation in a Rakefile.
26
+ class RakeTask < Rake::TaskLib
27
+ attr_accessor :grammar #: String?
28
+ attr_accessor :output #: String?
29
+ attr_accessor :options #: Array[String]
30
+ attr_accessor :action_source #: String | true | nil
31
+
32
+ # @rbs (String | Symbol name) ?{ (RakeTask) -> void } -> void
33
+ def initialize(name, &configuration)
34
+ super()
35
+ @name = name
36
+ @grammar = nil
37
+ @output = name.to_s.end_with?(".rb") ? name.to_s : nil
38
+ @options = []
39
+ @action_source = nil
40
+ configuration&.call(self)
41
+ define
42
+ end
43
+
44
+ private
45
+
46
+ # @rbs () -> void
47
+ def define
48
+ source = @grammar || raise(ArgumentError, "grammar is required")
49
+ reject_watch_option!
50
+ target = @output || source.sub(/\.[^.]+\z/, ".rb")
51
+ target = "#{source}.rb" if target == source
52
+ prerequisites = grammar_prerequisites(source)
53
+ action_target = configured_action_source(target)
54
+ arguments = [*@options]
55
+ arguments << (@action_source == true ? "--action-source" : "--action-source=#{action_target}") if action_target
56
+ generate = lambda do |_task, _task_arguments|
57
+ status = CLI.start([*arguments, "--output-file=#{target}", source])
58
+ raise "parser generation failed for #{source}" unless status.zero?
59
+ end
60
+
61
+ if action_target
62
+ Rake::FileTask.define_task(action_target => prerequisites, &generate)
63
+ Rake::FileTask.define_task(target => [*prerequisites, action_target], &generate)
64
+ else
65
+ Rake::FileTask.define_task(target => prerequisites, &generate)
66
+ end
67
+
68
+ Rake::Task.define_task(@name => target) unless @name.to_s == target
69
+ end
70
+
71
+ # @rbs () -> void
72
+ def reject_watch_option!
73
+ return unless @options.any? { |option| option == "--watch" || option.start_with?("--watch=") }
74
+
75
+ raise ArgumentError, "RakeTask options must not include --watch"
76
+ end
77
+
78
+ # @rbs (String target) -> String?
79
+ def configured_action_source(target)
80
+ return nil unless @action_source
81
+
82
+ path = @action_source == true ? default_action_source_path(target) : @action_source
83
+ raise ArgumentError, "action_source must be true or a non-empty String" unless
84
+ path.is_a?(String) && !path.empty?
85
+ if File.expand_path(path) == File.expand_path(target)
86
+ raise ArgumentError, "action_source and output must be distinct"
87
+ end
88
+
89
+ path
90
+ end
91
+
92
+ # @rbs (String target) -> String
93
+ def default_action_source_path(target)
94
+ directory = File.dirname(target)
95
+ basename = File.basename(target)
96
+ replaced = basename.sub(/\.[^.]+\z/, ".actions.rb")
97
+ replaced = "#{basename}.actions.rb" if replaced == basename
98
+ directory == "." ? replaced : File.join(directory, replaced)
99
+ end
100
+
101
+ # @rbs (String source) -> Array[String]
102
+ def grammar_prerequisites(source)
103
+ dependencies = Frontend::Resolver.new(source, mode: configured_mode).dependencies
104
+ [source, *dependencies.drop(1)]
105
+ end
106
+
107
+ # @rbs () -> Symbol
108
+ def configured_mode
109
+ explicit = @options.find { |option| option.start_with?("--mode=") }
110
+ return explicit.delete_prefix("--mode=").to_sym if explicit
111
+
112
+ index = @options.index("--mode")
113
+ index ? @options.fetch(index + 1, "default").to_sym : :default
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ # Generates bounded terminal sentences from Grammar IR.
6
+ class Samples
7
+ DEFAULT_MAX_EXPANSIONS = 100_000 #: Integer
8
+
9
+ # @rbs (IR::Grammar grammar, ?seed: Integer, ?max_tokens: Integer, ?max_depth: Integer,
10
+ # ?max_expansions: Integer, ?strategy: Symbol | String, ?path_length: Integer) -> void
11
+ def initialize(grammar, seed: 0, max_tokens: 32, max_depth: 16, max_expansions: DEFAULT_MAX_EXPANSIONS,
12
+ strategy: :random, path_length: 1)
13
+ raise ArgumentError, "max_tokens must be positive" unless max_tokens.positive?
14
+ raise ArgumentError, "max_depth must be positive" unless max_depth.positive?
15
+ raise ArgumentError, "max_expansions must be positive" unless max_expansions.positive?
16
+
17
+ normalized_strategy = strategy.to_sym
18
+ unless %i[random coverage].include?(normalized_strategy)
19
+ raise ArgumentError, "strategy must be :random or :coverage"
20
+ end
21
+ raise ArgumentError, "path_length must be 1 or 2" unless [1, 2].include?(path_length)
22
+
23
+ @grammar = grammar
24
+ @random = Random.new(seed)
25
+ @max_tokens = max_tokens
26
+ @max_depth = max_depth
27
+ @max_expansions = max_expansions
28
+ @strategy = normalized_strategy
29
+ @path_length = path_length
30
+ @path_coverage = Hash.new(0) #: Hash[Array[Integer], Integer]
31
+ @productions = grammar.productions.group_by(&:lhs)
32
+ @minimum_costs = compute_minimum_costs
33
+ @minimum_heights = compute_minimum_heights
34
+ end
35
+
36
+ # @rbs (?count: Integer) -> Array[Array[String]]
37
+ def generate(count: 1)
38
+ raise ArgumentError, "count must be positive" unless count.positive?
39
+
40
+ start = @grammar.symbol(@grammar.start) || raise(Ibex::Error, "(samples):1:1: missing start symbol")
41
+ minimum = @minimum_costs.fetch(start.id, nil)
42
+ raise Ibex::Error, "(samples):1:1: start symbol #{@grammar.start} derives no terminal sentence" unless minimum
43
+
44
+ if minimum > @max_tokens
45
+ raise Ibex::Error, "(samples):1:1: minimum sentence needs #{minimum} tokens; limit is #{@max_tokens}"
46
+ end
47
+ if count > @max_expansions
48
+ raise Ibex::Error, "(samples):1:1: count #{count} exceeds expansion limit #{@max_expansions}"
49
+ end
50
+
51
+ remaining_expansions = @max_expansions
52
+ Array.new(count) do
53
+ sample, remaining_expansions = expand(start, remaining_expansions)
54
+ sample
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # @rbs () -> Hash[Integer, Integer?]
61
+ def compute_minimum_costs
62
+ compute_minimum_values(1) do |production, values|
63
+ rhs_values = resolved_rhs_values(production, values)
64
+ rhs_values&.sum
65
+ end
66
+ end
67
+
68
+ # @rbs () -> Hash[Integer, Integer?]
69
+ def compute_minimum_heights
70
+ compute_minimum_values(0) do |production, values|
71
+ rhs_values = resolved_rhs_values(production, values)
72
+ rhs_values && ((rhs_values.max || 0) + 1)
73
+ end
74
+ end
75
+
76
+ # @rbs (Integer terminal_value) { (IR::Production, Hash[Integer, Integer?]) -> Integer? }
77
+ # -> Hash[Integer, Integer?]
78
+ def compute_minimum_values(terminal_value)
79
+ values = @grammar.symbols.to_h { |symbol| [symbol.id, nil] } #: Hash[Integer, Integer?]
80
+ dependents = {} #: Hash[Integer, Array[IR::Production]]
81
+ queue = seed_terminal_values(values, terminal_value)
82
+
83
+ @grammar.productions.each do |production|
84
+ update_minimum(values, queue, production.lhs, yield(production, values)) if production.rhs.empty?
85
+ production.rhs.uniq.each do |symbol_id|
86
+ (dependents[symbol_id] ||= []) << production
87
+ end
88
+ end
89
+
90
+ index = 0
91
+ while index < queue.length
92
+ dependents.fetch(queue.fetch(index), []).each do |production|
93
+ update_minimum(values, queue, production.lhs, yield(production, values))
94
+ end
95
+ index += 1
96
+ end
97
+
98
+ values
99
+ end
100
+
101
+ # @rbs (Hash[Integer, Integer?] values, Integer terminal_value) -> Array[Integer]
102
+ def seed_terminal_values(values, terminal_value)
103
+ @grammar.symbols.filter_map do |symbol|
104
+ next unless symbol.terminal? && !symbol.reserved
105
+
106
+ values[symbol.id] = terminal_value
107
+ symbol.id
108
+ end
109
+ end
110
+
111
+ # @rbs (Hash[Integer, Integer?] values, Array[Integer] queue, Integer symbol_id, Integer? candidate) -> void
112
+ def update_minimum(values, queue, symbol_id, candidate)
113
+ return unless candidate
114
+
115
+ current = values.fetch(symbol_id)
116
+ return if current && current <= candidate
117
+
118
+ values[symbol_id] = candidate
119
+ queue << symbol_id
120
+ end
121
+
122
+ # @rbs (IR::Production production, Hash[Integer, Integer?] values) -> Array[Integer]?
123
+ def resolved_rhs_values(production, values)
124
+ rhs_values = production.rhs.map { |symbol_id| values.fetch(symbol_id) }
125
+ return nil if rhs_values.any?(&:nil?)
126
+
127
+ rhs_values.compact
128
+ end
129
+
130
+ # @rbs (IR::GrammarSymbol start, Integer remaining_expansions) -> [Array[String], Integer]
131
+ def expand(start, remaining_expansions)
132
+ result = [] #: Array[String]
133
+ work = [[start.id, 0, []]] #: Array[[Integer, Integer, Array[Integer]]]
134
+ pending_minimum = minimum_cost!(start.id)
135
+
136
+ while (entry = work.pop)
137
+ if remaining_expansions.zero?
138
+ raise Ibex::Error, "(samples):1:1: expansion limit of #{@max_expansions} steps exceeded"
139
+ end
140
+
141
+ remaining_expansions -= 1
142
+ symbol_id, depth, path = entry
143
+ pending_minimum -= minimum_cost!(symbol_id)
144
+ symbol = @grammar.symbol_by_id(symbol_id) ||
145
+ raise(Ibex::Error, "(samples):1:1: missing symbol #{symbol_id}")
146
+ if symbol.terminal?
147
+ result << symbol.name
148
+ next
149
+ end
150
+
151
+ budget = @max_tokens - result.length - pending_minimum
152
+ production = choose_production(symbol_id, budget, depth, path)
153
+ production_path = (path + [production.id]).last(@path_length)
154
+ @path_coverage[production_path] += 1
155
+ pending_minimum += production_cost(production) ||
156
+ raise(Ibex::Error, "(samples):1:1: no bounded derivation for symbol #{symbol_id}")
157
+ production.rhs.reverse_each { |child_id| work << [child_id, depth + 1, production_path] }
158
+ end
159
+
160
+ [result, remaining_expansions]
161
+ end
162
+
163
+ # @rbs (Integer nonterminal_id, Integer budget, Integer depth, Array[Integer] path) -> IR::Production
164
+ def choose_production(nonterminal_id, budget, depth, path)
165
+ candidates = bounded_productions(nonterminal_id, budget)
166
+ candidates = minimum_height_productions(candidates) if depth >= @max_depth
167
+ return candidates.fetch(@random.rand(candidates.length)) if @strategy == :random
168
+
169
+ minimum_coverage = candidates.map { |production| path_count(path, production) }.min
170
+ least_covered = candidates.select { |production| path_count(path, production) == minimum_coverage }
171
+ least_covered.fetch(@random.rand(least_covered.length))
172
+ end
173
+
174
+ # @rbs (Integer nonterminal_id, Integer budget) -> Array[IR::Production]
175
+ def bounded_productions(nonterminal_id, budget)
176
+ productions = @productions[nonterminal_id]
177
+ raise Ibex::Error, "(samples):1:1: no bounded derivation for symbol #{nonterminal_id}" unless productions
178
+
179
+ candidates = productions.select do |production|
180
+ cost = production_cost(production)
181
+ cost && cost <= budget
182
+ end
183
+ raise Ibex::Error, "(samples):1:1: no bounded derivation for symbol #{nonterminal_id}" if candidates.empty?
184
+
185
+ candidates
186
+ end
187
+
188
+ # @rbs (Array[IR::Production] candidates) -> Array[IR::Production]
189
+ def minimum_height_productions(candidates)
190
+ minimum = candidates.filter_map { |production| production_height(production) }.min
191
+ candidates.select { |production| production_height(production) == minimum }
192
+ end
193
+
194
+ # @rbs (Array[Integer] path, IR::Production production) -> Integer
195
+ def path_count(path, production)
196
+ @path_coverage[(path + [production.id]).last(@path_length)]
197
+ end
198
+
199
+ # @rbs (Integer symbol_id) -> Integer
200
+ def minimum_cost!(symbol_id)
201
+ @minimum_costs.fetch(symbol_id) ||
202
+ raise(Ibex::Error, "(samples):1:1: no bounded derivation for symbol #{symbol_id}")
203
+ end
204
+
205
+ # @rbs (IR::Production production) -> Integer?
206
+ def production_cost(production)
207
+ resolved_rhs_values(production, @minimum_costs)&.sum
208
+ end
209
+
210
+ # @rbs (IR::Production production) -> Integer?
211
+ def production_height(production)
212
+ child_heights = resolved_rhs_values(production, @minimum_heights)
213
+ child_heights && ((child_heights.max || 0) + 1)
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,266 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module TableArtifact
5
+ # Projects validated Automaton IR into an action-free executable sidecar.
6
+ class Builder
7
+ # @rbs!
8
+ # type json_value = String | Integer | Float | bool | nil | Array[json_value] | Hash[String, json_value]
9
+ # type json_hash = Hash[String, untyped]
10
+ # type action_rows = Array[Hash[Integer, IR::runtime_action]]
11
+ # type action_table = action_rows | Tables::CompactActions
12
+ # type goto_rows = Array[Hash[Integer, Integer]]
13
+ # type goto_table = goto_rows | Tables::Compact
14
+
15
+ include CSTProjection
16
+
17
+ REPRESENTATIONS = %i[plain compact].freeze #: Array[Symbol]
18
+
19
+ # @rbs (IR::Automaton automaton, ?representation: Symbol | String, ?cst_trivia: Symbol | String?,
20
+ # ?omit_action_call: bool?) -> void
21
+ def initialize(automaton, representation: :compact, cst_trivia: nil, omit_action_call: nil)
22
+ @automaton = automaton
23
+ @grammar = automaton.grammar
24
+ @representation = representation.to_sym
25
+ @cst_trivia = effective_cst_trivia(cst_trivia)
26
+ @omit_action_call = omit_action_call.nil? ? @grammar.options.fetch(:omit_action_call) : omit_action_call
27
+ return if REPRESENTATIONS.include?(@representation)
28
+
29
+ raise ArgumentError, "representation must be :plain or :compact"
30
+ end
31
+
32
+ # @rbs () -> Document
33
+ def build
34
+ source_identity = {
35
+ "grammar_digest" => @automaton.grammar_digest,
36
+ "automaton_digest" => automaton_digest
37
+ }
38
+ payload = build_payload(source_identity)
39
+ cost = build_cost(payload)
40
+ identity = source_identity.merge(
41
+ "payload_digest" => Serializer.digest(payload),
42
+ "cst_metadata_digest" => Serializer.digest(payload.fetch("cst")),
43
+ "recovery_metadata_digest" => Serializer.digest(payload.fetch("recovery"))
44
+ )
45
+ Document.new(
46
+ "artifact_type" => ARTIFACT_TYPE,
47
+ "schema_version" => SCHEMA_VERSION,
48
+ "identity" => identity,
49
+ "payload" => payload,
50
+ "cost" => cost
51
+ )
52
+ end
53
+
54
+ private
55
+
56
+ # @rbs (Hash[String, String] source_identity) -> json_hash
57
+ def build_payload(source_identity)
58
+ {
59
+ "table_format" => table_format,
60
+ "source" => source_identity,
61
+ "state_count" => @automaton.states.length,
62
+ "symbols" => symbols,
63
+ "tokens" => tokens,
64
+ "entry_states" => entry_states,
65
+ "tables" => tables,
66
+ "productions" => productions,
67
+ "cst" => cst,
68
+ "recovery" => recovery,
69
+ "semantic_actions" => semantic_actions
70
+ }
71
+ end
72
+
73
+ # @rbs () -> String
74
+ def automaton_digest
75
+ "sha256:#{Digest::SHA256.hexdigest(IR::Serialize.dump(@automaton))}"
76
+ end
77
+
78
+ # @rbs () -> json_hash
79
+ def table_format
80
+ {
81
+ "family" => "ibex-runtime-parser-table",
82
+ "version" => Runtime::PARSER_TABLE_FORMAT_VERSION,
83
+ "representation" => @representation.to_s,
84
+ "action_encoding" => @representation == :compact ? "signed-row-displacement-v1" : "signed-sparse-rows-v1",
85
+ "goto_encoding" => @representation == :compact ? "row-displacement-v1" : "sparse-rows-v1"
86
+ }
87
+ end
88
+
89
+ # @rbs () -> Array[json_hash]
90
+ def symbols
91
+ @grammar.symbols.sort_by(&:id).map do |symbol|
92
+ {
93
+ "id" => symbol.id,
94
+ "name" => symbol.name,
95
+ "kind" => symbol.kind.to_s,
96
+ "display_name" => symbol.display_name
97
+ }
98
+ end
99
+ end
100
+
101
+ # @rbs () -> Array[json_hash]
102
+ def tokens
103
+ @grammar.terminals.sort_by(&:id).map do |symbol|
104
+ { "id" => symbol.id, "name" => symbol.name, "display_name" => symbol.display_name }
105
+ end
106
+ end
107
+
108
+ # @rbs () -> Array[json_hash]
109
+ def entry_states
110
+ @automaton.entry_states.map { |name, state| { "name" => name, "state" => state } }
111
+ end
112
+
113
+ # @rbs () -> json_hash
114
+ def tables
115
+ table_set = Tables.build(@automaton, format: @representation) #: Tables::TableSet
116
+ {
117
+ "actions" => action_table(table_set.actions),
118
+ "gotos" => goto_table(table_set.gotos),
119
+ "default_actions" => table_set.default_actions.map { |action| Tables::CompactActions.pack(action) }
120
+ }
121
+ end
122
+
123
+ # @rbs (action_table table) -> json_hash
124
+ def action_table(table)
125
+ return compact_action_table(table) if table.is_a?(Tables::CompactActions)
126
+
127
+ {
128
+ "encoding" => "signed-sparse-rows-v1",
129
+ "rows" => table.map do |row|
130
+ row.sort.map { |token_id, action| { "token_id" => token_id, "code" => Tables::CompactActions.pack(action) } }
131
+ end
132
+ }
133
+ end
134
+
135
+ # @rbs (Tables::CompactActions table) -> json_hash
136
+ def compact_action_table(table)
137
+ {
138
+ "encoding" => "signed-row-displacement-v1",
139
+ "row_count" => table.row_count,
140
+ "column_count" => table.column_count,
141
+ "offsets" => table.offsets,
142
+ "codes" => table.codes,
143
+ "checks" => table.checks
144
+ }
145
+ end
146
+
147
+ # @rbs (goto_table table) -> json_hash
148
+ def goto_table(table)
149
+ return compact_goto_table(table) if table.is_a?(Tables::Compact)
150
+
151
+ {
152
+ "encoding" => "sparse-rows-v1",
153
+ "rows" => table.map do |row|
154
+ row.sort.map { |symbol_id, state| { "symbol_id" => symbol_id, "state" => state } }
155
+ end
156
+ }
157
+ end
158
+
159
+ # @rbs (Tables::Compact table) -> json_hash
160
+ def compact_goto_table(table)
161
+ {
162
+ "encoding" => "row-displacement-v1",
163
+ "row_count" => table.row_count,
164
+ "dense_width" => table.dense_width,
165
+ "offsets" => table.offsets,
166
+ "values" => table.values,
167
+ "checks" => table.checks
168
+ }
169
+ end
170
+
171
+ # @rbs () -> Array[json_hash]
172
+ def productions
173
+ @grammar.productions.sort_by(&:id).map do |production|
174
+ {
175
+ "id" => production.id,
176
+ "lhs" => production.lhs,
177
+ "rhs" => production.rhs,
178
+ "rhs_length" => production.rhs.length,
179
+ "action_slot" => action_slot?(production) ? production.id : nil
180
+ }
181
+ end
182
+ end
183
+
184
+ # @rbs (IR::Production production) -> bool
185
+ def action_slot?(production)
186
+ !!(production.node || production.action || !@omit_action_call)
187
+ end
188
+
189
+ # @rbs () -> json_hash
190
+ def semantic_actions
191
+ {
192
+ "binding" => "opaque-wrapper-production-id-v1",
193
+ "verified" => false,
194
+ "slots" => @grammar.productions.select { |production| action_slot?(production) }.map(&:id)
195
+ }
196
+ end
197
+
198
+ # @rbs () -> json_hash
199
+ def recovery
200
+ sync_tokens = @grammar.recovery.fetch(:sync_tokens) #: Array[String]
201
+ on_error_reduce = @grammar.recovery.fetch(:on_error_reduce) #: Array[Array[String]]
202
+ {
203
+ "sync_token_ids" => sync_tokens.map { |name| @grammar.symbol(name).id },
204
+ "on_error_reduce_symbol_ids" => on_error_reduce.map do |group|
205
+ group.map { |name| @grammar.symbol(name).id }
206
+ end
207
+ }
208
+ end
209
+
210
+ # @rbs (json_hash payload) -> json_hash
211
+ def build_cost(payload)
212
+ tables = payload.fetch("tables") #: json_hash
213
+ action_table = tables.fetch("actions") #: json_hash
214
+ goto_table = tables.fetch("gotos") #: json_hash
215
+ {
216
+ "canonical_payload_bytes" => Serializer.compact(payload).bytesize,
217
+ "action_cells" => occupied_cells(action_table, "codes"),
218
+ "goto_cells" => occupied_cells(goto_table, "values"),
219
+ "lookup_cost" => lookup_cost,
220
+ "recognition_cost" => recognition_cost,
221
+ "measurement" => "not-measured",
222
+ "bounded_by_max_steps" => true
223
+ }
224
+ end
225
+
226
+ # @rbs (json_hash table, String values_key) -> Integer
227
+ def occupied_cells(table, values_key)
228
+ if table.key?("rows")
229
+ rows = table.fetch("rows") #: Array[json_value]
230
+ return rows.sum { |row| row.is_a?(Array) ? row.length : 0 }
231
+ end
232
+
233
+ values = table.fetch(values_key) #: Array[json_value]
234
+ values.compact.length
235
+ end
236
+
237
+ # @rbs () -> String
238
+ def lookup_cost
239
+ return "O(1) row-displacement probe" if @representation == :compact
240
+
241
+ "O(log row width) binary search"
242
+ end
243
+
244
+ # @rbs () -> String
245
+ def recognition_cost
246
+ prefix = if @representation == :compact
247
+ "O(input tokens + reductions)"
248
+ else
249
+ "O((input tokens + reductions) * log maximum row width)"
250
+ end
251
+ "#{prefix}; lexer, recovery search, and semantic actions excluded"
252
+ end
253
+
254
+ # @rbs (Symbol | String? requested) -> Symbol
255
+ def effective_cst_trivia(requested)
256
+ contract_entry = @grammar.parser_contract&.cst_trivia
257
+ persisted = contract_entry.value if contract_entry&.explicit
258
+ if requested && persisted && requested.to_sym != persisted
259
+ raise ArgumentError, "cst_trivia conflicts with the persisted parser contract"
260
+ end
261
+
262
+ (requested || persisted || :leading).to_sym
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module TableArtifact
5
+ # Converts code-generation CST metadata into closed JSON records.
6
+ module CSTProjection
7
+ # @rbs!
8
+ # private def cst: () -> Hash[String, Builder::json_value]?
9
+ # private def normalize_cst: (Codegen::CSTMetadata::metadata metadata) -> Hash[String, Builder::json_value]
10
+ # private def normalize_cst_kinds: (Codegen::CSTMetadata::kinds kinds) -> Hash[String, Builder::json_value]
11
+ # private def named_kinds: (Hash[String, Integer] values) -> Array[Hash[String, String | Integer]]
12
+ # private def normalize_cst_slot: (Integer production_id,
13
+ # Codegen::CSTMetadata::slot slot) -> Hash[String, Builder::json_value]
14
+
15
+ private
16
+
17
+ # @rbs skip
18
+ def cst
19
+ return unless @grammar.options[:cst]
20
+
21
+ normalize_cst(Codegen::CSTMetadata.new(@grammar, trivia_policy: @cst_trivia).build)
22
+ end
23
+
24
+ # @rbs skip
25
+ def normalize_cst(metadata)
26
+ kinds = metadata.fetch(:kinds)
27
+ {
28
+ "version" => metadata.fetch(:version),
29
+ "trivia_policy" => metadata.fetch(:trivia_policy).to_s,
30
+ "kinds" => normalize_cst_kinds(kinds),
31
+ "slots" => metadata.fetch(:slots).sort.map { |production_id, slot| normalize_cst_slot(production_id, slot) }
32
+ }
33
+ end
34
+
35
+ # @rbs skip
36
+ def normalize_cst_kinds(kinds)
37
+ {
38
+ "names" => kinds.fetch(:names),
39
+ "terminal_range" => kinds.fetch(:terminal_range),
40
+ "nonterminal_range" => kinds.fetch(:nonterminal_range),
41
+ "named" => named_kinds(kinds.fetch(:named)),
42
+ "named_nonterminals" => kinds.fetch(:named_nonterminals).sort.map do |kind_id, symbol_id|
43
+ { "kind_id" => kind_id, "symbol_id" => symbol_id }
44
+ end,
45
+ "trivia" => named_kinds(kinds.fetch(:trivia)),
46
+ "synthetic" => named_kinds(kinds.fetch(:synthetic))
47
+ }
48
+ end
49
+
50
+ # @rbs skip
51
+ def named_kinds(values)
52
+ values.sort_by { |_name, id| id }.map { |name, id| { "name" => name, "id" => id } }
53
+ end
54
+
55
+ # @rbs skip
56
+ def normalize_cst_slot(production_id, slot)
57
+ fields = slot.fetch(:fields).map do |name, value|
58
+ value = { index: value, extraction: nil } if value.is_a?(Integer)
59
+ { "name" => name, "index" => value.fetch(:index), "extraction" => value[:extraction]&.to_s }
60
+ end
61
+ {
62
+ "production_id" => production_id,
63
+ "node_kind_id" => slot.fetch(:node_kind),
64
+ "node_name" => slot.fetch(:node_name),
65
+ "fields" => fields
66
+ }
67
+ end
68
+ end
69
+ end
70
+ end