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,134 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "json"
5
+ require "optparse"
6
+ require_relative "../diff"
7
+ require_relative "../metrics"
8
+
9
+ module Ibex
10
+ # CLI entry points for deterministic grammar diff and metrics reports.
11
+ module CLIAnalysis
12
+ # @rbs!
13
+ # type analysis_options = Hash[Symbol, untyped]
14
+ # private def normalize_grammar_path: (String) -> IR::Grammar
15
+ # private def set_configuration_option: (Symbol, Object?) -> void
16
+ # private def local_configuration_value: (Hash[Symbol, untyped], String) -> untyped
17
+ # private def set_local_configuration_option: (Hash[Symbol, untyped], Symbol, untyped) -> void
18
+
19
+ private
20
+
21
+ # @rbs (Array[String] arguments) -> Integer
22
+ def run_diff_command(arguments)
23
+ settings = analysis_options(arguments, "diff", operands: "OLD NEW")
24
+ if settings[:help]
25
+ @stdout.puts(settings.fetch(:help))
26
+ return 0
27
+ end
28
+ paths = settings.fetch(:paths)
29
+ raise Ibex::Error, "(diff):1:1: diff requires exactly two grammar or IR files" unless paths.length == 2
30
+
31
+ algorithm = settings.fetch(:algorithm)
32
+ before = load_analysis_automaton(paths.fetch(0), algorithm, explicit: algo_set?(settings))
33
+ after = load_analysis_automaton(paths.fetch(1), algorithm, explicit: algo_set?(settings))
34
+ report = Diff.new(before, after).to_h
35
+ write_analysis_report(report, settings.fetch(:format))
36
+ 0
37
+ end
38
+
39
+ # @rbs (Array[String] arguments) -> Integer
40
+ def run_metrics_command(arguments)
41
+ settings = analysis_options(arguments, "metrics", operands: "GRAMMAR")
42
+ if settings[:help]
43
+ @stdout.puts(settings.fetch(:help))
44
+ return 0
45
+ end
46
+ paths = settings.fetch(:paths)
47
+ raise Ibex::Error, "(metrics):1:1: metrics requires exactly one grammar or IR file" unless paths.length == 1
48
+
49
+ automaton = load_analysis_automaton(paths.fetch(0), settings.fetch(:algorithm), explicit: algo_set?(settings))
50
+ report = Metrics.new(automaton).to_h
51
+ write_analysis_report(report, settings.fetch(:format))
52
+ 0
53
+ end
54
+
55
+ # @rbs (Array[String] arguments, String command, operands: String) -> Hash[Symbol, untyped]
56
+ def analysis_options(arguments, command, operands:)
57
+ settings = {
58
+ paths: [], algorithm: Configuration::Registry.fetch("parser.algorithm").default,
59
+ mode: Configuration::Registry.fetch("grammar.mode").default, format: "json", configuration_explicit: []
60
+ } #: Hash[Symbol, untyped]
61
+ parser = OptionParser.new do |options|
62
+ options.banner = "Usage: ibex #{command} [options] #{operands}"
63
+ options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "algorithm for grammar inputs") do |value|
64
+ set_local_configuration_option(settings, :algorithm, value.to_sym)
65
+ end
66
+ options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
67
+ set_local_configuration_option(settings, :mode, value.to_sym)
68
+ set_configuration_option(:mode, value.to_sym)
69
+ end
70
+ options.on("--format=FORMAT", %w[json text], "json or text") { |value| settings[:format] = value }
71
+ options.on("--help", "show help") { settings[:help] = options.to_s }
72
+ end
73
+ settings[:paths] = parser.parse(arguments)
74
+ settings[:algorithm] = local_configuration_value(settings, "parser.algorithm")
75
+ settings
76
+ end
77
+
78
+ # @rbs (String path, Symbol algorithm, explicit: bool) -> IR::Automaton
79
+ def load_analysis_automaton(path, algorithm, explicit:)
80
+ source = File.binread(path)
81
+ if source.lstrip.start_with?("{")
82
+ value = IR::Validator.validate(source)
83
+ if value.is_a?(IR::Automaton)
84
+ raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with Automaton IR analysis input" if explicit
85
+
86
+ return value
87
+ end
88
+ return build_analysis_automaton(value, algorithm, explicit) if value.is_a?(IR::Grammar)
89
+
90
+ raise Ibex::Error, "#{path}:1:1: analysis does not accept Lexer IR"
91
+ end
92
+
93
+ build_analysis_automaton(normalize_grammar_path(path), algorithm, explicit)
94
+ end
95
+
96
+ # @rbs (IR::Grammar grammar, Symbol algorithm, bool algorithm_explicit) -> IR::Automaton
97
+ def build_analysis_automaton(grammar, algorithm, algorithm_explicit)
98
+ explicit_keys = algorithm_explicit ? [:algorithm] : [] #: Array[Symbol]
99
+ active = activate_analysis_grammar(
100
+ grammar, options: { algorithm: algorithm }, explicit_keys: explicit_keys
101
+ )
102
+ LALR::Builder.new(
103
+ active, algorithm: configuration_value("parser.algorithm"),
104
+ entry_isolation: configuration_value("parser.entries") == :isolated
105
+ ).build
106
+ end
107
+
108
+ # @rbs (Hash[Symbol, untyped] report, String format) -> void
109
+ def write_analysis_report(report, format)
110
+ if format == "json"
111
+ @stdout.puts(JSON.pretty_generate(report))
112
+ elsif report.fetch(:ibex_report) == "metrics"
113
+ @stdout.puts("states=#{report.dig(:automaton, :states)} rules=#{report.dig(:grammar, :rules)} " \
114
+ "alternatives=#{report.dig(:grammar, :alternatives)}")
115
+ else
116
+ %i[symbols rules conflicts warnings].each do |section|
117
+ values = report.fetch(section)
118
+ @stdout.puts("#{section}: +#{values.fetch(:added).length} " \
119
+ "-#{values.fetch(:removed).length} ~#{values.fetch(:changed).length}")
120
+ end
121
+ end
122
+ end
123
+
124
+ # @rbs (Hash[Symbol, untyped] settings) -> bool
125
+ def algo_set?(settings)
126
+ settings.fetch(:configuration_explicit).include?(:algorithm)
127
+ end
128
+
129
+ # @rbs!
130
+ # private def activate_analysis_grammar: (IR::Grammar, ?options: Hash[Symbol, untyped],
131
+ # ?explicit_keys: Array[Symbol]) -> IR::Grammar
132
+ # private def configuration_value: (String) -> untyped
133
+ end
134
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "json"
5
+ require "optparse"
6
+ require_relative "../bison_import"
7
+
8
+ module Ibex
9
+ # CLI boundary for analysis-only Bison grammar import.
10
+ module CLIBisonImport
11
+ # @rbs!
12
+ # type bison_import_options = {
13
+ # format: String,
14
+ # max_bytes: Integer,
15
+ # max_tokens: Integer,
16
+ # max_rules: Integer,
17
+ # max_actions: Integer,
18
+ # ?output: String,
19
+ # ?class_name: String,
20
+ # ?help: bool
21
+ # }
22
+ # private def same_file_target?: (String, String) -> bool
23
+ # private def atomic_write_ir: (String, String) -> void
24
+
25
+ private
26
+
27
+ # @rbs (Array[String] arguments) -> Integer
28
+ def run_bison_import_command(arguments)
29
+ kind = arguments.shift
30
+ raise Ibex::Error, "(bison-import):1:1: import requires the `bison` format" unless kind == "bison"
31
+
32
+ settings = default_bison_import_options
33
+ parser = bison_import_option_parser(settings)
34
+ paths = parser.parse(arguments)
35
+ if settings[:help]
36
+ @stdout.puts(parser)
37
+ return 0
38
+ end
39
+ raise Ibex::Error, "(bison-import):1:1: import bison requires exactly one source file" unless paths.length == 1
40
+
41
+ path = paths.fetch(0)
42
+ result = build_bison_import(path, settings)
43
+ rendered = settings.fetch(:format) == "json" ? "#{JSON.pretty_generate(result.to_h)}\n" : result.source
44
+ write_bison_import(path, settings[:output], rendered)
45
+ 0
46
+ rescue BisonImport::BudgetExceeded => e
47
+ @stdout.puts(JSON.pretty_generate({ ibex_report: "bison_import", schema_version: 1 }.merge(e.details)))
48
+ 2
49
+ end
50
+
51
+ # @rbs () -> bison_import_options
52
+ def default_bison_import_options
53
+ {
54
+ format: "source",
55
+ max_bytes: BisonImport::Importer::DEFAULT_MAX_BYTES,
56
+ max_tokens: BisonImport::Importer::DEFAULT_MAX_TOKENS,
57
+ max_rules: BisonImport::Importer::DEFAULT_MAX_RULES,
58
+ max_actions: BisonImport::Importer::DEFAULT_MAX_ACTIONS
59
+ }
60
+ end
61
+
62
+ # @rbs (bison_import_options settings) -> OptionParser
63
+ def bison_import_option_parser(settings)
64
+ OptionParser.new do |options|
65
+ options.banner = "Usage: ibex import bison [options] grammar.y"
66
+ options.on("--format=FORMAT", %w[source json], "converted source or JSON report") do |value|
67
+ settings[:format] = value
68
+ end
69
+ options.on("-o FILE", "--output=FILE", "write atomically to FILE") { |value| settings[:output] = value }
70
+ options.on("--class=NAME", "generated analysis grammar class") { |value| settings[:class_name] = value }
71
+ add_bison_import_budgets(options, settings)
72
+ options.on("--help", "show help") { settings[:help] = true }
73
+ end
74
+ end
75
+
76
+ # @rbs (OptionParser options, bison_import_options settings) -> void
77
+ def add_bison_import_budgets(options, settings)
78
+ {
79
+ "max-bytes" => :max_bytes,
80
+ "max-tokens" => :max_tokens,
81
+ "max-rules" => :max_rules,
82
+ "max-actions" => :max_actions
83
+ }.each do |name, key|
84
+ options.on("--#{name}=N", Integer, "positive import budget") do |value|
85
+ raise OptionParser::InvalidArgument, "--#{name} must be positive" unless value.positive?
86
+
87
+ settings[key] = value
88
+ end
89
+ end
90
+ end
91
+
92
+ # @rbs (String path, bison_import_options settings) -> BisonImport::Result
93
+ def build_bison_import(path, settings)
94
+ BisonImport::Importer.new(
95
+ File.binread(path),
96
+ file: path,
97
+ class_name: settings[:class_name],
98
+ max_bytes: settings.fetch(:max_bytes),
99
+ max_tokens: settings.fetch(:max_tokens),
100
+ max_rules: settings.fetch(:max_rules),
101
+ max_actions: settings.fetch(:max_actions)
102
+ ).run
103
+ end
104
+
105
+ # @rbs (String input, String? output, String source) -> void
106
+ def write_bison_import(input, output, source)
107
+ unless output
108
+ @stdout.write(source)
109
+ return
110
+ end
111
+ if same_file_target?(input, output)
112
+ raise Ibex::Error, "(bison-import):1:1: import input and output paths must be distinct"
113
+ end
114
+ if File.symlink?(output) || (File.exist?(output) && File.stat(output).nlink > 1)
115
+ raise Ibex::Error, "(bison-import):1:1: output refuses symlink aliases and files with multiple hard links"
116
+ end
117
+
118
+ atomic_write_ir(output, source)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "json"
5
+ require "optparse"
6
+ require_relative "../configuration/inspector"
7
+ require_relative "../frontend/source_loader"
8
+ require_relative "../frontend/resolver"
9
+ require_relative "../ir/validator"
10
+
11
+ module Ibex
12
+ # Static effective-configuration reporting for source grammars and Grammar IR.
13
+ module CLIConfig
14
+ # @rbs!
15
+ # type config_options = {
16
+ # format: String,
17
+ # mode: Symbol,
18
+ # configuration_explicit: Array[Symbol],
19
+ # ?from: String,
20
+ # ?algorithm: Symbol,
21
+ # ?entry_isolation: bool,
22
+ # ?cst_trivia: Symbol,
23
+ # ?superclass: String,
24
+ # ?omit_actions: bool,
25
+ # ?help: String
26
+ # }
27
+ # private def input_path: (Array[String]) -> String
28
+ # private def set_local_configuration_option: (Hash[Symbol, Object?], Symbol, Object?) -> void
29
+
30
+ private
31
+
32
+ # @rbs (Array[String] arguments) -> Integer
33
+ def run_config_command(arguments)
34
+ settings, paths = config_options(arguments)
35
+ if settings[:help]
36
+ @stdout.puts(settings.fetch(:help))
37
+ return 0
38
+ end
39
+
40
+ path = input_path(paths)
41
+ input = load_configuration_input(path, settings)
42
+ cli_values = Configuration::CLIAdapter.new(
43
+ settings, explicit_keys: settings.fetch(:configuration_explicit)
44
+ ).configuration_values
45
+ report = Configuration::Report.new(input, cli: cli_values)
46
+ write_configuration_report(report, settings.fetch(:format))
47
+ return 0 if report.success?
48
+
49
+ report.conflicts.each do |conflict|
50
+ @stderr.puts(Messages.translate("cli.error", language: @language, detail: conflict.message))
51
+ end
52
+ 1
53
+ end
54
+
55
+ # @rbs (Array[String] arguments) -> [config_options, Array[String]]
56
+ def config_options(arguments)
57
+ settings = {
58
+ format: "text", mode: Configuration::Registry.fetch("grammar.mode").default,
59
+ configuration_explicit: []
60
+ } #: config_options
61
+ parser = OptionParser.new do |options|
62
+ options.banner = "Usage: ibex config [options] grammarfile"
63
+ add_config_options(options, settings)
64
+ end
65
+ [settings, parser.parse(arguments)]
66
+ end
67
+
68
+ # @rbs (OptionParser options, config_options settings) -> void
69
+ def add_config_options(options, settings)
70
+ options.on("--format=FORMAT", %w[text json], "text or json (default: text)") do |value|
71
+ settings[:format] = value
72
+ end
73
+ options.on("--from=FORMAT", %w[grammar-ir], "read validated Grammar IR JSON") do |value|
74
+ settings[:from] = value
75
+ end
76
+ add_config_contract_options(options, settings)
77
+ options.on("--help", "show help") { settings[:help] = options.to_s }
78
+ end
79
+
80
+ # @rbs (OptionParser options, config_options settings) -> void
81
+ def add_config_contract_options(options, settings)
82
+ options.on("--mode=MODE", %w[default extended], "grammar mode") do |value|
83
+ set_local_configuration_option(settings, :mode, value.to_sym)
84
+ end
85
+ options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
86
+ set_local_configuration_option(settings, :algorithm, value.to_sym)
87
+ end
88
+ options.on("--entry-isolation", "build independent state sets for each start symbol") do
89
+ set_local_configuration_option(settings, :entry_isolation, true)
90
+ end
91
+ options.on("--cst-trivia=POLICY", %w[leading balanced drop attach], "CST trivia policy") do |value|
92
+ set_local_configuration_option(settings, :cst_trivia, value.to_sym)
93
+ end
94
+ options.on("--superclass=CLASS", "request a parser superclass") do |value|
95
+ set_local_configuration_option(settings, :superclass, value)
96
+ end
97
+ options.on("--no-omit-actions", "generate implicit action methods") do
98
+ set_local_configuration_option(settings, :omit_actions, false)
99
+ end
100
+ end
101
+
102
+ # @rbs (String path, config_options settings) -> Configuration::Input
103
+ def load_configuration_input(path, settings)
104
+ return load_grammar_ir_configuration(path) if settings[:from] == "grammar-ir"
105
+
106
+ loader = Frontend::SourceLoader.new(record_reads: true)
107
+ resolver = Frontend::Resolver.new(path, mode: settings.fetch(:mode), loader: loader)
108
+ Configuration::Inspector.from_source(resolver.resolve)
109
+ end
110
+
111
+ # @rbs (String path) -> Configuration::Input
112
+ def load_grammar_ir_configuration(path)
113
+ value = IR::Validator.validate(File.binread(path))
114
+ raise Ibex::Error, "#{path}:1:1: expected grammar-ir input" unless value.is_a?(IR::Grammar)
115
+
116
+ Configuration::Inspector.from_grammar_ir(value, path: path)
117
+ end
118
+
119
+ # @rbs (Configuration::Report report, String format) -> void
120
+ def write_configuration_report(report, format)
121
+ if format == "json"
122
+ @stdout.puts(JSON.pretty_generate(report.to_h))
123
+ else
124
+ @stdout.write(report.render_text)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../lalr/conflict_search_limits"
4
+
3
5
  module Ibex
4
6
  # Counterexample report limits and their command-line validation.
5
7
  module CLICounterexampleOptions
8
+ # @rbs @options: cli_options
9
+
6
10
  DEFAULTS = {
7
- counterexample_max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS,
8
- counterexample_max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS
11
+ counterexample_max_tokens: LALR::ConflictSearchLimits::DEFAULT_MAX_TOKENS,
12
+ counterexample_max_configurations: LALR::ConflictSearchLimits::DEFAULT_MAX_CONFIGURATIONS
9
13
  }.freeze #: Hash[Symbol, Integer]
10
14
 
11
15
  private
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "tempfile"
5
+ require_relative "../coverage"
6
+
7
+ module Ibex
8
+ # CLI collection, merge, and threshold checks for runtime coverage.
9
+ module CLICoverage
10
+ # @rbs!
11
+ # private def same_file_target?: (String left, String right) -> bool
12
+ #
13
+ # type coverage_output_options = {
14
+ # paths: Array[String],
15
+ # ?output: String
16
+ # }
17
+ # type coverage_check_options = {
18
+ # paths: Array[String],
19
+ # min_states: Float,
20
+ # min_productions: Float
21
+ # }
22
+
23
+ private
24
+
25
+ # @rbs (Array[String] arguments) -> Integer
26
+ def run_coverage_command(arguments)
27
+ operation = arguments.shift
28
+ case operation
29
+ when "collect" then run_coverage_collect(arguments)
30
+ when "merge" then run_coverage_merge(arguments)
31
+ when "check" then run_coverage_check(arguments)
32
+ else
33
+ raise Ibex::Error, "(cli):1:1: coverage requires collect, merge, or check"
34
+ end
35
+ end
36
+
37
+ # @rbs (Array[String] arguments) -> Integer
38
+ def run_coverage_collect(arguments)
39
+ settings = coverage_output_options(arguments, "collect", "INPUT")
40
+ input = single_coverage_path(settings.fetch(:paths), "coverage collect")
41
+ reject_coverage_output_collision([input], settings[:output])
42
+ report = Coverage::Collector.collect_file(input)
43
+ write_coverage_report(report, settings[:output])
44
+ 0
45
+ end
46
+
47
+ # @rbs (Array[String] arguments) -> Integer
48
+ def run_coverage_merge(arguments)
49
+ settings = coverage_output_options(arguments, "merge", "INPUT...")
50
+ inputs = settings.fetch(:paths)
51
+ raise Ibex::Error, "(cli):1:1: coverage merge requires at least one input" if inputs.empty?
52
+
53
+ reject_coverage_output_collision(inputs, settings[:output])
54
+ reports = inputs.map { |path| Coverage::Report.load_file(path) }
55
+ report = Coverage::Report.merge(reports)
56
+ write_coverage_report(report, settings[:output])
57
+ 0
58
+ rescue ArgumentError => e
59
+ raise Ibex::Error, "(coverage):1:1: #{e.message}"
60
+ end
61
+
62
+ # @rbs (Array[String] arguments) -> Integer
63
+ def run_coverage_check(arguments)
64
+ settings = coverage_check_options(arguments)
65
+ path = single_coverage_path(settings.fetch(:paths), "coverage check")
66
+ report = Coverage::Report.load_file(path)
67
+ state_percentage = coverage_percentage(report.state_hits.length, report.state_count)
68
+ production_percentage = coverage_percentage(report.production_hits.length, report.production_count)
69
+ passed = state_percentage >= settings.fetch(:min_states) &&
70
+ production_percentage >= settings.fetch(:min_productions)
71
+ summary = format(
72
+ "coverage %<status>s: states %<states>.2f%% (%<state_hits>d/%<state_total>d), " \
73
+ "productions %<productions>.2f%% (%<production_hits>d/%<production_total>d)",
74
+ status: passed ? "ok" : "failed",
75
+ states: state_percentage,
76
+ state_hits: report.state_hits.length,
77
+ state_total: report.state_count,
78
+ productions: production_percentage,
79
+ production_hits: report.production_hits.length,
80
+ production_total: report.production_count
81
+ )
82
+ (passed ? @stdout : @stderr).puts(summary)
83
+ passed ? 0 : 1
84
+ end
85
+
86
+ # @rbs (Array[String] arguments, String command, String operands) -> coverage_output_options
87
+ def coverage_output_options(arguments, command, operands)
88
+ settings = { paths: [] } #: coverage_output_options
89
+ parser = OptionParser.new do |options|
90
+ options.banner = "Usage: ibex coverage #{command} #{operands} [-o FILE]"
91
+ options.on("-o FILE", "--output=FILE", "write atomically to FILE") { |value| settings[:output] = value }
92
+ end
93
+ settings[:paths] = parser.parse(arguments)
94
+ settings
95
+ end
96
+
97
+ # @rbs (Array[String] arguments) -> coverage_check_options
98
+ def coverage_check_options(arguments)
99
+ settings = { paths: [], min_states: 0.0, min_productions: 0.0 } #: coverage_check_options
100
+ parser = OptionParser.new do |options|
101
+ options.banner = "Usage: ibex coverage check REPORT [thresholds]"
102
+ options.on("--min-states=PERCENT", Float, "minimum visited states") do |value|
103
+ settings[:min_states] = coverage_threshold(value, "min-states")
104
+ end
105
+ options.on("--min-productions=PERCENT", Float, "minimum reduced productions") do |value|
106
+ settings[:min_productions] = coverage_threshold(value, "min-productions")
107
+ end
108
+ end
109
+ settings[:paths] = parser.parse(arguments)
110
+ settings
111
+ end
112
+
113
+ # @rbs (Float value, String name) -> Float
114
+ def coverage_threshold(value, name)
115
+ return value if value.finite? && value >= 0.0 && value <= 100.0
116
+
117
+ raise OptionParser::InvalidArgument, "--#{name} must be between 0 and 100"
118
+ end
119
+
120
+ # @rbs (Integer covered, Integer total) -> Float
121
+ def coverage_percentage(covered, total)
122
+ return 100.0 if total.zero?
123
+
124
+ covered.fdiv(total) * 100.0
125
+ end
126
+
127
+ # @rbs (Array[String] arguments, String command) -> String
128
+ def single_coverage_path(arguments, command)
129
+ return arguments.first if arguments.length == 1
130
+
131
+ raise Ibex::Error, "(cli):1:1: #{command} requires exactly one input"
132
+ end
133
+
134
+ # @rbs (Array[String] inputs, String? output) -> void
135
+ def reject_coverage_output_collision(inputs, output)
136
+ return unless output
137
+ return unless inputs.any? { |input| same_file_target?(input, output) }
138
+
139
+ raise Ibex::Error, "(cli):1:1: coverage input and output paths must be distinct"
140
+ end
141
+
142
+ # @rbs (Coverage::Report report, String? output) -> void
143
+ def write_coverage_report(report, output)
144
+ source = report.to_json
145
+ return @stdout.write(source) unless output
146
+
147
+ atomic_write_coverage(output, source)
148
+ end
149
+
150
+ # @rbs (String path, String source) -> void
151
+ def atomic_write_coverage(path, source)
152
+ target_path = File.symlink?(path) ? File.realpath(path) : path
153
+ directory = File.dirname(File.expand_path(target_path))
154
+ basename = File.basename(target_path)
155
+ Tempfile.create([".#{basename}.", ".tmp"], directory) do |temporary|
156
+ temporary.binmode
157
+ temporary.write(source)
158
+ temporary.flush
159
+ temporary.fsync
160
+ temporary.chmod(coverage_file_mode(target_path))
161
+ temporary.close
162
+ File.rename(temporary.path, target_path)
163
+ end
164
+ end
165
+
166
+ # @rbs (String path) -> Integer
167
+ def coverage_file_mode(path)
168
+ return File.stat(path).mode & 0o777 if File.exist?(path)
169
+
170
+ 0o666 & ~File.umask
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "optparse"
5
+ require_relative "../table_simulation"
6
+
7
+ module Ibex
8
+ # Safe parser-table simulation subcommand.
9
+ module CLIDebug
10
+ # @rbs!
11
+ # type debug_options = {
12
+ # paths: Array[String],
13
+ # format: String,
14
+ # max_steps: Integer,
15
+ # max_stack: Integer
16
+ # }
17
+
18
+ private
19
+
20
+ # @rbs (Array[String] arguments) -> Integer
21
+ def run_debug_command(arguments)
22
+ settings = debug_options(arguments)
23
+ operands = settings.fetch(:paths)
24
+ raise Ibex::Error, "(cli):1:1: debug requires an Automaton IR file" if operands.empty?
25
+
26
+ path = operands.first
27
+ value = IR::Validator.validate(File.read(path))
28
+ raise Ibex::Error, "#{path}:1:1: debug requires Automaton IR" unless value.is_a?(IR::Automaton)
29
+
30
+ simulator = TableSimulation::Simulator.new(
31
+ value,
32
+ max_steps: settings.fetch(:max_steps),
33
+ max_stack: settings.fetch(:max_stack)
34
+ )
35
+ tokens = operands.drop(1)
36
+ interactive = tokens.empty?
37
+ format = settings.fetch(:format)
38
+ result = interactive ? simulate_debug_input(simulator, format) : simulator.simulate(tokens)
39
+ write_debug_result(result, format, steps_written: interactive && format == "text")
40
+ result.status == :accepted ? 0 : 1
41
+ rescue ArgumentError => e
42
+ raise Ibex::Error, "(debug):1:1: #{e.message}"
43
+ end
44
+
45
+ # @rbs (Array[String] arguments) -> debug_options
46
+ def debug_options(arguments)
47
+ settings = {
48
+ paths: [],
49
+ format: "text",
50
+ max_steps: TableSimulation::Simulator::DEFAULT_MAX_STEPS,
51
+ max_stack: TableSimulation::Simulator::DEFAULT_MAX_STACK
52
+ } #: debug_options
53
+ parser = OptionParser.new do |options|
54
+ options.banner = "Usage: ibex debug AUTOMATON.json [TOKEN...]"
55
+ options.on("--format=FORMAT", %w[text json], "text or json") { |value| settings[:format] = value }
56
+ options.on("--max-steps=N", Integer, "maximum simulated actions") do |value|
57
+ settings[:max_steps] = positive_debug_budget(value, "max-steps")
58
+ end
59
+ options.on("--max-stack=N", Integer, "maximum simulated state stack depth") do |value|
60
+ settings[:max_stack] = positive_debug_budget(value, "max-stack")
61
+ end
62
+ end
63
+ settings[:paths] = parser.parse(arguments)
64
+ settings
65
+ end
66
+
67
+ # @rbs (Integer value, String name) -> Integer
68
+ def positive_debug_budget(value, name)
69
+ return value if value.positive?
70
+
71
+ raise OptionParser::InvalidArgument, "--#{name} must be positive"
72
+ end
73
+
74
+ # @rbs (TableSimulation::Simulator simulator, String format) -> TableSimulation::Result
75
+ def simulate_debug_input(simulator, format)
76
+ session = simulator.start
77
+ while (line = @stdin.gets)
78
+ spelling = line.strip
79
+ break if spelling.empty?
80
+
81
+ steps = session.push(spelling)
82
+ write_debug_steps(steps) if format == "text"
83
+ break if session.status
84
+ end
85
+ written = session.steps.length
86
+ result = session.finish
87
+ write_debug_steps(result.steps.drop(written)) if format == "text"
88
+ result
89
+ end
90
+
91
+ # @rbs (TableSimulation::Result result, String format, steps_written: bool) -> void
92
+ def write_debug_result(result, format, steps_written:)
93
+ if format == "json"
94
+ @stdout.write(result.to_json)
95
+ else
96
+ write_debug_steps(result.steps) unless steps_written
97
+ @stdout.puts("status=#{result.status}")
98
+ end
99
+ end
100
+
101
+ # @rbs (Array[TableSimulation::Step] steps) -> void
102
+ def write_debug_steps(steps)
103
+ steps.each { |step| @stdout.puts(TableSimulation::Text.render_step(step)) }
104
+ end
105
+ end
106
+ end