ibex 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (461) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -272
  3. data/docs/architecture.md +187 -35
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +3 -4
  12. data/docs/cst.md +24 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +274 -0
  40. data/docs/development.md +196 -2
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +2 -1
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1617 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +54 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +184 -13
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/impact.md +101 -0
  56. data/docs/ja/bison-import.md +51 -0
  57. data/docs/ja/stable-api.md +53 -0
  58. data/docs/lexer-construction-profile.md +109 -0
  59. data/docs/lexer-migration.md +5 -0
  60. data/docs/maturity.md +129 -0
  61. data/docs/project-site-strategy.md +54 -0
  62. data/docs/racc-migration-evidence.md +45 -0
  63. data/docs/racc-migration.md +11 -0
  64. data/docs/release-readiness.md +126 -68
  65. data/docs/repair-semantics.md +123 -0
  66. data/docs/runtime-abi-evolution.md +310 -0
  67. data/docs/stability.md +145 -34
  68. data/docs/status.md +43 -0
  69. data/docs/syntax-sessions.md +183 -0
  70. data/docs/table-artifact.md +125 -0
  71. data/docs/test-interactions.md +219 -0
  72. data/docs/verification-report.md +137 -0
  73. data/docs/verifier-trust-boundary.md +199 -0
  74. data/docs/workloads.md +132 -0
  75. data/lib/ibex/analysis/digraph.rb +128 -0
  76. data/lib/ibex/analysis/sets.rb +14 -0
  77. data/lib/ibex/analysis.rb +1 -0
  78. data/lib/ibex/bison_import/importer.rb +516 -0
  79. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  80. data/lib/ibex/bison_import.rb +200 -0
  81. data/lib/ibex/bounded_subprocess.rb +171 -0
  82. data/lib/ibex/cli/ambiguity.rb +14 -5
  83. data/lib/ibex/cli/analysis.rb +134 -0
  84. data/lib/ibex/cli/bison_import.rb +121 -0
  85. data/lib/ibex/cli/config.rb +128 -0
  86. data/lib/ibex/cli/diagnostics.rb +31 -11
  87. data/lib/ibex/cli/documentation.rb +11 -8
  88. data/lib/ibex/cli/equiv.rb +169 -0
  89. data/lib/ibex/cli/error_messages.rb +11 -4
  90. data/lib/ibex/cli/explain.rb +14 -5
  91. data/lib/ibex/cli/fix.rb +203 -0
  92. data/lib/ibex/cli/formatting.rb +11 -10
  93. data/lib/ibex/cli/fuzz.rb +200 -0
  94. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  95. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  96. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  97. data/lib/ibex/cli/grammar_tests.rb +32 -14
  98. data/lib/ibex/cli/impact.rb +393 -0
  99. data/lib/ibex/cli/ir_tools.rb +5 -61
  100. data/lib/ibex/cli/outputs.rb +60 -33
  101. data/lib/ibex/cli/reduce.rb +202 -0
  102. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  103. data/lib/ibex/cli/samples.rb +49 -23
  104. data/lib/ibex/cli/verify.rb +116 -0
  105. data/lib/ibex/cli/watch.rb +6 -5
  106. data/lib/ibex/cli.rb +362 -56
  107. data/lib/ibex/codegen/action_locations.rb +1 -1
  108. data/lib/ibex/codegen/action_method_source.rb +5 -6
  109. data/lib/ibex/codegen/action_source.rb +3 -2
  110. data/lib/ibex/codegen/ambiguity.rb +5 -4
  111. data/lib/ibex/codegen/explain.rb +123 -55
  112. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  113. data/lib/ibex/codegen/rbs.rb +15 -7
  114. data/lib/ibex/codegen/report.rb +25 -13
  115. data/lib/ibex/codegen/ruby.rb +28 -64
  116. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  117. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  118. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  119. data/lib/ibex/configuration/explanation.rb +421 -0
  120. data/lib/ibex/configuration/inspector.rb +232 -0
  121. data/lib/ibex/configuration.rb +580 -0
  122. data/lib/ibex/coverage/collector.rb +21 -11
  123. data/lib/ibex/coverage/event_stream.rb +13 -7
  124. data/lib/ibex/coverage/report.rb +26 -18
  125. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  126. data/lib/ibex/delta_reducer.rb +99 -0
  127. data/lib/ibex/diff.rb +141 -0
  128. data/lib/ibex/equiv/machine.rb +135 -0
  129. data/lib/ibex/equiv.rb +373 -0
  130. data/lib/ibex/fix.rb +557 -0
  131. data/lib/ibex/frontend/ast.rb +22 -2
  132. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  133. data/lib/ibex/frontend/diagnostic.rb +1 -1
  134. data/lib/ibex/frontend/formatter.rb +72 -26
  135. data/lib/ibex/frontend/generated_parser.rb +147 -117
  136. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  137. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  138. data/lib/ibex/frontend/generation.rb +1 -1
  139. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  140. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  141. data/lib/ibex/frontend/regenerator.rb +1 -0
  142. data/lib/ibex/frontend/resolution.rb +2 -1
  143. data/lib/ibex/frontend/resolver.rb +1 -1
  144. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  145. data/lib/ibex/frontend/source_cursor.rb +2 -2
  146. data/lib/ibex/frontend/source_span.rb +9 -1
  147. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  148. data/lib/ibex/frontend/token_adapter.rb +10 -0
  149. data/lib/ibex/frontend.rb +1 -0
  150. data/lib/ibex/fuzz.rb +219 -0
  151. data/lib/ibex/generation_input.rb +1 -1
  152. data/lib/ibex/generation_manifest.rb +36 -25
  153. data/lib/ibex/generation_transaction.rb +1 -1
  154. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  155. data/lib/ibex/generation_transaction_validation.rb +2 -2
  156. data/lib/ibex/grammar_tests.rb +1 -1
  157. data/lib/ibex/impact/action_impact.rb +148 -0
  158. data/lib/ibex/impact/automaton_impact.rb +57 -0
  159. data/lib/ibex/impact/coverage_impact.rb +53 -0
  160. data/lib/ibex/impact/graph.rb +132 -0
  161. data/lib/ibex/impact/propagation.rb +147 -0
  162. data/lib/ibex/impact/report.rb +273 -0
  163. data/lib/ibex/impact/seeds.rb +69 -0
  164. data/lib/ibex/impact/severity.rb +139 -0
  165. data/lib/ibex/impact.rb +16 -0
  166. data/lib/ibex/ir/automaton_ir.rb +61 -19
  167. data/lib/ibex/ir/grammar_ir.rb +76 -45
  168. data/lib/ibex/ir/lexer_ir.rb +5 -5
  169. data/lib/ibex/ir/parser_contract.rb +135 -0
  170. data/lib/ibex/ir/serialize.rb +203 -76
  171. data/lib/ibex/ir/validator/automaton.rb +64 -34
  172. data/lib/ibex/ir/validator/base.rb +51 -33
  173. data/lib/ibex/ir/validator/grammar.rb +113 -83
  174. data/lib/ibex/ir/validator/lexer.rb +2 -2
  175. data/lib/ibex/ir/validator.rb +2 -1
  176. data/lib/ibex/ir.rb +16 -3
  177. data/lib/ibex/lalr/build_metrics.rb +50 -2
  178. data/lib/ibex/lalr/builder.rb +191 -56
  179. data/lib/ibex/lalr/conflict_search.rb +15 -4
  180. data/lib/ibex/lalr/counterexample.rb +19 -14
  181. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  182. data/lib/ibex/lalr/goto_follows.rb +229 -0
  183. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  184. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  185. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  186. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  187. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  188. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  189. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  190. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  191. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  192. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  193. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  194. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  195. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  196. data/lib/ibex/lalr.rb +52 -1
  197. data/lib/ibex/location.rb +3 -3
  198. data/lib/ibex/lsp/document_handlers.rb +9 -7
  199. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  200. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  201. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  202. data/lib/ibex/lsp/position_codec.rb +6 -2
  203. data/lib/ibex/lsp/request_handlers.rb +3 -2
  204. data/lib/ibex/lsp/request_support.rb +14 -7
  205. data/lib/ibex/lsp/server.rb +13 -11
  206. data/lib/ibex/lsp/symbol_index.rb +13 -13
  207. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  208. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  209. data/lib/ibex/lsp/transport.rb +13 -3
  210. data/lib/ibex/lsp/workspace.rb +5 -4
  211. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  212. data/lib/ibex/lsp.rb +1 -0
  213. data/lib/ibex/messages/en.yml +28 -0
  214. data/lib/ibex/messages/ja.yml +28 -0
  215. data/lib/ibex/messages.rb +68 -0
  216. data/lib/ibex/metrics.rb +175 -0
  217. data/lib/ibex/normalize/declarations.rb +2 -0
  218. data/lib/ibex/normalize/diagnostics.rb +63 -38
  219. data/lib/ibex/normalize/expander.rb +5 -4
  220. data/lib/ibex/normalize/expression.rb +8 -6
  221. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  222. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  223. data/lib/ibex/normalize/lexer.rb +3 -3
  224. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  225. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  226. data/lib/ibex/normalize/parameters.rb +31 -4
  227. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  228. data/lib/ibex/normalize.rb +10 -20
  229. data/lib/ibex/racc_migration/report.rb +6 -3
  230. data/lib/ibex/rake_task.rb +1 -1
  231. data/lib/ibex/samples.rb +43 -13
  232. data/lib/ibex/table_artifact/builder.rb +266 -0
  233. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  234. data/lib/ibex/table_artifact/document.rb +39 -0
  235. data/lib/ibex/table_artifact/executor.rb +187 -0
  236. data/lib/ibex/table_artifact/serializer.rb +57 -0
  237. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  238. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  239. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  240. data/lib/ibex/table_artifact/validator.rb +253 -0
  241. data/lib/ibex/table_artifact.rb +88 -0
  242. data/lib/ibex/table_simulation/result.rb +6 -2
  243. data/lib/ibex/table_simulation/step.rb +3 -1
  244. data/lib/ibex/tables.rb +14 -0
  245. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  246. data/lib/ibex/verification_report/builder.rb +159 -0
  247. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  248. data/lib/ibex/verification_report/logical_path.rb +68 -0
  249. data/lib/ibex/verification_report/validator.rb +329 -0
  250. data/lib/ibex/verification_report.rb +69 -0
  251. data/lib/ibex/verify/action_correspondence.rb +138 -0
  252. data/lib/ibex/verify/language_witness.rb +295 -0
  253. data/lib/ibex/verify/reference_collection.rb +190 -0
  254. data/lib/ibex/verify/result.rb +73 -0
  255. data/lib/ibex/verify/verifier.rb +598 -0
  256. data/lib/ibex/verify.rb +15 -0
  257. data/lib/ibex/version.rb +1 -1
  258. data/lib/ibex/watch/runner.rb +10 -1
  259. data/lib/ibex/watch/source_snapshot.rb +13 -8
  260. data/lib/ibex.rb +11 -0
  261. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  262. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  263. data/schema/bison-import-v1.schema.json +106 -0
  264. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  265. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  266. data/schema/construction-profile-v1.schema.json +779 -0
  267. data/schema/diff-v1.schema.json +41 -0
  268. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  269. data/schema/equiv-v1.schema.json +64 -0
  270. data/schema/error-ux-review-v1.schema.json +609 -0
  271. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  272. data/schema/error-ux-round2-v1.schema.json +519 -0
  273. data/schema/explain-v1.schema.json +63 -1
  274. data/schema/fix-v1.schema.json +64 -0
  275. data/schema/fix-v2.schema.json +66 -0
  276. data/schema/fix-v3.schema.json +101 -0
  277. data/schema/fuzz-regression-v1.schema.json +79 -0
  278. data/schema/fuzz-v1.schema.json +114 -0
  279. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  280. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  281. data/schema/grammar-ir.schema.json +271 -0
  282. data/schema/ielr-benchmark-v1.schema.json +85 -0
  283. data/schema/impact-v1.schema.json +208 -0
  284. data/schema/lexer-profile-v1.schema.json +491 -0
  285. data/schema/metrics-v1.schema.json +60 -0
  286. data/schema/reduce-v1.schema.json +22 -0
  287. data/schema/reduce-v2.schema.json +63 -0
  288. data/schema/table-artifact-v1.schema.json +377 -0
  289. data/schema/verification-report-v1.schema.json +222 -0
  290. data/schema/verify-v1.schema.json +42 -0
  291. data/sig/ibex/analysis/digraph.rbs +19 -0
  292. data/sig/ibex/analysis/sets.rbs +10 -0
  293. data/sig/ibex/bison_import/importer.rbs +140 -0
  294. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  295. data/sig/ibex/bison_import.rbs +95 -0
  296. data/sig/ibex/bounded_subprocess.rbs +76 -0
  297. data/sig/ibex/cli/ambiguity.rbs +6 -0
  298. data/sig/ibex/cli/analysis.rbs +43 -0
  299. data/sig/ibex/cli/bison_import.rbs +32 -0
  300. data/sig/ibex/cli/config.rbs +35 -0
  301. data/sig/ibex/cli/diagnostics.rbs +16 -3
  302. data/sig/ibex/cli/documentation.rbs +5 -1
  303. data/sig/ibex/cli/equiv.rbs +49 -0
  304. data/sig/ibex/cli/error_messages.rbs +6 -0
  305. data/sig/ibex/cli/explain.rbs +6 -0
  306. data/sig/ibex/cli/fix.rbs +53 -0
  307. data/sig/ibex/cli/formatting.rbs +5 -1
  308. data/sig/ibex/cli/fuzz.rbs +47 -0
  309. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  310. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  311. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  312. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  313. data/sig/ibex/cli/impact.rbs +95 -0
  314. data/sig/ibex/cli/ir_tools.rbs +7 -19
  315. data/sig/ibex/cli/outputs.rbs +9 -3
  316. data/sig/ibex/cli/reduce.rbs +60 -0
  317. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  318. data/sig/ibex/cli/samples.rbs +8 -0
  319. data/sig/ibex/cli/verify.rbs +28 -0
  320. data/sig/ibex/cli/watch.rbs +2 -2
  321. data/sig/ibex/cli.rbs +79 -5
  322. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  323. data/sig/ibex/codegen/explain.rbs +45 -25
  324. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  325. data/sig/ibex/codegen/rbs.rbs +12 -10
  326. data/sig/ibex/codegen/report.rbs +12 -12
  327. data/sig/ibex/codegen/ruby.rbs +18 -15
  328. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  329. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  330. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  331. data/sig/ibex/configuration/explanation.rbs +195 -0
  332. data/sig/ibex/configuration/inspector.rbs +53 -0
  333. data/sig/ibex/configuration.rbs +242 -0
  334. data/sig/ibex/coverage/collector.rbs +16 -14
  335. data/sig/ibex/coverage/event_stream.rbs +12 -10
  336. data/sig/ibex/coverage/report.rbs +20 -18
  337. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  338. data/sig/ibex/delta_reducer.rbs +38 -0
  339. data/sig/ibex/diff.rbs +47 -0
  340. data/sig/ibex/equiv/machine.rbs +54 -0
  341. data/sig/ibex/equiv.rbs +129 -0
  342. data/sig/ibex/fix.rbs +138 -0
  343. data/sig/ibex/frontend/ast.rbs +33 -7
  344. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  345. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  346. data/sig/ibex/frontend/formatter.rbs +38 -30
  347. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  348. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  349. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  350. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  351. data/sig/ibex/frontend/resolution.rbs +3 -2
  352. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  353. data/sig/ibex/frontend/source_span.rbs +5 -2
  354. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  355. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  356. data/sig/ibex/fuzz.rbs +71 -0
  357. data/sig/ibex/generation_input.rbs +2 -2
  358. data/sig/ibex/generation_manifest.rbs +35 -32
  359. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  360. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  361. data/sig/ibex/grammar_tests.rbs +2 -2
  362. data/sig/ibex/impact/action_impact.rbs +58 -0
  363. data/sig/ibex/impact/automaton_impact.rbs +37 -0
  364. data/sig/ibex/impact/coverage_impact.rbs +28 -0
  365. data/sig/ibex/impact/graph.rbs +67 -0
  366. data/sig/ibex/impact/propagation.rbs +56 -0
  367. data/sig/ibex/impact/report.rbs +107 -0
  368. data/sig/ibex/impact/seeds.rbs +36 -0
  369. data/sig/ibex/impact/severity.rbs +55 -0
  370. data/sig/ibex/impact.rbs +6 -0
  371. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  372. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  373. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  374. data/sig/ibex/ir/parser_contract.rbs +69 -0
  375. data/sig/ibex/ir/serialize.rbs +63 -28
  376. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  377. data/sig/ibex/ir/validator/base.rbs +35 -31
  378. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  379. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  380. data/sig/ibex/ir.rbs +9 -3
  381. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  382. data/sig/ibex/lalr/builder.rbs +75 -24
  383. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  384. data/sig/ibex/lalr/counterexample.rbs +17 -14
  385. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  386. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  387. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  388. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  389. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  390. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  391. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  392. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  393. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  394. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  395. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  396. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  397. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  398. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  399. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  400. data/sig/ibex/lalr.rbs +11 -1
  401. data/sig/ibex/location.rbs +6 -6
  402. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  403. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  404. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  405. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  406. data/sig/ibex/lsp/position_codec.rbs +8 -4
  407. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  408. data/sig/ibex/lsp/request_support.rbs +8 -8
  409. data/sig/ibex/lsp/server.rbs +16 -16
  410. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  411. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  412. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  413. data/sig/ibex/lsp/transport.rbs +18 -6
  414. data/sig/ibex/lsp/workspace.rbs +3 -2
  415. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  416. data/sig/ibex/messages.rbs +26 -0
  417. data/sig/ibex/metrics.rbs +50 -0
  418. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  419. data/sig/ibex/normalize/expander.rbs +2 -2
  420. data/sig/ibex/normalize/expression.rbs +10 -8
  421. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  422. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  423. data/sig/ibex/normalize/lexer.rbs +4 -4
  424. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  425. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  426. data/sig/ibex/normalize/parameters.rbs +13 -8
  427. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  428. data/sig/ibex/normalize.rbs +11 -5
  429. data/sig/ibex/racc_migration/report.rbs +8 -6
  430. data/sig/ibex/rake_task.rbs +1 -1
  431. data/sig/ibex/samples.rbs +13 -4
  432. data/sig/ibex/table_artifact/builder.rbs +93 -0
  433. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  434. data/sig/ibex/table_artifact/document.rbs +27 -0
  435. data/sig/ibex/table_artifact/executor.rbs +66 -0
  436. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  437. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  438. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  439. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  440. data/sig/ibex/table_artifact/validator.rbs +66 -0
  441. data/sig/ibex/table_artifact.rbs +32 -0
  442. data/sig/ibex/table_simulation/result.rbs +8 -4
  443. data/sig/ibex/table_simulation/step.rbs +4 -2
  444. data/sig/ibex/tables.rbs +10 -9
  445. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  446. data/sig/ibex/verification_report/builder.rbs +53 -0
  447. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  448. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  449. data/sig/ibex/verification_report/validator.rbs +114 -0
  450. data/sig/ibex/verification_report.rbs +44 -0
  451. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  452. data/sig/ibex/verify/language_witness.rbs +112 -0
  453. data/sig/ibex/verify/reference_collection.rbs +63 -0
  454. data/sig/ibex/verify/result.rbs +52 -0
  455. data/sig/ibex/verify/verifier.rbs +170 -0
  456. data/sig/ibex/verify.rbs +6 -0
  457. data/sig/ibex/watch/runner.rbs +12 -2
  458. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  459. metadata +254 -12
  460. data/lib/ibex/ir/migration.rb +0 -120
  461. data/sig/ibex/ir/migration.rbs +0 -34
data/lib/ibex/cli.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ # rbs_inline: enabled
2
3
 
3
4
  require "json"
4
5
  require "optparse"
5
6
  require_relative "version"
6
7
  require_relative "error"
8
+ require_relative "configuration"
9
+ require_relative "messages"
7
10
  require_relative "artifact_set"
8
11
  require_relative "generation_input"
9
12
  require_relative "generation_transaction"
@@ -18,9 +21,12 @@ require_relative "lalr/conflict"
18
21
  require_relative "lalr/on_error_reductions"
19
22
  require_relative "lalr/default_reductions"
20
23
  require_relative "lalr/build_metrics"
24
+ require_relative "lalr/inadequacy_report"
21
25
  require_relative "lalr/direct_lookaheads"
22
26
  require_relative "lalr/ielr_partition"
23
27
  require_relative "lalr/builder"
28
+ require_relative "lalr/unreachable_states"
29
+ require_relative "impact"
24
30
  require_relative "codegen/ruby"
25
31
  require_relative "cli/counterexample_options"
26
32
  require_relative "cli/generation_error_messages"
@@ -30,24 +36,32 @@ require_relative "cli/outputs"
30
36
  module Ibex
31
37
  CLI_FEATURE_ROOT = File.expand_path("cli", __dir__ || raise("CLI source directory is unavailable")) #: String
32
38
  autoload :CLIAmbiguity, File.join(CLI_FEATURE_ROOT, "ambiguity")
39
+ autoload :CLIAnalysis, File.join(CLI_FEATURE_ROOT, "analysis")
40
+ autoload :CLIImpact, File.join(CLI_FEATURE_ROOT, "impact")
41
+ autoload :CLIBisonImport, File.join(CLI_FEATURE_ROOT, "bison_import")
33
42
  autoload :CLICoverage, File.join(CLI_FEATURE_ROOT, "coverage")
34
43
  autoload :CLIDebug, File.join(CLI_FEATURE_ROOT, "debug")
35
44
  autoload :CLIDiagnostics, File.join(CLI_FEATURE_ROOT, "diagnostics")
36
45
  autoload :CLIDocumentation, File.join(CLI_FEATURE_ROOT, "documentation")
37
46
  autoload :CLIErrorMessages, File.join(CLI_FEATURE_ROOT, "error_messages")
47
+ autoload :CLIEquiv, File.join(CLI_FEATURE_ROOT, "equiv")
38
48
  autoload :CLIExplain, File.join(CLI_FEATURE_ROOT, "explain")
39
49
  autoload :CLIFormatting, File.join(CLI_FEATURE_ROOT, "formatting")
50
+ autoload :CLIFix, File.join(CLI_FEATURE_ROOT, "fix")
51
+ autoload :CLIFuzz, File.join(CLI_FEATURE_ROOT, "fuzz")
40
52
  autoload :CLIGrammarTests, File.join(CLI_FEATURE_ROOT, "grammar_tests")
41
53
  autoload :CLIIRTools, File.join(CLI_FEATURE_ROOT, "ir_tools")
42
54
  autoload :CLILSP, File.join(CLI_FEATURE_ROOT, "lsp")
43
55
  autoload :CLIRaccMigration, File.join(CLI_FEATURE_ROOT, "racc_migration")
56
+ autoload :CLIReduce, File.join(CLI_FEATURE_ROOT, "reduce")
44
57
  autoload :CLISamples, File.join(CLI_FEATURE_ROOT, "samples")
58
+ autoload :CLIVerify, File.join(CLI_FEATURE_ROOT, "verify")
45
59
  autoload :CLIWatch, File.join(CLI_FEATURE_ROOT, "watch")
46
60
 
47
61
  # @rbs!
48
62
  # interface _CLIOutput
49
- # def puts: (*untyped) -> untyped
50
- # def write: (String) -> untyped
63
+ # def puts: (*Object?) -> Object?
64
+ # def write: (String) -> Object?
51
65
  # end
52
66
  # interface _CLIInput
53
67
  # def read: () -> String
@@ -66,6 +80,9 @@ module Ibex
66
80
  # ?algorithm: Symbol,
67
81
  # ?suggest_ielr: bool,
68
82
  # ?entry_isolation: bool,
83
+ # ?ielr_strategy: Symbol,
84
+ # ?ielr_report: bool,
85
+ # ?remove_unreachable: bool,
69
86
  # ?warnings: Array[Symbol],
70
87
  # ?output: String,
71
88
  # ?embedded: bool,
@@ -105,7 +122,31 @@ module Ibex
105
122
  # ?explain_token: String,
106
123
  # ?explain_format: String,
107
124
  # ?check_ambiguity: bool,
108
- # ?check_format: String
125
+ # ?check_format: String,
126
+ # ?fuzz_seed: Integer,
127
+ # ?fuzz_count: Integer,
128
+ # ?fuzz_max_tokens: Integer,
129
+ # ?fuzz_max_depth: Integer,
130
+ # ?fuzz_max_expansions: Integer,
131
+ # ?fuzz_max_actions: Integer,
132
+ # ?fuzz_max_stack: Integer,
133
+ # ?fuzz_coverage_guided: bool,
134
+ # ?fuzz_path_length: Integer,
135
+ # ?fuzz_against: String,
136
+ # ?fuzz_against_runtime: String,
137
+ # ?fuzz_against_timeout: Integer,
138
+ # ?fuzz_against_max_output: Integer,
139
+ # ?fuzz_max_reduction_trials: Integer,
140
+ # ?fuzz_regression_dir: String,
141
+ # ?fuzz_save_regression: bool,
142
+ # ?fuzz_format: String,
143
+ # ?reduce_command: String,
144
+ # ?reduce_mode: Symbol,
145
+ # ?reduce_max_trials: Integer,
146
+ # ?reduce_timeout: Integer,
147
+ # ?reduce_max_output_bytes: Integer,
148
+ # ?reduce_max_input_bytes: Integer,
149
+ # ?reduce_format: String
109
150
  # }
110
151
 
111
152
  # Command-line pipeline coordinator.
@@ -113,21 +154,29 @@ module Ibex
113
154
  class CLI
114
155
  SUBCOMMAND_HANDLERS = {
115
156
  "check" => %i[CLIAmbiguity run_check_command],
157
+ "diff" => %i[CLIAnalysis run_diff_command],
158
+ "impact" => %i[CLIImpact run_impact_command],
116
159
  "diagnose" => %i[CLIDiagnostics run_diagnose_command],
117
- "coverage" => %i[CLICoverage run_coverage_command],
160
+ "coverage" => %i[CLICoverage run_coverage_command], "config" => %i[CLIConfig run_config_command],
118
161
  "debug" => %i[CLIDebug run_debug_command],
119
162
  "doc" => %i[CLIDocumentation run_documentation_command],
120
163
  "errors" => %i[CLIErrorMessages run_error_messages_command],
164
+ "equiv" => %i[CLIEquiv run_equiv_command],
121
165
  "explain" => %i[CLIExplain run_explain_command],
122
166
  "fmt" => %i[CLIFormatting run_format_command],
167
+ "fix" => %i[CLIFix run_fix_command],
168
+ "fuzz" => %i[CLIFuzz run_fuzz_command],
123
169
  "test" => %i[CLIGrammarTests run_grammar_tests_command],
124
170
  "lsp" => %i[CLILSP run_lsp_command],
171
+ "import" => %i[CLIBisonImport run_bison_import_command],
172
+ "metrics" => %i[CLIAnalysis run_metrics_command],
125
173
  "migrate-check" => %i[CLIRaccMigration run_migrate_check_command],
126
174
  "migrate-harness" => %i[CLIRaccMigration run_migrate_harness_command],
175
+ "reduce" => %i[CLIReduce run_reduce_command],
127
176
  "samples" => %i[CLISamples run_samples_command],
177
+ "verify" => %i[CLIVerify run_verify_command],
128
178
  "validate-ir" => %i[CLIIRTools run_validate_ir_command],
129
- "compare" => %i[CLIIRTools run_compare_command],
130
- "migrate-ir" => %i[CLIIRTools run_migrate_ir_command]
179
+ "compare" => %i[CLIIRTools run_compare_command]
131
180
  }.freeze #: Hash[String, [Symbol, Symbol]]
132
181
 
133
182
  include CLICounterexampleOptions
@@ -138,6 +187,10 @@ module Ibex
138
187
  # @rbs @stdout: _CLIOutput
139
188
  # @rbs @stderr: _CLIOutput
140
189
  # @rbs @options: cli_options
190
+ # @rbs @language: String
191
+ # @rbs @configuration_explicit_options: Hash[Symbol, bool]
192
+ # @rbs @generation_grammar: IR::Grammar?
193
+ # @rbs @generation_automaton: IR::Automaton?
141
194
 
142
195
  # rubocop:disable Layout/LineLength
143
196
  # @rbs (Array[String] arguments, ?stdin: _CLIInput, ?stdout: _CLIOutput, ?stderr: _CLIOutput, ?watch_clock: (^() -> Float)?, ?watch_sleeper: (^(Float) -> void)?, ?watch_iteration_hook: (^(Symbol, Integer, Array[String]) -> (Integer | Symbol | nil))?) -> Integer
@@ -157,13 +210,23 @@ module Ibex
157
210
  @watch_clock = watch_clock || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
158
211
  @watch_sleeper = watch_sleeper || ->(seconds) { sleep(seconds) }
159
212
  @watch_iteration_hook = watch_iteration_hook || ->(_event, _iteration, _paths) {}
160
- @options = { emit: "ruby", mode: :default, table: :compact, line_convert: true }
213
+ @language = Messages.language(ENV.fetch("IBEX_LANG", nil))
214
+ @options = {
215
+ emit: "ruby", mode: Configuration::Registry.fetch("grammar.mode").default,
216
+ table: Configuration::Registry.fetch("table.representation").default, line_convert: true
217
+ }
161
218
  .merge(CLICounterexampleOptions::DEFAULTS)
219
+ @configuration_explicit_options = {}
220
+ @generation_grammar = nil
221
+ @generation_automaton = @analysis_configuration = nil
162
222
  end
163
223
  # rubocop:enable Layout/LineLength
164
224
 
165
225
  # @rbs (Array[String] arguments) -> Integer
166
226
  def run(arguments)
227
+ arguments = extract_language(arguments)
228
+ @generation_grammar = nil
229
+ @generation_automaton = @analysis_configuration = nil
167
230
  subcommand = dispatch_subcommand(arguments)
168
231
  return subcommand unless subcommand.nil?
169
232
 
@@ -183,12 +246,94 @@ module Ibex
183
246
  process_grammar(path)
184
247
  end
185
248
  rescue OptionParser::ParseError, Ibex::Error, SystemCallError, SystemStackError => e
186
- @stderr.puts(e.message)
249
+ @stderr.puts(Messages.translate("cli.error", language: @language, detail: e.message))
187
250
  1
188
251
  end
189
252
 
190
253
  private
191
254
 
255
+ # @rbs (Symbol name) -> void
256
+ def mark_configuration_option(name)
257
+ @configuration_explicit_options[name] = true
258
+ end
259
+
260
+ # OptionParser accepts a heterogeneous set of operation and configuration
261
+ # values. The CLIAdapter is the validation boundary for this dynamic map.
262
+ # @rbs (Symbol name, untyped value) -> void
263
+ def set_configuration_option(name, value)
264
+ @options[name] = value
265
+ mark_configuration_option(name)
266
+ end
267
+
268
+ # @rbs (String value) -> void
269
+ def select_configuration_mode(value)
270
+ set_configuration_option(:mode, value.to_sym)
271
+ end
272
+
273
+ # @rbs () -> Configuration::Resolver
274
+ def effective_configuration
275
+ grammar = @generation_grammar
276
+ contract = grammar&.parser_contract
277
+ @analysis_configuration || Configuration::CLIAdapter.new(
278
+ @options, explicit_keys: @configuration_explicit_options.keys
279
+ ).resolve(
280
+ grammar: contract&.configuration_values || {},
281
+ locations: contract&.configuration_locations || {}
282
+ )
283
+ end
284
+
285
+ # Resolve a command-local legacy option hash without promoting it into the
286
+ # reusable CLI instance's generation settings.
287
+ # @rbs (Hash[Symbol, untyped] options, explicit_keys: Array[Symbol]) -> Configuration::Resolver
288
+ def resolve_configuration_options(options, explicit_keys:)
289
+ Configuration::CLIAdapter.new(options, explicit_keys: explicit_keys).resolve
290
+ end
291
+
292
+ # @rbs (Hash[Symbol, untyped] options, String name) -> untyped
293
+ def local_configuration_value(options, name)
294
+ explicit_keys = options.fetch(:configuration_explicit)
295
+ resolve_configuration_options(options, explicit_keys: explicit_keys).value(name)
296
+ end
297
+
298
+ # @rbs (Hash[Symbol, untyped] options, Symbol name, untyped value) -> void
299
+ def set_local_configuration_option(options, name, value)
300
+ options[name] = value
301
+ options.fetch(:configuration_explicit) << name
302
+ end
303
+
304
+ # Configuration values have already been validated by Configuration::Resolver;
305
+ # callers narrow the value according to the option they are consuming.
306
+ # @rbs (String name) -> untyped
307
+ def configuration_value(name)
308
+ effective_configuration.value(name)
309
+ end
310
+
311
+ # @rbs (Array[String] arguments) -> Array[String]
312
+ def extract_language(arguments)
313
+ remaining = [] #: Array[String]
314
+ index = 0
315
+ while index < arguments.length
316
+ argument = arguments.fetch(index)
317
+ if argument == "--lang"
318
+ value = arguments[index + 1]
319
+ raise OptionParser::MissingArgument, "--lang" unless value
320
+
321
+ @language = Messages.language(value)
322
+ index += 2
323
+ elsif argument.start_with?("--lang=")
324
+ value = argument.delete_prefix("--lang=")
325
+ raise OptionParser::MissingArgument, "--lang" if value.empty?
326
+
327
+ @language = Messages.language(value)
328
+ index += 1
329
+ else
330
+ remaining << argument
331
+ index += 1
332
+ end
333
+ end
334
+ remaining
335
+ end
336
+
192
337
  # @rbs (Array[String] arguments) -> Integer?
193
338
  def dispatch_subcommand(arguments)
194
339
  definition = SUBCOMMAND_HANDLERS[arguments.first]
@@ -220,28 +365,42 @@ module Ibex
220
365
  add_error_messages_generation_option(options)
221
366
  add_compatibility_options(options)
222
367
  add_information_options(options)
223
- options.separator("")
224
- options.separator("Subcommands:")
225
- options.separator(" check --ambiguity search for ambiguity within explicit budgets")
226
- options.separator(" coverage collect, merge, or check runtime coverage")
227
- options.separator(" debug AUTOMATON [TOKEN] simulate validated Automaton IR tables")
228
- options.separator(" diagnose collect frontend diagnostics")
229
- options.separator(" doc render grammar documentation")
230
- options.separator(" errors --list|--update list or update example-keyed syntax error messages")
231
- options.separator(" explain explain selected parser conflicts")
232
- options.separator(" fmt format grammar source")
233
- options.separator(" test run grammar-declared source examples")
234
- options.separator(" lsp run the language server over stdio")
235
- options.separator(" migrate-check statically check a racc grammar migration")
236
- options.separator(" migrate-harness generate a differential subprocess harness")
237
- options.separator(" samples generate bounded terminal sentences")
238
- options.separator(" validate-ir FILE validate a versioned IR document")
239
- options.separator(" compare BEFORE AFTER compare two versioned IR documents")
240
- options.separator(" migrate-ir INPUT --to=2 migrate a versioned IR document")
368
+ add_subcommand_help(options)
241
369
  end
242
370
  end
243
371
 
244
372
  # @rbs (OptionParser options) -> void
373
+ def add_subcommand_help(options)
374
+ options.separator("")
375
+ options.separator("Subcommands:")
376
+ options.separator(" check --ambiguity search for ambiguity within explicit budgets")
377
+ options.separator(CONFIG_SUBCOMMAND_HELP)
378
+ options.separator(" debug AUTOMATON [TOKEN] simulate validated Automaton IR tables")
379
+ options.separator(" diagnose collect frontend diagnostics")
380
+ options.separator(" diff OLD NEW classify grammar and automaton changes")
381
+ options.separator(" impact GRAMMAR report grammar change propagation")
382
+ options.separator(" doc render grammar documentation")
383
+ options.separator(" errors --list|--update list or update example-keyed syntax error messages")
384
+ options.separator(" equiv LEFT RIGHT search for bounded language differences")
385
+ options.separator(" explain explain selected parser conflicts")
386
+ options.separator(" fmt format grammar source")
387
+ options.separator(" fix propose bounded-equivalent conflict repairs")
388
+ options.separator(" fuzz run bounded grammar-derived differential fuzzing")
389
+ options.separator(" test run grammar-declared source examples")
390
+ options.separator(" lsp run the language server over stdio")
391
+ options.separator(" import bison FILE import Bison grammar structure for analysis")
392
+ options.separator(" migrate-check statically check a racc grammar migration")
393
+ options.separator(" migrate-harness generate a differential subprocess harness")
394
+ options.separator(" metrics GRAMMAR report deterministic grammar/table metrics")
395
+ options.separator(" reduce delta-debug a failing token, line, or byte sequence")
396
+ options.separator(" samples generate bounded terminal sentences")
397
+ options.separator(" verify AUTOMATON independently verify Automaton IR semantics")
398
+ options.separator(" validate-ir FILE validate the current IR document")
399
+ options.separator(" compare BEFORE AFTER compare current IR documents")
400
+ end
401
+
402
+ # @rbs (OptionParser options) -> void
403
+ # rubocop:disable Metrics/MethodLength -- pipeline flags share one parser boundary.
245
404
  def add_pipeline_options(options)
246
405
  options.on("--emit=FORMAT", "ast, sets, lexer-ir, grammar-ir, automaton-ir, or ruby") do |value|
247
406
  @options[:emit] = value
@@ -249,38 +408,54 @@ module Ibex
249
408
  options.on("--from=FORMAT", %w[grammar-ir automaton-ir], "resume from IR JSON") do |value|
250
409
  @options[:from] = value
251
410
  end
252
- options.on("--mode=MODE", %w[default extended], "grammar mode") { |value| @options[:mode] = value.to_sym }
411
+ options.on("--mode=MODE", %w[default extended], "grammar mode") { |value| select_configuration_mode(value) }
253
412
  options.on("--table=FORMAT", %w[plain compact], "parser table format") do |value|
254
- @options[:table] = value.to_sym
413
+ set_configuration_option(:table, value.to_sym)
255
414
  end
256
415
  options.on(
257
416
  "--cst-trivia=POLICY",
258
417
  %w[leading balanced drop attach],
259
418
  "leading, balanced, drop, or attach (alias for leading)"
260
419
  ) do |value|
261
- @options[:cst_trivia] = value.to_sym
420
+ set_configuration_option(:cst_trivia, value.to_sym)
262
421
  end
263
422
  options.on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value|
264
- @options[:algorithm] = value.to_sym
423
+ set_configuration_option(:algorithm, value.to_sym)
424
+ end
425
+ options.on("--ielr-strategy=NAME", %w[direct partition], "IELR construction strategy") do |value|
426
+ @options[:ielr_strategy] = value.to_sym
427
+ end
428
+ options.on("--ielr-report", "report canonical-vs-IELR action differences") do
429
+ @options[:ielr_report] = true
430
+ end
431
+ options.on("--remove-unreachable", "compact unreachable IELR states after resolution") do
432
+ @options[:remove_unreachable] = true
265
433
  end
266
434
  options.on("--suggest-ielr", "check whether IELR removes unexpected LALR conflicts") do
267
435
  @options[:suggest_ielr] = true
268
436
  end
269
437
  options.on("--entry-isolation", "build independent state sets for each start symbol") do
270
- @options[:entry_isolation] = true
438
+ set_configuration_option(:entry_isolation, true)
271
439
  end
272
440
  options.on("--warnings=CATEGORIES", "all, error, all,error, or none") do |value|
273
441
  @options[:warnings] = warning_categories(value)
274
442
  end
275
443
  options.on("--watch", "regenerate file outputs when grammar sources change") { @options[:watch] = true }
276
444
  end
445
+ # rubocop:enable Metrics/MethodLength
277
446
 
278
447
  # @rbs (OptionParser options) -> void
279
448
  def add_output_options(options)
280
449
  options.on("-o", "--output-file=FILE", "generated parser path") { |value| @options[:output] = value }
281
- options.on("-E", "--embedded", "embed the Pure Ruby runtime") { @options[:embedded] = true }
282
- options.on("-t", "--debug", "generate a debug-capable parser") { @options[:debug] = true }
283
- options.on("-g", "obsolete alias for --debug") { @options[:debug] = true }
450
+ options.on("-E", "--embedded", "embed the Pure Ruby runtime") do
451
+ set_configuration_option(:embedded, true)
452
+ end
453
+ options.on("-t", "--debug", "generate a debug-capable parser") do
454
+ set_configuration_option(:debug, true)
455
+ end
456
+ options.on("-g", "obsolete alias for --debug") do
457
+ set_configuration_option(:debug, true)
458
+ end
284
459
  options.on("-v", "--verbose", "write an automaton report") { @options[:verbose] = true }
285
460
  add_counterexample_options(options)
286
461
  add_signature_output_options(options)
@@ -298,7 +473,7 @@ module Ibex
298
473
  @options[:log_file] = value
299
474
  end
300
475
  options.on("-e", "--executable [RUBY]", "add a shebang") do |value|
301
- @options[:executable] = value || "/usr/bin/env ruby"
476
+ set_configuration_option(:executable, value || "/usr/bin/env ruby")
302
477
  end
303
478
  end
304
479
 
@@ -314,17 +489,23 @@ module Ibex
314
489
 
315
490
  # @rbs (OptionParser options) -> void
316
491
  def add_compatibility_options(options)
317
- options.on("-F", "--frozen", "emit frozen string literals") { @options[:frozen] = true }
492
+ options.on("-F", "--frozen", "emit frozen string literals") do
493
+ set_configuration_option(:frozen, true)
494
+ end
318
495
  options.on("--line-convert-all", "convert all source lines") do
319
- @options[:line_convert] = true
320
496
  @options[:line_convert_all] = true
497
+ set_configuration_option(:line_convert, true)
321
498
  end
322
499
  options.on("-l", "--no-line-convert", "use generated-file action lines") do
323
- @options[:line_convert] = false
324
500
  @options[:line_convert_all] = false
501
+ set_configuration_option(:line_convert, false)
502
+ end
503
+ options.on("-a", "--no-omit-actions", "generate implicit action methods") do
504
+ set_configuration_option(:omit_actions, false)
505
+ end
506
+ options.on("--superclass=CLASS", "override parser superclass") do |value|
507
+ set_configuration_option(:superclass, value)
325
508
  end
326
- options.on("-a", "--no-omit-actions", "generate implicit action methods") { @options[:omit_actions] = false }
327
- options.on("--superclass=CLASS", "override parser superclass") { |value| @options[:superclass] = value }
328
509
  options.on("--check", "verify generated parser content without rewriting") { @options[:verify_output] = true }
329
510
  options.on("-C", "--check-only", "check grammar and exit") { @options[:check_only] = true }
330
511
  options.on("-S", "--output-status", "show pipeline status") { @options[:status] = true }
@@ -334,12 +515,55 @@ module Ibex
334
515
 
335
516
  # @rbs (OptionParser options) -> void
336
517
  def add_information_options(options)
518
+ options.on("--lang=LANG", "built-in diagnostic language (en or ja)") do |value|
519
+ @language = Messages.language(value)
520
+ end
337
521
  options.on("--version", "show version") { @options[:version] = true }
338
522
  options.on("--runtime-version", "show runtime version") { @options[:runtime_version] = true }
339
523
  options.on("--copyright", "show copyright") { @options[:copyright] = true }
340
524
  options.on("--help", "show help") { @options[:help] = true }
341
525
  end
342
526
 
527
+ # @rbs @analysis_configuration: Configuration::Resolver?
528
+
529
+ # @rbs (IR::Grammar grammar, ?options: Hash[Symbol, untyped], ?explicit_keys: Array[Symbol]) -> IR::Grammar
530
+ def activate_analysis_grammar(grammar, options: @options, explicit_keys: @configuration_explicit_options.keys)
531
+ adapter = Configuration::CLIAdapter.new(options, explicit_keys: explicit_keys)
532
+ cli = adapter.configuration_values
533
+ contract = grammar.parser_contract
534
+ grammar_values = contract&.configuration_values || {}
535
+ locations = contract&.configuration_locations || {}
536
+ overrides = {} #: Hash[String, Configuration::config_value]
537
+ algorithm = "parser.algorithm"
538
+ if grammar_values.key?(algorithm) && cli.key?(algorithm) &&
539
+ grammar_values.fetch(algorithm) != cli.fetch(algorithm)
540
+ overrides[algorithm] = cli.delete(algorithm)
541
+ end
542
+ source_locations = {} #: Hash[Symbol, Hash[String, Location]]
543
+ source_locations[:grammar] = locations unless locations.empty?
544
+ configuration = Configuration::Resolver.new(
545
+ grammar: grammar_values, cli: cli, analysis_overrides: overrides, locations: source_locations
546
+ )
547
+ @analysis_configuration = configuration
548
+ active = noncanonical_analysis_grammar(grammar, configuration)
549
+ @generation_grammar = active
550
+ report_noncanonical_analysis(configuration)
551
+ active
552
+ end
553
+
554
+ # @rbs (IR::Grammar grammar, Hash[Symbol, untyped] options, Array[Symbol] explicit_keys) ->
555
+ # [IR::Grammar, Symbol, IR::Automaton]
556
+ def construct_analysis_automaton(grammar, options, explicit_keys)
557
+ active = activate_analysis_grammar(grammar, options: options, explicit_keys: explicit_keys)
558
+ algorithm = configuration_value("parser.algorithm") #: Symbol
559
+ automaton = LALR::Builder.new(
560
+ active, algorithm: algorithm, ielr_strategy: options.fetch(:ielr_strategy, :partition),
561
+ remove_unreachable: options.fetch(:remove_unreachable, false),
562
+ entry_isolation: configuration_value("parser.entries") == :isolated
563
+ ).build
564
+ [active, algorithm, automaton]
565
+ end
566
+
343
567
  # @rbs (OptionParser parser) -> Integer?
344
568
  def informational_result(parser)
345
569
  return print_version if @options[:version] || @options[:runtime_version]
@@ -359,9 +583,7 @@ module Ibex
359
583
 
360
584
  # @rbs () -> void
361
585
  def validate_generation_options
362
- if @options[:entry_isolation] && @options[:from] == "automaton-ir"
363
- raise Ibex::Error, "(cli):1:1: --entry-isolation cannot be combined with --from=automaton-ir"
364
- end
586
+ validate_automaton_construction_options
365
587
 
366
588
  validate_watch_generation_options if @options[:watch]
367
589
  validate_manifest_generation_options
@@ -369,6 +591,18 @@ module Ibex
369
591
  validate_verification_generation_options
370
592
  end
371
593
 
594
+ # @rbs () -> void
595
+ def validate_automaton_construction_options
596
+ return unless @options[:from] == "automaton-ir"
597
+
598
+ if @configuration_explicit_options[:algorithm]
599
+ raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with --from=automaton-ir"
600
+ end
601
+ return unless @configuration_explicit_options[:entry_isolation]
602
+
603
+ raise Ibex::Error, "(cli):1:1: --entry-isolation cannot be combined with --from=automaton-ir"
604
+ end
605
+
372
606
  # @rbs () -> void
373
607
  def validate_manifest_generation_options
374
608
  return unless @options[:manifest]
@@ -511,20 +745,33 @@ module Ibex
511
745
  validate_generation_paths!(path, source_paths: resolution.files)
512
746
  return emit_ast(resolution.root) if @options[:emit] == "ast"
513
747
 
514
- grammar = Normalizer.new(resolution, mode: @options[:mode]).normalize
748
+ grammar = Normalizer.new(resolution, mode: configuration_value("grammar.mode")).normalize
515
749
  dispatch_grammar(grammar, path)
516
750
  end
517
751
 
518
752
  # @rbs (String path) -> Frontend::Resolution
519
753
  def resolve_grammar_path(path)
520
754
  loader = Frontend::SourceLoader.new(record_reads: true)
521
- @last_resolver = Frontend::Resolver.new(path, mode: @options[:mode], loader: loader)
755
+ @last_resolver = Frontend::Resolver.new(path, mode: configuration_value("grammar.mode"), loader: loader)
522
756
  @last_resolver.resolve
523
757
  end
524
758
 
525
759
  # @rbs (String path) -> IR::Grammar
526
760
  def normalize_grammar_path(path)
527
- Normalizer.new(resolve_grammar_path(path), mode: @options[:mode]).normalize
761
+ source = File.binread(path)
762
+ if bison_source?(source)
763
+ require_relative "bison_import"
764
+ imported = BisonImport::Importer.new(source, file: path).run
765
+ ast = Frontend::Parser.new(imported.source, file: path, mode: :extended).parse
766
+ return Normalizer.new(ast, mode: :extended).normalize
767
+ end
768
+
769
+ Normalizer.new(resolve_grammar_path(path), mode: configuration_value("grammar.mode")).normalize
770
+ end
771
+
772
+ # @rbs (String source) -> bool
773
+ def bison_source?(source)
774
+ source.lines.count { |line| line.match?(%r{^\s*%%(?:\s|/|$)}) } >= 2
528
775
  end
529
776
 
530
777
  # @rbs (String path) -> Integer
@@ -548,6 +795,7 @@ module Ibex
548
795
 
549
796
  # @rbs (IR::Grammar grammar, String path) -> Integer
550
797
  def dispatch_grammar(grammar, path)
798
+ activate_generation_grammar(grammar)
551
799
  handle_grammar_warnings(grammar, path)
552
800
  if @options[:check_only]
553
801
  build_automaton(grammar, path) if @options[:warnings]&.include?(:error)
@@ -566,6 +814,7 @@ module Ibex
566
814
 
567
815
  # @rbs (IR::Automaton automaton, String path) -> Integer
568
816
  def dispatch_automaton(automaton, path)
817
+ activate_generation_grammar(automaton.grammar)
569
818
  handle_grammar_warnings(automaton.grammar, path)
570
819
  return 0 if @options[:check_only]
571
820
 
@@ -583,6 +832,36 @@ module Ibex
583
832
  raise Ibex::Error, "(cli):1:1: AST cannot be reconstructed from Automaton IR"
584
833
  end
585
834
 
835
+ # @rbs (IR::Grammar grammar) -> void
836
+ def activate_generation_grammar(grammar)
837
+ @analysis_configuration = nil
838
+ @generation_grammar = grammar
839
+ effective_configuration
840
+ end
841
+
842
+ # @rbs (IR::Grammar grammar, Configuration::Resolver configuration) -> IR::Grammar
843
+ def noncanonical_analysis_grammar(grammar, configuration)
844
+ selection = configuration.fetch("parser.algorithm")
845
+ return grammar if selection.canonical
846
+
847
+ require_relative "configuration/analysis_grammar"
848
+ algorithm = selection.value #: Symbol
849
+ Configuration::AnalysisGrammar.for_algorithm(grammar, algorithm)
850
+ end
851
+
852
+ # @rbs (Configuration::Resolver configuration) -> void
853
+ def report_noncanonical_analysis(configuration)
854
+ selection = configuration.fetch("parser.algorithm")
855
+ return if selection.canonical
856
+
857
+ analysis = selection.to_h.fetch("analysis") #: Hash[String, Configuration::json_value]
858
+ @stderr.puts(
859
+ "noncanonical analysis configuration: parser.algorithm " \
860
+ "declared=#{analysis.fetch('declared')} selected=#{analysis.fetch('selected')} " \
861
+ "override=true canonical_generation=false"
862
+ )
863
+ end
864
+
586
865
  # @rbs () -> Integer
587
866
  def print_version
588
867
  @stdout.puts("ibex #{VERSION}")
@@ -654,18 +933,27 @@ module Ibex
654
933
 
655
934
  # @rbs (IR::Automaton automaton, String input_path) -> Integer
656
935
  def generate_ruby(automaton, input_path)
936
+ @generation_automaton = automaton
937
+ line_mapping = configuration_value("source.line_mapping") #: Symbol
938
+ executable = configuration_value("build.executable") #: String?
939
+ table = configuration_value("table.representation") #: Symbol | String
940
+ embedded = configuration_value("runtime.embedded") #: bool
941
+ debug = configuration_value("build.debug") #: bool
942
+ omit_action_call = configuration_value("actions.omit_calls") #: bool?
943
+ superclass = configuration_value("parser.superclass") #: String?
944
+ cst_trivia = configuration_value("cst.trivia") #: Symbol | String
657
945
  source = Codegen::Ruby.new(
658
- automaton, table: @options[:table], embedded: @options.fetch(:embedded, false),
659
- line_convert: @options.fetch(:line_convert), debug: @options.fetch(:debug, false),
660
- line_convert_all: @options.fetch(:line_convert_all, false),
661
- omit_action_call: @options[:omit_actions], superclass: @options[:superclass],
662
- executable: @options[:executable], cst_trivia: @options.fetch(:cst_trivia, :leading),
946
+ automaton, table: table, embedded: embedded,
947
+ line_convert: line_mapping != :none, debug: debug,
948
+ line_convert_all: line_mapping == :all,
949
+ omit_action_call: omit_action_call, superclass: superclass,
950
+ executable: executable, cst_trivia: cst_trivia,
663
951
  error_messages: configured_error_messages(automaton)
664
952
  ).generate
665
953
  output_path = @options[:output] || default_output_path(input_path, ".rb")
666
954
  action_source = action_source_source(automaton) if @options[:action_source]
667
955
  write_action_source(output_path, action_source) if action_source
668
- register_artifact(:parser, output_path, source, mode: (0o755 if @options[:executable]), status: true)
956
+ register_artifact(:parser, output_path, source, mode: (0o755 if executable), status: true)
669
957
  write_rbs(automaton, output_path) if @options[:rbs]
670
958
  finish_artifact_generation(@generation_sources)
671
959
  end
@@ -706,8 +994,10 @@ module Ibex
706
994
  # @rbs (IR::Automaton automaton) -> String
707
995
  def rbs_source(automaton)
708
996
  require_relative "codegen/rbs"
997
+ superclass = configuration_value("parser.superclass") #: String?
998
+ omit_action_call = configuration_value("actions.omit_calls") #: bool?
709
999
  Codegen::RBS.new(
710
- automaton, superclass: @options[:superclass], omit_action_call: @options[:omit_actions]
1000
+ automaton, superclass: superclass, omit_action_call: omit_action_call
711
1001
  ).generate
712
1002
  end
713
1003
 
@@ -729,7 +1019,9 @@ module Ibex
729
1019
  # @rbs (IR::Automaton automaton) -> String
730
1020
  def action_source_source(automaton)
731
1021
  require_relative "codegen/action_source"
732
- Codegen::ActionSource.new(automaton, omit_action_call: @options[:omit_actions]).generate
1022
+ Codegen::ActionSource.new(
1023
+ automaton, omit_action_call: configuration_value("actions.omit_calls")
1024
+ ).generate
733
1025
  end
734
1026
 
735
1027
  # @rbs (IR::Automaton automaton, String input_path) -> Integer
@@ -742,11 +1034,14 @@ module Ibex
742
1034
 
743
1035
  # @rbs (IR::Grammar grammar, String input_path) -> IR::Automaton
744
1036
  def build_automaton(grammar, input_path)
745
- algorithm = @options[:algorithm] || :lalr
1037
+ algorithm = configuration_value("parser.algorithm")
746
1038
  report_status("building #{algorithm} automaton")
747
1039
  automaton = LALR::Builder.new(
748
- grammar, algorithm: algorithm, entry_isolation: @options[:entry_isolation] == true
1040
+ grammar, algorithm: algorithm, ielr_strategy: @options.fetch(:ielr_strategy, :partition),
1041
+ remove_unreachable: @options.fetch(:remove_unreachable, false),
1042
+ entry_isolation: configuration_value("parser.entries") == :isolated
749
1043
  ).build
1044
+ write_ielr_report(grammar, automaton) if @options[:ielr_report]
750
1045
  report_conflicts(automaton, input_path)
751
1046
  suggest_ielr(automaton, input_path)
752
1047
  write_report(automaton, input_path) if @options[:verbose] && !@options[:verify_output]
@@ -754,6 +1049,12 @@ module Ibex
754
1049
  automaton
755
1050
  end
756
1051
 
1052
+ # @rbs (IR::Grammar grammar, IR::Automaton automaton) -> void
1053
+ def write_ielr_report(grammar, automaton)
1054
+ canonical = LALR::Builder.new(grammar, algorithm: :lr1).build
1055
+ @stdout.write(LALR::InadequacyReport.new(canonical, automaton).to_json)
1056
+ end
1057
+
757
1058
  # @rbs (IR::Automaton automaton, String input_path) -> void
758
1059
  def prepare_loaded_automaton(automaton, input_path)
759
1060
  report_conflicts(automaton, input_path)
@@ -798,5 +1099,10 @@ module Ibex
798
1099
  default_output_path(output_path, ".ibex.json")
799
1100
  end
800
1101
  end
1102
+ CONFIG_SUBCOMMAND_HELP = [
1103
+ " coverage collect, merge, or check runtime coverage",
1104
+ " config explain effective configuration without running user code"
1105
+ ].join("\n").freeze #: String
1106
+ autoload :CLIConfig, File.join(CLI_FEATURE_ROOT, "config")
801
1107
  # rubocop:enable Metrics/ClassLength
802
1108
  end