ibex 0.2.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 (437) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +95 -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 +262 -0
  40. data/docs/development.md +179 -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 +1581 -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/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 +5 -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 +11 -0
  63. data/docs/release-readiness.md +126 -68
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +144 -34
  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/lib/ibex/analysis/digraph.rb +128 -0
  75. data/lib/ibex/analysis.rb +1 -0
  76. data/lib/ibex/bison_import/importer.rb +516 -0
  77. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  78. data/lib/ibex/bison_import.rb +200 -0
  79. data/lib/ibex/bounded_subprocess.rb +171 -0
  80. data/lib/ibex/cli/ambiguity.rb +14 -5
  81. data/lib/ibex/cli/analysis.rb +134 -0
  82. data/lib/ibex/cli/bison_import.rb +121 -0
  83. data/lib/ibex/cli/config.rb +128 -0
  84. data/lib/ibex/cli/diagnostics.rb +31 -11
  85. data/lib/ibex/cli/documentation.rb +11 -8
  86. data/lib/ibex/cli/equiv.rb +169 -0
  87. data/lib/ibex/cli/error_messages.rb +11 -4
  88. data/lib/ibex/cli/explain.rb +14 -5
  89. data/lib/ibex/cli/fix.rb +203 -0
  90. data/lib/ibex/cli/formatting.rb +11 -10
  91. data/lib/ibex/cli/fuzz.rb +200 -0
  92. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  93. data/lib/ibex/cli/generation_artifacts.rb +53 -2
  94. data/lib/ibex/cli/generation_error_messages.rb +1 -1
  95. data/lib/ibex/cli/grammar_tests.rb +32 -14
  96. data/lib/ibex/cli/ir_tools.rb +5 -61
  97. data/lib/ibex/cli/outputs.rb +60 -33
  98. data/lib/ibex/cli/reduce.rb +202 -0
  99. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  100. data/lib/ibex/cli/samples.rb +49 -23
  101. data/lib/ibex/cli/verify.rb +116 -0
  102. data/lib/ibex/cli/watch.rb +6 -5
  103. data/lib/ibex/cli.rb +357 -56
  104. data/lib/ibex/codegen/action_locations.rb +1 -1
  105. data/lib/ibex/codegen/action_method_source.rb +5 -6
  106. data/lib/ibex/codegen/action_source.rb +3 -2
  107. data/lib/ibex/codegen/ambiguity.rb +5 -4
  108. data/lib/ibex/codegen/explain.rb +123 -55
  109. data/lib/ibex/codegen/generated_action_abi.rb +10 -5
  110. data/lib/ibex/codegen/rbs.rb +15 -7
  111. data/lib/ibex/codegen/report.rb +25 -13
  112. data/lib/ibex/codegen/ruby.rb +28 -64
  113. data/lib/ibex/codegen/ruby_actions.rb +9 -6
  114. data/lib/ibex/codegen/ruby_syntax.rb +15 -9
  115. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  116. data/lib/ibex/configuration/explanation.rb +421 -0
  117. data/lib/ibex/configuration/inspector.rb +232 -0
  118. data/lib/ibex/configuration.rb +580 -0
  119. data/lib/ibex/coverage/collector.rb +21 -11
  120. data/lib/ibex/coverage/event_stream.rb +13 -7
  121. data/lib/ibex/coverage/report.rb +26 -18
  122. data/lib/ibex/coverage/runtime_event_validator.rb +30 -21
  123. data/lib/ibex/delta_reducer.rb +99 -0
  124. data/lib/ibex/diff.rb +140 -0
  125. data/lib/ibex/equiv/machine.rb +135 -0
  126. data/lib/ibex/equiv.rb +373 -0
  127. data/lib/ibex/fix.rb +557 -0
  128. data/lib/ibex/frontend/ast.rb +22 -2
  129. data/lib/ibex/frontend/bootstrap_parser.rb +6 -13
  130. data/lib/ibex/frontend/diagnostic.rb +1 -1
  131. data/lib/ibex/frontend/formatter.rb +72 -26
  132. data/lib/ibex/frontend/generated_parser.rb +147 -117
  133. data/lib/ibex/frontend/generated_parser_base.rb +7 -3
  134. data/lib/ibex/frontend/generated_parser_includes.rb +1 -11
  135. data/lib/ibex/frontend/generation.rb +1 -1
  136. data/lib/ibex/frontend/parser/declarations.rb +17 -2
  137. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  138. data/lib/ibex/frontend/regenerator.rb +1 -0
  139. data/lib/ibex/frontend/resolution.rb +2 -1
  140. data/lib/ibex/frontend/resolver.rb +1 -1
  141. data/lib/ibex/frontend/rule_documentation.rb +2 -1
  142. data/lib/ibex/frontend/source_cursor.rb +2 -2
  143. data/lib/ibex/frontend/source_span.rb +9 -1
  144. data/lib/ibex/frontend/token_adapter/declaration_state.rb +38 -6
  145. data/lib/ibex/frontend/token_adapter.rb +10 -0
  146. data/lib/ibex/frontend.rb +1 -0
  147. data/lib/ibex/fuzz.rb +219 -0
  148. data/lib/ibex/generation_input.rb +1 -1
  149. data/lib/ibex/generation_manifest.rb +36 -25
  150. data/lib/ibex/generation_transaction.rb +1 -1
  151. data/lib/ibex/generation_transaction_recovery.rb +4 -4
  152. data/lib/ibex/generation_transaction_validation.rb +2 -2
  153. data/lib/ibex/grammar_tests.rb +1 -1
  154. data/lib/ibex/ir/automaton_ir.rb +61 -19
  155. data/lib/ibex/ir/grammar_ir.rb +76 -45
  156. data/lib/ibex/ir/lexer_ir.rb +5 -5
  157. data/lib/ibex/ir/parser_contract.rb +135 -0
  158. data/lib/ibex/ir/serialize.rb +203 -76
  159. data/lib/ibex/ir/validator/automaton.rb +64 -34
  160. data/lib/ibex/ir/validator/base.rb +51 -33
  161. data/lib/ibex/ir/validator/grammar.rb +113 -83
  162. data/lib/ibex/ir/validator/lexer.rb +2 -2
  163. data/lib/ibex/ir/validator.rb +2 -1
  164. data/lib/ibex/ir.rb +16 -3
  165. data/lib/ibex/lalr/build_metrics.rb +50 -2
  166. data/lib/ibex/lalr/builder.rb +191 -56
  167. data/lib/ibex/lalr/conflict_search.rb +15 -4
  168. data/lib/ibex/lalr/counterexample.rb +19 -14
  169. data/lib/ibex/lalr/direct_lookaheads.rb +110 -57
  170. data/lib/ibex/lalr/goto_follows.rb +229 -0
  171. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  172. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  173. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  174. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  175. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  176. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  177. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  178. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  179. data/lib/ibex/lalr/ielr_partition.rb +22 -8
  180. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  181. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  182. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  183. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  184. data/lib/ibex/lalr.rb +52 -1
  185. data/lib/ibex/location.rb +3 -3
  186. data/lib/ibex/lsp/document_handlers.rb +9 -7
  187. data/lib/ibex/lsp/initialization_handlers.rb +9 -7
  188. data/lib/ibex/lsp/navigation_handlers.rb +25 -11
  189. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  190. data/lib/ibex/lsp/position_codec.rb +6 -2
  191. data/lib/ibex/lsp/request_handlers.rb +3 -2
  192. data/lib/ibex/lsp/request_support.rb +14 -7
  193. data/lib/ibex/lsp/server.rb +13 -11
  194. data/lib/ibex/lsp/symbol_index.rb +13 -13
  195. data/lib/ibex/lsp/symbol_index_builder.rb +30 -20
  196. data/lib/ibex/lsp/symbol_occurrence.rb +8 -2
  197. data/lib/ibex/lsp/transport.rb +13 -3
  198. data/lib/ibex/lsp/workspace.rb +5 -4
  199. data/lib/ibex/lsp/workspace_analyzer.rb +1 -1
  200. data/lib/ibex/lsp.rb +1 -0
  201. data/lib/ibex/messages/en.yml +28 -0
  202. data/lib/ibex/messages/ja.yml +28 -0
  203. data/lib/ibex/messages.rb +68 -0
  204. data/lib/ibex/metrics.rb +175 -0
  205. data/lib/ibex/normalize/declarations.rb +2 -0
  206. data/lib/ibex/normalize/diagnostics.rb +63 -38
  207. data/lib/ibex/normalize/expander.rb +5 -4
  208. data/lib/ibex/normalize/expression.rb +8 -6
  209. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  210. data/lib/ibex/normalize/inline_expansion.rb +100 -49
  211. data/lib/ibex/normalize/lexer.rb +3 -3
  212. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +11 -10
  213. data/lib/ibex/normalize/parameter_lowering.rb +40 -23
  214. data/lib/ibex/normalize/parameters.rb +31 -4
  215. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  216. data/lib/ibex/normalize.rb +10 -20
  217. data/lib/ibex/racc_migration/report.rb +6 -3
  218. data/lib/ibex/rake_task.rb +1 -1
  219. data/lib/ibex/samples.rb +43 -13
  220. data/lib/ibex/table_artifact/builder.rb +266 -0
  221. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  222. data/lib/ibex/table_artifact/document.rb +39 -0
  223. data/lib/ibex/table_artifact/executor.rb +187 -0
  224. data/lib/ibex/table_artifact/serializer.rb +57 -0
  225. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  226. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  227. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  228. data/lib/ibex/table_artifact/validator.rb +253 -0
  229. data/lib/ibex/table_artifact.rb +88 -0
  230. data/lib/ibex/table_simulation/result.rb +6 -2
  231. data/lib/ibex/table_simulation/step.rb +3 -1
  232. data/lib/ibex/tables.rb +14 -0
  233. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  234. data/lib/ibex/verification_report/builder.rb +159 -0
  235. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  236. data/lib/ibex/verification_report/logical_path.rb +68 -0
  237. data/lib/ibex/verification_report/validator.rb +329 -0
  238. data/lib/ibex/verification_report.rb +69 -0
  239. data/lib/ibex/verify/action_correspondence.rb +138 -0
  240. data/lib/ibex/verify/language_witness.rb +295 -0
  241. data/lib/ibex/verify/reference_collection.rb +190 -0
  242. data/lib/ibex/verify/result.rb +73 -0
  243. data/lib/ibex/verify/verifier.rb +598 -0
  244. data/lib/ibex/verify.rb +15 -0
  245. data/lib/ibex/version.rb +1 -1
  246. data/lib/ibex/watch/runner.rb +10 -1
  247. data/lib/ibex/watch/source_snapshot.rb +13 -8
  248. data/lib/ibex.rb +10 -0
  249. data/schema/{automaton-ir-v1.schema.json → automaton-ir-definitions.schema.json} +6 -6
  250. data/schema/{automaton-ir-v2.schema.json → automaton-ir.schema.json} +14 -7
  251. data/schema/bison-import-v1.schema.json +106 -0
  252. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  253. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  254. data/schema/construction-profile-v1.schema.json +779 -0
  255. data/schema/diff-v1.schema.json +41 -0
  256. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  257. data/schema/equiv-v1.schema.json +64 -0
  258. data/schema/error-ux-review-v1.schema.json +609 -0
  259. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  260. data/schema/error-ux-round2-v1.schema.json +519 -0
  261. data/schema/explain-v1.schema.json +63 -1
  262. data/schema/fix-v1.schema.json +64 -0
  263. data/schema/fix-v2.schema.json +66 -0
  264. data/schema/fix-v3.schema.json +101 -0
  265. data/schema/fuzz-regression-v1.schema.json +79 -0
  266. data/schema/fuzz-v1.schema.json +114 -0
  267. data/schema/{grammar-ir-v2.schema.json → grammar-ir-extensions.schema.json} +20 -65
  268. data/schema/{grammar-ir-v1.schema.json → grammar-ir-foundation.schema.json} +3 -3
  269. data/schema/grammar-ir.schema.json +271 -0
  270. data/schema/ielr-benchmark-v1.schema.json +85 -0
  271. data/schema/lexer-profile-v1.schema.json +491 -0
  272. data/schema/metrics-v1.schema.json +60 -0
  273. data/schema/reduce-v1.schema.json +22 -0
  274. data/schema/reduce-v2.schema.json +63 -0
  275. data/schema/table-artifact-v1.schema.json +377 -0
  276. data/schema/verification-report-v1.schema.json +222 -0
  277. data/schema/verify-v1.schema.json +42 -0
  278. data/sig/ibex/analysis/digraph.rbs +19 -0
  279. data/sig/ibex/bison_import/importer.rbs +140 -0
  280. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  281. data/sig/ibex/bison_import.rbs +95 -0
  282. data/sig/ibex/bounded_subprocess.rbs +76 -0
  283. data/sig/ibex/cli/ambiguity.rbs +6 -0
  284. data/sig/ibex/cli/analysis.rbs +43 -0
  285. data/sig/ibex/cli/bison_import.rbs +32 -0
  286. data/sig/ibex/cli/config.rbs +35 -0
  287. data/sig/ibex/cli/diagnostics.rbs +16 -3
  288. data/sig/ibex/cli/documentation.rbs +5 -1
  289. data/sig/ibex/cli/equiv.rbs +49 -0
  290. data/sig/ibex/cli/error_messages.rbs +6 -0
  291. data/sig/ibex/cli/explain.rbs +6 -0
  292. data/sig/ibex/cli/fix.rbs +53 -0
  293. data/sig/ibex/cli/formatting.rbs +5 -1
  294. data/sig/ibex/cli/fuzz.rbs +47 -0
  295. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  296. data/sig/ibex/cli/generation_artifacts.rbs +21 -2
  297. data/sig/ibex/cli/generation_error_messages.rbs +2 -2
  298. data/sig/ibex/cli/grammar_tests.rbs +15 -3
  299. data/sig/ibex/cli/ir_tools.rbs +7 -19
  300. data/sig/ibex/cli/outputs.rbs +9 -3
  301. data/sig/ibex/cli/reduce.rbs +60 -0
  302. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  303. data/sig/ibex/cli/samples.rbs +8 -0
  304. data/sig/ibex/cli/verify.rbs +28 -0
  305. data/sig/ibex/cli/watch.rbs +2 -2
  306. data/sig/ibex/cli.rbs +79 -5
  307. data/sig/ibex/codegen/action_method_source.rbs +4 -4
  308. data/sig/ibex/codegen/explain.rbs +45 -25
  309. data/sig/ibex/codegen/generated_action_abi.rbs +14 -10
  310. data/sig/ibex/codegen/rbs.rbs +12 -10
  311. data/sig/ibex/codegen/report.rbs +12 -12
  312. data/sig/ibex/codegen/ruby.rbs +18 -15
  313. data/sig/ibex/codegen/ruby_actions.rbs +6 -6
  314. data/sig/ibex/codegen/ruby_syntax.rbs +10 -8
  315. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  316. data/sig/ibex/configuration/explanation.rbs +195 -0
  317. data/sig/ibex/configuration/inspector.rbs +53 -0
  318. data/sig/ibex/configuration.rbs +242 -0
  319. data/sig/ibex/coverage/collector.rbs +16 -14
  320. data/sig/ibex/coverage/event_stream.rbs +12 -10
  321. data/sig/ibex/coverage/report.rbs +20 -18
  322. data/sig/ibex/coverage/runtime_event_validator.rbs +38 -36
  323. data/sig/ibex/delta_reducer.rbs +38 -0
  324. data/sig/ibex/diff.rbs +47 -0
  325. data/sig/ibex/equiv/machine.rbs +54 -0
  326. data/sig/ibex/equiv.rbs +129 -0
  327. data/sig/ibex/fix.rbs +138 -0
  328. data/sig/ibex/frontend/ast.rbs +33 -7
  329. data/sig/ibex/frontend/bootstrap_parser.rbs +2 -0
  330. data/sig/ibex/frontend/diagnostic.rbs +2 -2
  331. data/sig/ibex/frontend/formatter.rbs +38 -30
  332. data/sig/ibex/frontend/generated_parser.rbs +87 -77
  333. data/sig/ibex/frontend/generated_parser_base.rbs +4 -2
  334. data/sig/ibex/frontend/parser/declarations.rbs +3 -0
  335. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  336. data/sig/ibex/frontend/resolution.rbs +3 -2
  337. data/sig/ibex/frontend/source_cursor.rbs +2 -2
  338. data/sig/ibex/frontend/source_span.rbs +5 -2
  339. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +13 -1
  340. data/sig/ibex/frontend/token_adapter.rbs +6 -0
  341. data/sig/ibex/fuzz.rbs +71 -0
  342. data/sig/ibex/generation_input.rbs +2 -2
  343. data/sig/ibex/generation_manifest.rbs +35 -32
  344. data/sig/ibex/generation_transaction_recovery.rbs +2 -2
  345. data/sig/ibex/generation_transaction_validation.rbs +2 -2
  346. data/sig/ibex/grammar_tests.rbs +2 -2
  347. data/sig/ibex/ir/automaton_ir.rbs +30 -11
  348. data/sig/ibex/ir/grammar_ir.rbs +41 -27
  349. data/sig/ibex/ir/lexer_ir.rbs +8 -8
  350. data/sig/ibex/ir/parser_contract.rbs +69 -0
  351. data/sig/ibex/ir/serialize.rbs +63 -28
  352. data/sig/ibex/ir/validator/automaton.rbs +47 -44
  353. data/sig/ibex/ir/validator/base.rbs +35 -31
  354. data/sig/ibex/ir/validator/grammar.rbs +78 -67
  355. data/sig/ibex/ir/validator/lexer.rbs +4 -4
  356. data/sig/ibex/ir.rbs +9 -3
  357. data/sig/ibex/lalr/build_metrics.rbs +42 -2
  358. data/sig/ibex/lalr/builder.rbs +75 -24
  359. data/sig/ibex/lalr/conflict_search.rbs +5 -2
  360. data/sig/ibex/lalr/counterexample.rbs +17 -14
  361. data/sig/ibex/lalr/direct_lookaheads.rbs +35 -28
  362. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  363. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  364. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  365. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  366. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  367. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  368. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  369. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  370. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  371. data/sig/ibex/lalr/ielr_partition.rbs +17 -5
  372. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  373. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  374. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  375. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  376. data/sig/ibex/lalr.rbs +11 -1
  377. data/sig/ibex/location.rbs +6 -6
  378. data/sig/ibex/lsp/document_handlers.rbs +8 -8
  379. data/sig/ibex/lsp/initialization_handlers.rbs +12 -12
  380. data/sig/ibex/lsp/navigation_handlers.rbs +15 -12
  381. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  382. data/sig/ibex/lsp/position_codec.rbs +8 -4
  383. data/sig/ibex/lsp/request_handlers.rbs +4 -4
  384. data/sig/ibex/lsp/request_support.rbs +8 -8
  385. data/sig/ibex/lsp/server.rbs +16 -16
  386. data/sig/ibex/lsp/symbol_index.rbs +20 -21
  387. data/sig/ibex/lsp/symbol_index_builder.rbs +9 -8
  388. data/sig/ibex/lsp/symbol_occurrence.rbs +11 -5
  389. data/sig/ibex/lsp/transport.rbs +18 -6
  390. data/sig/ibex/lsp/workspace.rbs +3 -2
  391. data/sig/ibex/lsp/workspace_analyzer.rbs +1 -1
  392. data/sig/ibex/messages.rbs +26 -0
  393. data/sig/ibex/metrics.rbs +50 -0
  394. data/sig/ibex/normalize/diagnostics.rbs +4 -4
  395. data/sig/ibex/normalize/expander.rbs +2 -2
  396. data/sig/ibex/normalize/expression.rbs +10 -8
  397. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  398. data/sig/ibex/normalize/inline_expansion.rbs +59 -50
  399. data/sig/ibex/normalize/lexer.rbs +4 -4
  400. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +15 -14
  401. data/sig/ibex/normalize/parameter_lowering.rbs +18 -18
  402. data/sig/ibex/normalize/parameters.rbs +13 -8
  403. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  404. data/sig/ibex/normalize.rbs +11 -5
  405. data/sig/ibex/racc_migration/report.rbs +8 -6
  406. data/sig/ibex/rake_task.rbs +1 -1
  407. data/sig/ibex/samples.rbs +13 -4
  408. data/sig/ibex/table_artifact/builder.rbs +93 -0
  409. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  410. data/sig/ibex/table_artifact/document.rbs +27 -0
  411. data/sig/ibex/table_artifact/executor.rbs +66 -0
  412. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  413. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  414. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  415. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  416. data/sig/ibex/table_artifact/validator.rbs +66 -0
  417. data/sig/ibex/table_artifact.rbs +32 -0
  418. data/sig/ibex/table_simulation/result.rbs +8 -4
  419. data/sig/ibex/table_simulation/step.rbs +4 -2
  420. data/sig/ibex/tables.rbs +10 -9
  421. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  422. data/sig/ibex/verification_report/builder.rbs +53 -0
  423. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  424. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  425. data/sig/ibex/verification_report/validator.rbs +114 -0
  426. data/sig/ibex/verification_report.rbs +44 -0
  427. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  428. data/sig/ibex/verify/language_witness.rbs +112 -0
  429. data/sig/ibex/verify/reference_collection.rbs +63 -0
  430. data/sig/ibex/verify/result.rbs +52 -0
  431. data/sig/ibex/verify/verifier.rbs +170 -0
  432. data/sig/ibex/verify.rbs +6 -0
  433. data/sig/ibex/watch/runner.rbs +12 -2
  434. data/sig/ibex/watch/source_snapshot.rbs +13 -9
  435. metadata +232 -12
  436. data/lib/ibex/ir/migration.rb +0 -120
  437. data/sig/ibex/ir/migration.rbs +0 -34
@@ -20,10 +20,10 @@ module Ibex
20
20
  @snapshot_state = files.to_h do |file|
21
21
  snapshot = store.snapshot_for(file)
22
22
  [file, snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]]
23
- end #: Hash[String, Array[untyped]?]
23
+ end #: Hash[String, [Integer?, String]?]
24
24
  end
25
25
 
26
- # @rbs (String path, Hash[String, untyped] position) -> Array[Hash[String, untyped]]
26
+ # @rbs (String path, lsp_object position) -> Array[lsp_object]
27
27
  def definition(path, position)
28
28
  occurrence = occurrence_at(path, position)
29
29
  return [] unless occurrence
@@ -32,8 +32,7 @@ module Ibex
32
32
  matching(occurrence.key, role: :definition).map { |entry| location(entry) }
33
33
  end
34
34
 
35
- # @rbs (String path, Hash[String, untyped] position, ?include_declaration: bool) ->
36
- # Array[Hash[String, untyped]]
35
+ # @rbs (String path, lsp_object position, ?include_declaration: bool) -> Array[lsp_object]
37
36
  def references(path, position, include_declaration: false)
38
37
  occurrence = occurrence_at(path, position)
39
38
  return [] unless occurrence
@@ -43,13 +42,13 @@ module Ibex
43
42
  entries.map { |entry| location(entry) }
44
43
  end
45
44
 
46
- # @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
45
+ # @rbs (String path, lsp_object position) -> lsp_object?
47
46
  def prepare_rename(path, position)
48
47
  occurrence = renameable_occurrence(path, position)
49
48
  { "range" => range(occurrence), "placeholder" => occurrence.name }
50
49
  end
51
50
 
52
- # @rbs (String path, Hash[String, untyped] position, String new_name) -> Hash[String, untyped]
51
+ # @rbs (String path, lsp_object position, String new_name) -> lsp_object
53
52
  def rename(path, position, new_name)
54
53
  ensure_fresh!
55
54
  occurrence = renameable_occurrence(path, position)
@@ -78,7 +77,7 @@ module Ibex
78
77
  { "documentChanges" => document_changes }
79
78
  end
80
79
 
81
- # @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
80
+ # @rbs (String path, lsp_object position) -> lsp_object?
82
81
  def hover(path, position)
83
82
  occurrence = occurrence_at(path, position)
84
83
  return unless occurrence
@@ -94,7 +93,7 @@ module Ibex
94
93
 
95
94
  private
96
95
 
97
- # @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence?
96
+ # @rbs (String path, lsp_object position) -> SymbolOccurrence?
98
97
  def occurrence_at(path, position)
99
98
  document = @documents[path]
100
99
  return unless document
@@ -106,17 +105,17 @@ module Ibex
106
105
  candidates.min_by { |entry| entry.span.length }
107
106
  end
108
107
 
109
- # @rbs (Array[untyped] key, ?role: Symbol?) -> Array[SymbolOccurrence]
108
+ # @rbs (symbol_key key, ?role: Symbol?) -> Array[SymbolOccurrence]
110
109
  def matching(key, role: nil)
111
110
  @occurrences.select { |entry| entry.key == key && (!role || entry.role == role) }
112
111
  end
113
112
 
114
- # @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
113
+ # @rbs (SymbolOccurrence occurrence) -> lsp_object
115
114
  def location(occurrence)
116
115
  { "uri" => @store.uri_for(occurrence.path), "range" => range(occurrence) }
117
116
  end
118
117
 
119
- # @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
118
+ # @rbs (SymbolOccurrence occurrence) -> lsp_object
120
119
  def include_target_location(occurrence)
121
120
  target = occurrence.data.fetch(:target)
122
121
  point = { "line" => 0, "character" => 0 }
@@ -129,7 +128,7 @@ module Ibex
129
128
  PositionCodec.new(document.source).range(occurrence.span)
130
129
  end
131
130
 
132
- # @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence
131
+ # @rbs (String path, lsp_object position) -> SymbolOccurrence
133
132
  def renameable_occurrence(path, position)
134
133
  occurrence = occurrence_at(path, position)
135
134
  unless occurrence && %i[rule terminal parameter].include?(occurrence.kind) &&
@@ -232,7 +231,8 @@ module Ibex
232
231
  lines << "Display: #{data[:display]}" if data[:display]
233
232
  lines << "Type: `#{data[:type]}`" if data[:type]
234
233
  if (precedence = data[:precedence])
235
- lines << "Precedence: #{precedence[:associativity]} level #{precedence[:level]}"
234
+ precedence_data = precedence #: Hash[Symbol, symbol_data_value]
235
+ lines << "Precedence: #{precedence_data[:associativity]} level #{precedence_data[:level]}"
236
236
  end
237
237
  lines.join("\n\n")
238
238
  end
@@ -14,8 +14,8 @@ module Ibex
14
14
  @occurrences = [] #: Array[SymbolOccurrence]
15
15
  @documents = {} #: Hash[String, Frontend::SourceDocument]
16
16
  @global_kinds = {} #: Hash[String, Symbol]
17
- @rule_data = {} #: Hash[String, Hash[Symbol, untyped]]
18
- @terminal_data = Hash.new { |hash, key| hash[key] = {} } #: Hash[String, Hash[Symbol, untyped]]
17
+ @rule_data = {} #: Hash[String, symbol_data]
18
+ @terminal_data = Hash.new { |hash, key| hash[key] = {} } #: Hash[String, symbol_data]
19
19
  end
20
20
 
21
21
  # @rbs () -> [Array[SymbolOccurrence], Hash[String, Frontend::SourceDocument]]
@@ -85,21 +85,25 @@ module Ibex
85
85
  # @rbs (String path, Array[Frontend::Token] tokens, Frontend::AST::Include declaration) -> void
86
86
  def collect_include(path, tokens, declaration)
87
87
  token = tokens.find { |candidate| candidate.type == :literal }
88
- return unless token&.span
88
+ span = token&.span
89
+ return unless span
89
90
 
90
91
  target = canonical_include_target(declaration)
91
92
  return unless target
92
93
 
93
94
  add_occurrence(
94
95
  name: declaration.path, kind: :include, role: :reference, key: [:include, target],
95
- path: path, span: token.span, data: { target: target }
96
+ path: path, span: span, data: { target: target }
96
97
  )
97
98
  end
98
99
 
99
100
  # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule) -> void
100
101
  def collect_rule_definition(path, document, rule)
101
102
  token = token_at(document, rule.loc, rule.lhs)
102
- return unless token&.span
103
+ span = token&.span
104
+ return unless span
105
+
106
+ lhs_token = token #: Frontend::Token
103
107
 
104
108
  @global_kinds[rule.lhs] ||= :rule
105
109
  signature = "#{rule.lhs}#{parameter_signature(rule.parameters)}"
@@ -113,9 +117,9 @@ module Ibex
113
117
  @rule_data[rule.lhs] ||= data
114
118
  add_occurrence(
115
119
  name: rule.lhs, kind: :rule, role: :definition, key: global_key(rule.lhs),
116
- path: path, span: token.span, data: data
120
+ path: path, span: span, data: data
117
121
  )
118
- collect_parameters(path, document, rule, token)
122
+ collect_parameters(path, document, rule, lhs_token)
119
123
  end
120
124
 
121
125
  # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule,
@@ -125,11 +129,12 @@ module Ibex
125
129
 
126
130
  rule_id = lhs_token.span&.start_byte || 0
127
131
  rule.parameters.zip(parameter_tokens(document, lhs_token)).each do |parameter, token|
128
- next unless token&.span
132
+ span = token&.span
133
+ next unless span
129
134
 
130
135
  add_occurrence(
131
136
  name: parameter, kind: :parameter, role: :definition,
132
- key: parameter_key(path, rule_id, parameter), path: path, span: token.span,
137
+ key: parameter_key(path, rule_id, parameter), path: path, span: span,
133
138
  data: { rule: rule.lhs }
134
139
  )
135
140
  end
@@ -205,18 +210,19 @@ module Ibex
205
210
 
206
211
  # @rbs (String path, Frontend::Token token, String name) -> void
207
212
  def add_global_reference(path, token, name)
208
- return unless token.span
213
+ span = token.span
214
+ return unless span
209
215
 
210
216
  kind = @global_kinds[name] || :terminal
211
217
  data = symbol_data(kind, name)
212
218
  add_occurrence(name: name, kind: kind, role: :reference, key: global_key(name),
213
- path: path, span: token.span, data: data)
219
+ path: path, span: span, data: data)
214
220
  end
215
221
 
216
- # @rbs (Symbol kind, String name) -> Hash[Symbol, untyped]
222
+ # @rbs (Symbol kind, String name) -> symbol_data
217
223
  def symbol_data(kind, name)
218
224
  data = kind == :rule ? @rule_data[name] : @terminal_data[name]
219
- empty = {} #: Hash[Symbol, untyped]
225
+ empty = {} #: symbol_data
220
226
  data || empty
221
227
  end
222
228
 
@@ -226,25 +232,29 @@ module Ibex
226
232
  names.each do |name|
227
233
  index = remaining.index { |token| token.value == name }
228
234
  token = index && remaining.delete_at(index)
229
- next unless token&.span
235
+ span = token&.span
236
+ next unless span
230
237
 
231
238
  @global_kinds[name] ||= kind
232
239
  add_occurrence(name: name, kind: kind, role: role, key: global_key(name),
233
- path: path, span: token.span, data: @terminal_data[name])
240
+ path: path, span: span, data: @terminal_data[name])
234
241
  end
235
242
  end
236
243
 
237
- # @rbs (**untyped attributes) -> void
238
- def add_occurrence(**attributes)
239
- @occurrences << SymbolOccurrence.new(**attributes)
244
+ # @rbs (name: String, kind: Symbol, role: Symbol, key: symbol_key, path: String,
245
+ # span: Frontend::SourceSpan, data: symbol_data) -> void
246
+ def add_occurrence(name:, kind:, role:, key:, path:, span:, data:)
247
+ @occurrences << SymbolOccurrence.new(
248
+ name: name, kind: kind, role: role, key: key, path: path, span: span, data: data
249
+ )
240
250
  end
241
251
 
242
- # @rbs (String name) -> Array[untyped]
252
+ # @rbs (String name) -> symbol_key
243
253
  def global_key(name)
244
254
  [:symbol, name]
245
255
  end
246
256
 
247
- # @rbs (String path, Integer rule_id, String name) -> Array[untyped]
257
+ # @rbs (String path, Integer rule_id, String name) -> symbol_key
248
258
  def parameter_key(path, rule_id, name)
249
259
  [:parameter, path, rule_id, name]
250
260
  end
@@ -2,15 +2,21 @@
2
2
 
3
3
  module Ibex
4
4
  module LSP
5
+ # @rbs!
6
+ # type symbol_key = [:symbol, String] | [:parameter, String, Integer, String] | [:include, String]
7
+ # type symbol_data_value = String | Symbol | Integer | bool | nil | Array[String] |
8
+ # Hash[Symbol, symbol_data_value]
9
+ # type symbol_data = Hash[Symbol, symbol_data_value]
10
+
5
11
  # A source-backed grammar symbol definition or reference.
6
12
  SymbolOccurrence = Struct.new(
7
13
  :name, #: String
8
14
  :kind, #: Symbol
9
15
  :role, #: Symbol
10
- :key, #: Array[untyped]
16
+ :key, #: symbol_key
11
17
  :path, #: String
12
18
  :span, #: Frontend::SourceSpan
13
- :data, #: Hash[Symbol, untyped]
19
+ :data, #: symbol_data
14
20
  keyword_init: true
15
21
  )
16
22
  end
@@ -4,16 +4,26 @@ module Ibex
4
4
  module LSP
5
5
  # Reads and writes bounded LSP JSON-RPC messages over Content-Length framing.
6
6
  class Transport
7
+ # @rbs!
8
+ # interface _Input
9
+ # def read: (Integer length) -> String?
10
+ # def readpartial: (Integer length) -> String
11
+ # end
12
+ # interface _Output
13
+ # def write: (String value) -> Object?
14
+ # def flush: () -> Object?
15
+ # end
16
+
7
17
  HEADER_SEPARATOR = "\r\n\r\n"
8
18
 
9
- # @rbs (untyped input, untyped output) -> void
19
+ # @rbs (_Input input, _Output output) -> void
10
20
  def initialize(input, output)
11
21
  @input = input
12
22
  @output = output
13
23
  @buffer = String.new(encoding: Encoding::BINARY)
14
24
  end
15
25
 
16
- # @rbs () -> Hash[String, untyped]?
26
+ # @rbs () -> LSP::lsp_object?
17
27
  def read_message
18
28
  header = read_header
19
29
  return unless header
@@ -28,7 +38,7 @@ module Ibex
28
38
  raise ProtocolError.new("malformed JSON: #{e.message}", code: -32_700)
29
39
  end
30
40
 
31
- # @rbs (Hash[String, untyped] message) -> void
41
+ # @rbs (LSP::lsp_object message) -> void
32
42
  def write_message(message)
33
43
  body = JSON.generate(message)
34
44
  if body.bytesize > Limits::MAX_OUTPUT_BYTES
@@ -17,7 +17,7 @@ module Ibex
17
17
  # @rbs (String uri, ?allow_missing: bool) -> String
18
18
  def path(uri, allow_missing: true)
19
19
  parsed = parse_file_uri(uri)
20
- decoded = decode_path(parsed.path)
20
+ decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
21
21
 
22
22
  canonical = @loader.canonical_path(decoded, allow_missing: allow_missing)
23
23
  return canonical if root_for(canonical)
@@ -48,11 +48,12 @@ module Ibex
48
48
  private
49
49
 
50
50
  # URI is a stdlib boundary whose implementation class varies by scheme.
51
- # @rbs (String uri) -> untyped
51
+ # URI parsing returns a scheme-specific URI::Generic subclass.
52
+ # @rbs (String uri) -> URI::Generic
52
53
  def parse_file_uri(uri)
53
54
  validate_raw_authority!(uri)
54
55
  parsed = URI.parse(uri)
55
- path = parsed.path
56
+ path = parsed.path || raise(ArgumentError, "file URI must contain an absolute path")
56
57
  local_host = parsed.host.nil? || parsed.host.empty? || parsed.host.casecmp?("localhost")
57
58
  unless parsed.scheme == "file" && local_host &&
58
59
  parsed.query.nil? && parsed.fragment.nil? && path&.start_with?("/")
@@ -77,7 +78,7 @@ module Ibex
77
78
  # @rbs (String uri) -> String
78
79
  def canonical_root(uri)
79
80
  parsed = parse_file_uri(uri)
80
- decoded = decode_path(parsed.path)
81
+ decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
81
82
  canonical = File.realpath(decoded)
82
83
  unless File.directory?(canonical)
83
84
  raise ProtocolError.new("workspace root is not a directory: #{uri}", code: -32_602)
@@ -8,7 +8,7 @@ module Ibex
8
8
  WINDOWS_ABSOLUTE = %r{\A(?:[A-Za-z]:[\\/]|\\\\)} #: Regexp
9
9
 
10
10
  # @rbs!
11
- # type lsp_diagnostic = Hash[String, untyped]
11
+ # type lsp_diagnostic = lsp_object
12
12
  # type analyzed_document = {
13
13
  # source: String,
14
14
  # document: Frontend::SourceDocument?,
data/lib/ibex/lsp.rb CHANGED
@@ -18,6 +18,7 @@ require_relative "lsp/symbol_index_source_queries"
18
18
  require_relative "lsp/symbol_index_precedence_references"
19
19
  require_relative "lsp/symbol_index_builder"
20
20
  require_relative "lsp/symbol_index"
21
+ require_relative "lsp/parser_configuration_assistance"
21
22
  require_relative "lsp/request_support"
22
23
  require_relative "lsp/initialization_handlers"
23
24
  require_relative "lsp/document_handlers"
@@ -0,0 +1,28 @@
1
+ {
2
+ "version": 1,
3
+ "messages": {
4
+ "cli.error": "%{detail}",
5
+ "diagnostic.frontend.lexical_error": "%{detail}",
6
+ "diagnostic.frontend.syntax_error": "%{detail}",
7
+ "diagnostic.frontend.resolution_error": "%{detail}",
8
+ "diagnostic.generic": "%{detail}",
9
+ "label.warning": "warning",
10
+ "label.warning_as_error": "warning treated as error",
11
+ "warning.undeclared_terminal": "undeclared terminal %{symbol}",
12
+ "warning.unused_terminal": "unused terminal %{symbol}",
13
+ "warning.unused_precedence": "unused precedence %{symbol}",
14
+ "warning.unreachable_terminal": "declared terminal %{symbol} is unreachable",
15
+ "warning.unreachable_nonterminal": "unreachable nonterminal %{symbol}",
16
+ "warning.duplicate_production": "duplicate production %{production} (first defined as %{original})",
17
+ "warning.implicit_empty": "implicit empty alternative; write %%empty to document intent",
18
+ "warning.empty_language": "start symbol %{symbol} derives no terminal sentence",
19
+ "warning.lexer_redos": "lexer pattern may exhibit excessive backtracking",
20
+ "warning.lexer_redos_symbol": "lexer pattern for %{symbol} may exhibit excessive backtracking",
21
+ "conflict.shift_reduce_expected": "%{actual} shift/reduce conflicts; expected %{expected}",
22
+ "conflict.reduce_reduce_expected": "%{actual} reduce/reduce conflicts; expected %{expected}",
23
+ "conflict.reduce_reduce": "%{actual} reduce/reduce conflicts",
24
+ "conflict.treated_as_error": "%{detail}; conflict treated as error",
25
+ "conflict.count": "%{count} %{kind} conflict%{plural}",
26
+ "note.ielr": "note: --algorithm=ielr avoids %{avoided}; consider --algorithm=ielr"
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "version": 1,
3
+ "messages": {
4
+ "cli.error": "エラー: %{detail}",
5
+ "diagnostic.frontend.lexical_error": "字句エラー: %{detail}",
6
+ "diagnostic.frontend.syntax_error": "構文エラー: %{detail}",
7
+ "diagnostic.frontend.resolution_error": "解決エラー: %{detail}",
8
+ "diagnostic.generic": "診断: %{detail}",
9
+ "label.warning": "警告",
10
+ "label.warning_as_error": "エラーとして扱われた警告",
11
+ "warning.undeclared_terminal": "未宣言の終端記号 %{symbol}",
12
+ "warning.unused_terminal": "未使用の終端記号 %{symbol}",
13
+ "warning.unused_precedence": "未使用の優先順位 %{symbol}",
14
+ "warning.unreachable_terminal": "宣言された終端記号 %{symbol} に到達できません",
15
+ "warning.unreachable_nonterminal": "非終端記号 %{symbol} に到達できません",
16
+ "warning.duplicate_production": "生成規則 %{production} は重複しています(最初の定義: %{original})",
17
+ "warning.implicit_empty": "暗黙の空選択肢です。意図を示すには %%empty を記述してください",
18
+ "warning.empty_language": "開始記号 %{symbol} は終端記号列を導出しません",
19
+ "warning.lexer_redos": "字句パターンで過大なバックトラックが発生する可能性があります",
20
+ "warning.lexer_redos_symbol": "%{symbol} の字句パターンで過大なバックトラックが発生する可能性があります",
21
+ "conflict.shift_reduce_expected": "shift/reduce 競合は %{actual} 件です(期待値: %{expected})",
22
+ "conflict.reduce_reduce_expected": "reduce/reduce 競合は %{actual} 件です(期待値: %{expected})",
23
+ "conflict.reduce_reduce": "reduce/reduce 競合が %{actual} 件あります",
24
+ "conflict.treated_as_error": "%{detail}(競合をエラーとして扱いました)",
25
+ "conflict.count": "%{kind} 競合 %{count} 件%{plural}",
26
+ "note.ielr": "注記: --algorithm=ielr により %{avoided} を回避できます。--algorithm=ielr を検討してください"
27
+ }
28
+ }
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "json"
5
+
6
+ module Ibex
7
+ # Immutable built-in diagnostic translations, separate from user E00xx
8
+ # sentence-keyed parser error catalogs.
9
+ module Messages
10
+ ROOT = File.expand_path("messages", __dir__ || raise("message catalog directory is unavailable")) #: String
11
+ LANGUAGES = %w[en ja].freeze #: Array[String]
12
+
13
+ # @rbs (String? requested) -> String
14
+ def language(requested)
15
+ candidate = requested.to_s.downcase.tr("_", "-").split("-").first
16
+ LANGUAGES.include?(candidate) ? candidate : "en"
17
+ end
18
+ module_function :language
19
+
20
+ # @rbs (String id, ?language: String, **Object? values) -> String
21
+ def translate(id, language: "en", **values)
22
+ selected = catalog(self.language(language))
23
+ template = selected[id] || catalog("en").fetch(id) do
24
+ raise Ibex::Error, "(messages):1:1: unknown built-in message id #{id.inspect}"
25
+ end
26
+ template % values.transform_keys(&:to_sym)
27
+ rescue KeyError => e
28
+ raise Ibex::Error, "(messages):1:1: missing interpolation for #{id.inspect}: #{e.message}"
29
+ end
30
+ module_function :translate
31
+
32
+ # @rbs (String id) -> bool
33
+ def known?(id)
34
+ catalog("en").key?(id)
35
+ end
36
+ module_function :known?
37
+
38
+ # @rbs (String language) -> Hash[String, String]
39
+ def catalog(language)
40
+ @catalogs ||= {} #: Hash[String, Hash[String, String]]
41
+ @catalogs[language] ||= load_catalog(language)
42
+ end
43
+ module_function :catalog
44
+
45
+ # @rbs (String language) -> Hash[String, String]
46
+ def load_catalog(language)
47
+ path = File.join(ROOT, "#{language}.yml")
48
+ document = JSON.parse(File.binread(path))
49
+ unless document.is_a?(Hash) && document["version"] == 1 && document["messages"].is_a?(Hash)
50
+ raise Ibex::Error, "#{path}:1:1: invalid built-in message catalog"
51
+ end
52
+
53
+ document.fetch("messages").to_h do |id, value|
54
+ unless id.is_a?(String) && value.is_a?(String)
55
+ raise Ibex::Error, "#{path}:1:1: message ids and templates must be strings"
56
+ end
57
+
58
+ [id.freeze, value.freeze]
59
+ end.freeze
60
+ rescue Errno::ENOENT => e
61
+ raise Ibex::Error, "#{path}:1:1: cannot read built-in message catalog: #{e.message}"
62
+ rescue JSON::ParserError => e
63
+ raise Ibex::Error, "#{path}:1:1: invalid JSON-compatible YAML: #{e.message}"
64
+ end
65
+ module_function :load_catalog
66
+ private_class_method :load_catalog
67
+ end
68
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require "set"
5
+
6
+ module Ibex
7
+ # Deterministic structural metrics over normalized Grammar and Automaton IR.
8
+ class Metrics
9
+ # @rbs!
10
+ # type report_value = String | Integer | Float | Array[report_value] | Hash[Symbol, report_value]
11
+
12
+ # @rbs (IR::Automaton automaton) -> void
13
+ def initialize(automaton)
14
+ @automaton = automaton
15
+ @grammar = automaton.grammar
16
+ end
17
+
18
+ # @rbs () -> Hash[Symbol, report_value]
19
+ def to_h
20
+ {
21
+ ibex_report: "metrics", schema_version: 1,
22
+ algorithm: @automaton.algorithm,
23
+ grammar_digest: @automaton.grammar_digest,
24
+ symbols: symbol_metrics,
25
+ grammar: grammar_metrics,
26
+ automaton: automaton_metrics
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ # @rbs () -> Hash[Symbol, Integer]
33
+ def symbol_metrics
34
+ { terminals: @grammar.terminals.length, nonterminals: @grammar.nonterminals.length }
35
+ end
36
+
37
+ # @rbs () -> Hash[Symbol, report_value]
38
+ def grammar_metrics
39
+ rule_counts = @grammar.productions.group_by(&:lhs).transform_values(&:length)
40
+ {
41
+ rules: rule_counts.length,
42
+ alternatives: @grammar.productions.length,
43
+ average_alternatives_per_rule: average(rule_counts.values),
44
+ maximum_branching: rule_counts.values.max || 0,
45
+ epsilon_productions: @grammar.productions.count { |production| production.rhs.empty? },
46
+ recursive_nonterminals: recursive_nonterminal_ids.map { |id| symbol_name(id) }.sort,
47
+ recursion_component_depth: recursion_component_depth,
48
+ warnings: @grammar.warnings.length
49
+ }
50
+ end
51
+
52
+ # @rbs () -> Hash[Symbol, report_value]
53
+ def automaton_metrics
54
+ {
55
+ states: @automaton.states.length,
56
+ transitions: @automaton.states.sum { |state| state.transitions.length },
57
+ action_cells: @automaton.states.sum { |state| state.actions.length },
58
+ goto_cells: @automaton.states.sum { |state| state.gotos.length },
59
+ default_reductions: @automaton.states.count(&:default_action),
60
+ conflicts: {
61
+ shift_reduce: @automaton.conflict_summary.fetch(:sr),
62
+ precedence_resolved_shift_reduce: @automaton.conflict_summary.fetch(:resolved_sr),
63
+ reduce_reduce: @automaton.conflict_summary.fetch(:rr)
64
+ }
65
+ }
66
+ end
67
+
68
+ # @rbs (Array[Integer] values) -> Float
69
+ def average(values)
70
+ return 0.0 if values.empty?
71
+
72
+ values.sum.fdiv(values.length).round(6)
73
+ end
74
+
75
+ # @rbs () -> Hash[Integer, Array[Integer]]
76
+ def dependency_graph
77
+ @dependency_graph ||= begin
78
+ graph = {} #: Hash[Integer, Array[Integer]]
79
+ @grammar.nonterminals.each { |symbol| graph[symbol.id] = [] }
80
+ @grammar.productions.each do |production|
81
+ production.rhs.each do |id|
82
+ symbol = @grammar.symbol_by_id(id)
83
+ graph.fetch(production.lhs) << id if symbol&.nonterminal?
84
+ end
85
+ end
86
+ graph.transform_values { |targets| targets.uniq.sort }
87
+ end
88
+ end
89
+
90
+ # @rbs () -> Hash[Integer, Set[Integer]]
91
+ def reachability
92
+ @reachability ||= dependency_graph.to_h do |source, _targets|
93
+ found = Set[source]
94
+ queue = [source]
95
+ cursor = 0
96
+ while cursor < queue.length
97
+ dependency_graph.fetch(queue.fetch(cursor)).each do |target|
98
+ next if found.include?(target)
99
+
100
+ found << target
101
+ queue << target
102
+ end
103
+ cursor += 1
104
+ end
105
+ [source, found]
106
+ end
107
+ end
108
+
109
+ # @rbs () -> Array[Array[Integer]]
110
+ def recursion_components
111
+ remaining = dependency_graph.keys.sort
112
+ components = [] #: Array[Array[Integer]]
113
+ until remaining.empty?
114
+ source = remaining.fetch(0)
115
+ component = remaining.select do |candidate|
116
+ reachability.fetch(source).include?(candidate) && reachability.fetch(candidate).include?(source)
117
+ end
118
+ components << component
119
+ remaining -= component
120
+ end
121
+ components
122
+ end
123
+
124
+ # @rbs () -> Array[Integer]
125
+ def recursive_nonterminal_ids
126
+ recursion_components.flat_map do |component|
127
+ next component if component.length > 1
128
+
129
+ id = component.fetch(0)
130
+ dependency_graph.fetch(id).include?(id) ? component : []
131
+ end
132
+ end
133
+
134
+ # Longest path after collapsing mutually recursive nonterminals.
135
+ # @rbs () -> Integer
136
+ def recursion_component_depth
137
+ components = recursion_components
138
+ component_for = {} #: Hash[Integer, Integer]
139
+ components.each_with_index { |ids, index| ids.each { |id| component_for[id] = index } }
140
+ edges = Array.new(components.length) { Set.new } #: Array[Set[Integer]]
141
+ dependency_graph.each do |source, targets|
142
+ targets.each do |target|
143
+ from = component_for.fetch(source)
144
+ to = component_for.fetch(target)
145
+ edges.fetch(from) << to unless from == to
146
+ end
147
+ end
148
+ longest_dag_path(edges)
149
+ end
150
+
151
+ # @rbs (Array[Set[Integer]] edges) -> Integer
152
+ def longest_dag_path(edges)
153
+ indegree = Array.new(edges.length, 0)
154
+ edges.each { |targets| targets.each { |target| indegree[target] += 1 } }
155
+ depths = Array.new(edges.length, 1)
156
+ queue = indegree.each_index.select { |index| indegree[index].zero? }
157
+ cursor = 0
158
+ while cursor < queue.length
159
+ source = queue.fetch(cursor)
160
+ edges.fetch(source).each do |target|
161
+ depths[target] = [depths[target], depths[source] + 1].max
162
+ indegree[target] -= 1
163
+ queue << target if indegree[target].zero?
164
+ end
165
+ cursor += 1
166
+ end
167
+ depths.max || 0
168
+ end
169
+
170
+ # @rbs (Integer id) -> String
171
+ def symbol_name(id)
172
+ @grammar.symbol_by_id(id)&.name || id.to_s
173
+ end
174
+ end
175
+ end
@@ -28,6 +28,7 @@ module Ibex
28
28
  @on_error_reduce_locations = {} #: Hash[String, Frontend::Location]
29
29
  @grammar_tests = [] #: Array[IR::grammar_test]
30
30
  @lexer_declaration = nil #: Frontend::AST::Lexer?
31
+ @parser_configuration = nil #: Frontend::AST::ParserConfiguration?
31
32
  @node_shapes = {} #: Hash[String, Array[String]]
32
33
  @ast.declarations.each { |declaration| read_declaration(declaration) }
33
34
  end
@@ -46,6 +47,7 @@ module Ibex
46
47
  when Frontend::AST::Lexer
47
48
  fail_at(declaration.loc, "duplicate lexer declaration") if @lexer_declaration
48
49
  @lexer_declaration = declaration
50
+ when Frontend::AST::ParserConfiguration then read_parser_configuration(declaration)
49
51
  when Frontend::AST::Convert then read_conversions(declaration)
50
52
  when Frontend::AST::DisplayName, Frontend::AST::SemanticType, Frontend::AST::Parameter, Frontend::AST::Printer
51
53
  read_extended_declaration(declaration)