ibex 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -123
  3. data/docs/architecture.md +477 -31
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +106 -0
  12. data/docs/cst.md +237 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +262 -0
  40. data/docs/development.md +306 -0
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +26 -0
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1581 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +114 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +629 -18
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/ja/bison-import.md +51 -0
  56. data/docs/ja/stable-api.md +53 -0
  57. data/docs/lexer-construction-profile.md +109 -0
  58. data/docs/lexer-migration.md +56 -0
  59. data/docs/maturity.md +128 -0
  60. data/docs/project-site-strategy.md +54 -0
  61. data/docs/racc-migration-evidence.md +45 -0
  62. data/docs/racc-migration.md +45 -6
  63. data/docs/release-readiness.md +221 -0
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +234 -0
  67. data/docs/status.md +43 -0
  68. data/docs/syntax-sessions.md +183 -0
  69. data/docs/table-artifact.md +125 -0
  70. data/docs/test-interactions.md +219 -0
  71. data/docs/verification-report.md +137 -0
  72. data/docs/verifier-trust-boundary.md +199 -0
  73. data/docs/workloads.md +132 -0
  74. data/examples/README.md +60 -0
  75. data/examples/calculator.y +44 -0
  76. data/examples/csv.y +32 -0
  77. data/examples/ini.y +70 -0
  78. data/examples/json.y +48 -0
  79. data/examples/tiny_language.y +75 -0
  80. data/lib/ibex/analysis/digraph.rb +128 -0
  81. data/lib/ibex/analysis/sets.rb +5 -4
  82. data/lib/ibex/analysis.rb +1 -0
  83. data/lib/ibex/artifact_set.rb +63 -0
  84. data/lib/ibex/bison_import/importer.rb +516 -0
  85. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  86. data/lib/ibex/bison_import.rb +200 -0
  87. data/lib/ibex/bounded_subprocess.rb +171 -0
  88. data/lib/ibex/cli/ambiguity.rb +75 -0
  89. data/lib/ibex/cli/analysis.rb +134 -0
  90. data/lib/ibex/cli/bison_import.rb +121 -0
  91. data/lib/ibex/cli/config.rb +128 -0
  92. data/lib/ibex/cli/counterexample_options.rb +6 -2
  93. data/lib/ibex/cli/coverage.rb +173 -0
  94. data/lib/ibex/cli/debug.rb +106 -0
  95. data/lib/ibex/cli/diagnostics.rb +136 -0
  96. data/lib/ibex/cli/documentation.rb +70 -0
  97. data/lib/ibex/cli/equiv.rb +169 -0
  98. data/lib/ibex/cli/error_messages.rb +184 -0
  99. data/lib/ibex/cli/explain.rb +85 -0
  100. data/lib/ibex/cli/fix.rb +203 -0
  101. data/lib/ibex/cli/formatting.rb +387 -0
  102. data/lib/ibex/cli/fuzz.rb +200 -0
  103. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  104. data/lib/ibex/cli/generation_artifacts.rb +189 -0
  105. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  106. data/lib/ibex/cli/grammar_tests.rb +140 -0
  107. data/lib/ibex/cli/ir_tools.rb +128 -0
  108. data/lib/ibex/cli/lsp.rb +33 -0
  109. data/lib/ibex/cli/outputs.rb +133 -23
  110. data/lib/ibex/cli/racc_migration.rb +87 -0
  111. data/lib/ibex/cli/reduce.rb +202 -0
  112. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  113. data/lib/ibex/cli/samples.rb +118 -0
  114. data/lib/ibex/cli/verify.rb +116 -0
  115. data/lib/ibex/cli/watch.rb +104 -0
  116. data/lib/ibex/cli.rb +825 -55
  117. data/lib/ibex/codegen/action_locations.rb +103 -0
  118. data/lib/ibex/codegen/action_method_source.rb +209 -0
  119. data/lib/ibex/codegen/action_source.rb +119 -0
  120. data/lib/ibex/codegen/ambiguity.rb +174 -0
  121. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  122. data/lib/ibex/codegen/documentation.rb +170 -0
  123. data/lib/ibex/codegen/explain.rb +380 -0
  124. data/lib/ibex/codegen/generated_action_abi.rb +293 -0
  125. data/lib/ibex/codegen/html.rb +94 -10
  126. data/lib/ibex/codegen/mermaid.rb +43 -0
  127. data/lib/ibex/codegen/railroad.rb +197 -0
  128. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  129. data/lib/ibex/codegen/rbs.rb +331 -2
  130. data/lib/ibex/codegen/report.rb +67 -15
  131. data/lib/ibex/codegen/ruby.rb +305 -66
  132. data/lib/ibex/codegen/ruby_actions.rb +146 -0
  133. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  134. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  135. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  136. data/lib/ibex/codegen/ruby_syntax.rb +96 -0
  137. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  138. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  139. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  140. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  141. data/lib/ibex/configuration/explanation.rb +421 -0
  142. data/lib/ibex/configuration/inspector.rb +232 -0
  143. data/lib/ibex/configuration.rb +580 -0
  144. data/lib/ibex/coverage/collector.rb +198 -0
  145. data/lib/ibex/coverage/event_stream.rb +103 -0
  146. data/lib/ibex/coverage/report.rb +267 -0
  147. data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
  148. data/lib/ibex/coverage.rb +13 -0
  149. data/lib/ibex/delta_reducer.rb +99 -0
  150. data/lib/ibex/diff.rb +140 -0
  151. data/lib/ibex/equiv/machine.rb +135 -0
  152. data/lib/ibex/equiv.rb +373 -0
  153. data/lib/ibex/error_messages/parser.rb +159 -0
  154. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  155. data/lib/ibex/error_messages/renderer.rb +65 -0
  156. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  157. data/lib/ibex/error_messages/update.rb +169 -0
  158. data/lib/ibex/error_messages.rb +165 -0
  159. data/lib/ibex/fix.rb +557 -0
  160. data/lib/ibex/frontend/ast.rb +166 -7
  161. data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
  162. data/lib/ibex/frontend/diagnostic.rb +81 -0
  163. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  164. data/lib/ibex/frontend/dsl.rb +66 -7
  165. data/lib/ibex/frontend/formatter.rb +453 -0
  166. data/lib/ibex/frontend/generated_parser.rb +644 -190
  167. data/lib/ibex/frontend/generated_parser_base.rb +170 -32
  168. data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
  169. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  170. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  171. data/lib/ibex/frontend/generation.rb +33 -0
  172. data/lib/ibex/frontend/lexer.rb +162 -10
  173. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  174. data/lib/ibex/frontend/parser/declarations.rb +262 -11
  175. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  176. data/lib/ibex/frontend/parser/rules.rb +43 -6
  177. data/lib/ibex/frontend/parser.rb +182 -4
  178. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  179. data/lib/ibex/frontend/regenerator.rb +27 -1
  180. data/lib/ibex/frontend/resolution.rb +70 -0
  181. data/lib/ibex/frontend/resolver.rb +217 -0
  182. data/lib/ibex/frontend/rule_documentation.rb +104 -0
  183. data/lib/ibex/frontend/source_cursor.rb +133 -9
  184. data/lib/ibex/frontend/source_document.rb +229 -0
  185. data/lib/ibex/frontend/source_loader.rb +150 -0
  186. data/lib/ibex/frontend/source_span.rb +89 -0
  187. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  188. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  189. data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
  190. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  191. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  192. data/lib/ibex/frontend/token_adapter.rb +18 -3
  193. data/lib/ibex/frontend.rb +14 -2
  194. data/lib/ibex/fuzz.rb +219 -0
  195. data/lib/ibex/generation_input.rb +57 -0
  196. data/lib/ibex/generation_manifest.rb +211 -0
  197. data/lib/ibex/generation_transaction.rb +261 -0
  198. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  199. data/lib/ibex/generation_transaction_validation.rb +196 -0
  200. data/lib/ibex/grammar_tests.rb +206 -0
  201. data/lib/ibex/ir/automaton_ir.rb +86 -11
  202. data/lib/ibex/ir/grammar_ir.rb +170 -26
  203. data/lib/ibex/ir/lexer_ir.rb +76 -0
  204. data/lib/ibex/ir/parser_contract.rb +135 -0
  205. data/lib/ibex/ir/serialize.rb +268 -50
  206. data/lib/ibex/ir/validator/automaton.rb +375 -0
  207. data/lib/ibex/ir/validator/base.rb +147 -0
  208. data/lib/ibex/ir/validator/grammar.rb +634 -0
  209. data/lib/ibex/ir/validator/lexer.rb +113 -0
  210. data/lib/ibex/ir/validator.rb +63 -0
  211. data/lib/ibex/ir.rb +71 -5
  212. data/lib/ibex/lalr/build_metrics.rb +71 -0
  213. data/lib/ibex/lalr/builder.rb +514 -52
  214. data/lib/ibex/lalr/conflict.rb +1 -0
  215. data/lib/ibex/lalr/conflict_search.rb +26 -9
  216. data/lib/ibex/lalr/counterexample.rb +38 -18
  217. data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
  218. data/lib/ibex/lalr/goto_follows.rb +229 -0
  219. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  220. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  221. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  222. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  223. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  224. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  225. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  226. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  227. data/lib/ibex/lalr/ielr_partition.rb +166 -0
  228. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  229. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  230. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  231. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  232. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  233. data/lib/ibex/lalr.rb +59 -1
  234. data/lib/ibex/location.rb +129 -0
  235. data/lib/ibex/lsp/document_handlers.rb +68 -0
  236. data/lib/ibex/lsp/document_store.rb +264 -0
  237. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  238. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  239. data/lib/ibex/lsp/initialization_handlers.rb +80 -0
  240. data/lib/ibex/lsp/navigation_handlers.rb +70 -0
  241. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  242. data/lib/ibex/lsp/position_codec.rb +113 -0
  243. data/lib/ibex/lsp/protocol_error.rb +33 -0
  244. data/lib/ibex/lsp/request_handlers.rb +46 -0
  245. data/lib/ibex/lsp/request_support.rb +94 -0
  246. data/lib/ibex/lsp/server.rb +148 -0
  247. data/lib/ibex/lsp/symbol_index.rb +241 -0
  248. data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
  249. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  250. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  251. data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
  252. data/lib/ibex/lsp/transport.rb +128 -0
  253. data/lib/ibex/lsp/workspace.rb +128 -0
  254. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  255. data/lib/ibex/lsp.rb +33 -0
  256. data/lib/ibex/messages/en.yml +28 -0
  257. data/lib/ibex/messages/ja.yml +28 -0
  258. data/lib/ibex/messages.rb +68 -0
  259. data/lib/ibex/metrics.rb +175 -0
  260. data/lib/ibex/normalize/declarations.rb +142 -7
  261. data/lib/ibex/normalize/diagnostics.rb +94 -24
  262. data/lib/ibex/normalize/expander.rb +64 -59
  263. data/lib/ibex/normalize/expression.rb +63 -40
  264. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  265. data/lib/ibex/normalize/inline_expansion.rb +465 -0
  266. data/lib/ibex/normalize/inline_validation.rb +174 -0
  267. data/lib/ibex/normalize/lexer.rb +131 -0
  268. data/lib/ibex/normalize/named_references.rb +60 -0
  269. data/lib/ibex/normalize/nodes.rb +46 -0
  270. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
  271. data/lib/ibex/normalize/parameter_lowering.rb +143 -0
  272. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  273. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  274. data/lib/ibex/normalize/parameters.rb +226 -0
  275. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  276. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  277. data/lib/ibex/normalize.rb +172 -17
  278. data/lib/ibex/racc_migration/checker.rb +122 -0
  279. data/lib/ibex/racc_migration/harness.rb +177 -0
  280. data/lib/ibex/racc_migration/report.rb +97 -0
  281. data/lib/ibex/racc_migration.rb +12 -0
  282. data/lib/ibex/rake_task.rb +116 -0
  283. data/lib/ibex/samples.rb +216 -0
  284. data/lib/ibex/table_artifact/builder.rb +266 -0
  285. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  286. data/lib/ibex/table_artifact/document.rb +39 -0
  287. data/lib/ibex/table_artifact/executor.rb +187 -0
  288. data/lib/ibex/table_artifact/serializer.rb +57 -0
  289. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  290. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  291. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  292. data/lib/ibex/table_artifact/validator.rb +253 -0
  293. data/lib/ibex/table_artifact.rb +88 -0
  294. data/lib/ibex/table_simulation/result.rb +55 -0
  295. data/lib/ibex/table_simulation/simulator.rb +253 -0
  296. data/lib/ibex/table_simulation/step.rb +62 -0
  297. data/lib/ibex/table_simulation/text.rb +31 -0
  298. data/lib/ibex/table_simulation.rb +13 -0
  299. data/lib/ibex/tables.rb +22 -69
  300. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  301. data/lib/ibex/verification_report/builder.rb +159 -0
  302. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  303. data/lib/ibex/verification_report/logical_path.rb +68 -0
  304. data/lib/ibex/verification_report/validator.rb +329 -0
  305. data/lib/ibex/verification_report.rb +69 -0
  306. data/lib/ibex/verify/action_correspondence.rb +138 -0
  307. data/lib/ibex/verify/language_witness.rb +295 -0
  308. data/lib/ibex/verify/reference_collection.rb +190 -0
  309. data/lib/ibex/verify/result.rb +73 -0
  310. data/lib/ibex/verify/verifier.rb +598 -0
  311. data/lib/ibex/verify.rb +15 -0
  312. data/lib/ibex/version.rb +1 -1
  313. data/lib/ibex/watch/runner.rb +181 -0
  314. data/lib/ibex/watch/source_snapshot.rb +98 -0
  315. data/lib/ibex/watch.rb +11 -0
  316. data/lib/ibex.rb +35 -1
  317. data/schema/automaton-ir-definitions.schema.json +401 -0
  318. data/schema/automaton-ir.schema.json +65 -0
  319. data/schema/benchmark-v1.schema.json +212 -0
  320. data/schema/benchmark-v2.schema.json +61 -0
  321. data/schema/bison-import-v1.schema.json +106 -0
  322. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  323. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  324. data/schema/construction-profile-v1.schema.json +779 -0
  325. data/schema/cst-v1.json +170 -0
  326. data/schema/diff-v1.schema.json +41 -0
  327. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  328. data/schema/equiv-v1.schema.json +64 -0
  329. data/schema/error-ux-review-v1.schema.json +609 -0
  330. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  331. data/schema/error-ux-round2-v1.schema.json +519 -0
  332. data/schema/error-ux-v1.schema.json +258 -0
  333. data/schema/explain-v1.schema.json +495 -0
  334. data/schema/fix-v1.schema.json +64 -0
  335. data/schema/fix-v2.schema.json +66 -0
  336. data/schema/fix-v3.schema.json +101 -0
  337. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  338. data/schema/fuzz-regression-v1.schema.json +79 -0
  339. data/schema/fuzz-v1.schema.json +114 -0
  340. data/schema/generation-manifest-v1.schema.json +115 -0
  341. data/schema/grammar-ir-extensions.schema.json +734 -0
  342. data/schema/grammar-ir-foundation.schema.json +426 -0
  343. data/schema/grammar-ir.schema.json +271 -0
  344. data/schema/ielr-benchmark-v1.schema.json +85 -0
  345. data/schema/lexer-ir-v1.schema.json +215 -0
  346. data/schema/lexer-profile-v1.schema.json +491 -0
  347. data/schema/metrics-v1.schema.json +60 -0
  348. data/schema/migration-check-v1.schema.json +60 -0
  349. data/schema/performance-comparison-v1.schema.json +395 -0
  350. data/schema/public-performance-comparison-v1.schema.json +506 -0
  351. data/schema/public-performance-profile-v1.schema.json +360 -0
  352. data/schema/reduce-v1.schema.json +22 -0
  353. data/schema/reduce-v2.schema.json +63 -0
  354. data/schema/runtime-coverage-v1.schema.json +86 -0
  355. data/schema/runtime-event-v1.schema.json +308 -0
  356. data/schema/table-artifact-v1.schema.json +377 -0
  357. data/schema/table-simulation-v1.schema.json +70 -0
  358. data/schema/verification-report-v1.schema.json +222 -0
  359. data/schema/verify-v1.schema.json +42 -0
  360. data/sig/ibex/analysis/digraph.rbs +19 -0
  361. data/sig/ibex/artifact_set.rbs +37 -0
  362. data/sig/ibex/bison_import/importer.rbs +140 -0
  363. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  364. data/sig/ibex/bison_import.rbs +95 -0
  365. data/sig/ibex/bounded_subprocess.rbs +76 -0
  366. data/sig/ibex/cli/ambiguity.rbs +28 -0
  367. data/sig/ibex/cli/analysis.rbs +43 -0
  368. data/sig/ibex/cli/bison_import.rbs +32 -0
  369. data/sig/ibex/cli/config.rbs +35 -0
  370. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  371. data/sig/ibex/cli/coverage.rbs +53 -0
  372. data/sig/ibex/cli/debug.rbs +28 -0
  373. data/sig/ibex/cli/diagnostics.rbs +51 -0
  374. data/sig/ibex/cli/documentation.rbs +29 -0
  375. data/sig/ibex/cli/equiv.rbs +49 -0
  376. data/sig/ibex/cli/error_messages.rbs +63 -0
  377. data/sig/ibex/cli/explain.rbs +31 -0
  378. data/sig/ibex/cli/fix.rbs +53 -0
  379. data/sig/ibex/cli/formatting.rbs +107 -0
  380. data/sig/ibex/cli/fuzz.rbs +47 -0
  381. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  382. data/sig/ibex/cli/generation_artifacts.rbs +69 -0
  383. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  384. data/sig/ibex/cli/grammar_tests.rbs +48 -0
  385. data/sig/ibex/cli/ir_tools.rbs +39 -0
  386. data/sig/ibex/cli/lsp.rbs +14 -0
  387. data/sig/ibex/cli/outputs.rbs +26 -3
  388. data/sig/ibex/cli/racc_migration.rbs +30 -0
  389. data/sig/ibex/cli/reduce.rbs +60 -0
  390. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  391. data/sig/ibex/cli/samples.rbs +38 -0
  392. data/sig/ibex/cli/verify.rbs +28 -0
  393. data/sig/ibex/cli/watch.rbs +43 -0
  394. data/sig/ibex/cli.rbs +182 -9
  395. data/sig/ibex/codegen/action_locations.rbs +45 -0
  396. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  397. data/sig/ibex/codegen/action_source.rbs +50 -0
  398. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  399. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  400. data/sig/ibex/codegen/documentation.rbs +50 -0
  401. data/sig/ibex/codegen/explain.rbs +105 -0
  402. data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
  403. data/sig/ibex/codegen/html.rbs +18 -2
  404. data/sig/ibex/codegen/mermaid.rbs +16 -0
  405. data/sig/ibex/codegen/railroad.rbs +82 -0
  406. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  407. data/sig/ibex/codegen/rbs.rbs +86 -4
  408. data/sig/ibex/codegen/report.rbs +16 -8
  409. data/sig/ibex/codegen/ruby.rbs +105 -28
  410. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  411. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  412. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  413. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  414. data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
  415. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  416. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  417. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  418. data/sig/ibex/configuration/explanation.rbs +195 -0
  419. data/sig/ibex/configuration/inspector.rbs +53 -0
  420. data/sig/ibex/configuration.rbs +242 -0
  421. data/sig/ibex/coverage/collector.rbs +78 -0
  422. data/sig/ibex/coverage/event_stream.rbs +44 -0
  423. data/sig/ibex/coverage/report.rbs +102 -0
  424. data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
  425. data/sig/ibex/coverage.rbs +7 -0
  426. data/sig/ibex/delta_reducer.rbs +38 -0
  427. data/sig/ibex/diff.rbs +47 -0
  428. data/sig/ibex/equiv/machine.rbs +54 -0
  429. data/sig/ibex/equiv.rbs +129 -0
  430. data/sig/ibex/error_messages/parser.rbs +58 -0
  431. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  432. data/sig/ibex/error_messages/renderer.rbs +23 -0
  433. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  434. data/sig/ibex/error_messages/update.rbs +43 -0
  435. data/sig/ibex/error_messages.rbs +85 -0
  436. data/sig/ibex/fix.rbs +138 -0
  437. data/sig/ibex/frontend/ast.rbs +237 -22
  438. data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
  439. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  440. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  441. data/sig/ibex/frontend/dsl.rbs +33 -4
  442. data/sig/ibex/frontend/formatter.rbs +143 -0
  443. data/sig/ibex/frontend/generated_parser.rbs +228 -68
  444. data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
  445. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  446. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  447. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  448. data/sig/ibex/frontend/generation.rbs +6 -0
  449. data/sig/ibex/frontend/lexer.rbs +49 -2
  450. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  451. data/sig/ibex/frontend/parser/declarations.rbs +57 -0
  452. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  453. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  454. data/sig/ibex/frontend/parser.rbs +66 -0
  455. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  456. data/sig/ibex/frontend/regenerator.rbs +11 -0
  457. data/sig/ibex/frontend/resolution.rbs +34 -0
  458. data/sig/ibex/frontend/resolver.rbs +91 -0
  459. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  460. data/sig/ibex/frontend/source_cursor.rbs +38 -5
  461. data/sig/ibex/frontend/source_document.rbs +119 -0
  462. data/sig/ibex/frontend/source_loader.rbs +66 -0
  463. data/sig/ibex/frontend/source_span.rbs +56 -0
  464. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  465. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  466. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
  467. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  468. data/sig/ibex/frontend/token_adapter.rbs +11 -2
  469. data/sig/ibex/frontend.rbs +1 -1
  470. data/sig/ibex/fuzz.rbs +71 -0
  471. data/sig/ibex/generation_input.rbs +37 -0
  472. data/sig/ibex/generation_manifest.rbs +70 -0
  473. data/sig/ibex/generation_transaction.rbs +82 -0
  474. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  475. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  476. data/sig/ibex/grammar_tests.rbs +93 -0
  477. data/sig/ibex/ir/automaton_ir.rbs +35 -10
  478. data/sig/ibex/ir/grammar_ir.rbs +96 -22
  479. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  480. data/sig/ibex/ir/parser_contract.rbs +69 -0
  481. data/sig/ibex/ir/serialize.rbs +75 -23
  482. data/sig/ibex/ir/validator/automaton.rbs +112 -0
  483. data/sig/ibex/ir/validator/base.rbs +69 -0
  484. data/sig/ibex/ir/validator/grammar.rbs +195 -0
  485. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  486. data/sig/ibex/ir/validator.rbs +16 -0
  487. data/sig/ibex/ir.rbs +45 -5
  488. data/sig/ibex/lalr/build_metrics.rbs +60 -0
  489. data/sig/ibex/lalr/builder.rbs +150 -19
  490. data/sig/ibex/lalr/conflict_search.rbs +12 -5
  491. data/sig/ibex/lalr/counterexample.rbs +20 -14
  492. data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
  493. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  494. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  495. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  496. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  497. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  498. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  499. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  500. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  501. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  502. data/sig/ibex/lalr/ielr_partition.rbs +71 -0
  503. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  504. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  505. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  506. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  507. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  508. data/sig/ibex/lalr.rbs +17 -1
  509. data/sig/ibex/location.rbs +67 -0
  510. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  511. data/sig/ibex/lsp/document_store.rbs +94 -0
  512. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  513. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  514. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  515. data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
  516. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  517. data/sig/ibex/lsp/position_codec.rbs +44 -0
  518. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  519. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  520. data/sig/ibex/lsp/request_support.rbs +40 -0
  521. data/sig/ibex/lsp/server.rbs +55 -0
  522. data/sig/ibex/lsp/symbol_index.rbs +77 -0
  523. data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
  524. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  525. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  526. data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
  527. data/sig/ibex/lsp/transport.rbs +47 -0
  528. data/sig/ibex/lsp/workspace.rbs +42 -0
  529. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  530. data/sig/ibex/lsp.rbs +7 -0
  531. data/sig/ibex/messages.rbs +26 -0
  532. data/sig/ibex/metrics.rbs +50 -0
  533. data/sig/ibex/normalize/declarations.rbs +31 -0
  534. data/sig/ibex/normalize/diagnostics.rbs +13 -4
  535. data/sig/ibex/normalize/expander.rbs +22 -16
  536. data/sig/ibex/normalize/expression.rbs +11 -9
  537. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  538. data/sig/ibex/normalize/inline_expansion.rbs +129 -0
  539. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  540. data/sig/ibex/normalize/lexer.rbs +37 -0
  541. data/sig/ibex/normalize/named_references.rbs +20 -0
  542. data/sig/ibex/normalize/nodes.rbs +14 -0
  543. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
  544. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  545. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  546. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  547. data/sig/ibex/normalize/parameters.rbs +51 -0
  548. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  549. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  550. data/sig/ibex/normalize.rbs +129 -18
  551. data/sig/ibex/racc_migration/checker.rbs +36 -0
  552. data/sig/ibex/racc_migration/harness.rbs +16 -0
  553. data/sig/ibex/racc_migration/report.rbs +55 -0
  554. data/sig/ibex/racc_migration.rbs +8 -0
  555. data/sig/ibex/rake_task.rbs +51 -0
  556. data/sig/ibex/samples.rbs +60 -0
  557. data/sig/ibex/table_artifact/builder.rbs +93 -0
  558. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  559. data/sig/ibex/table_artifact/document.rbs +27 -0
  560. data/sig/ibex/table_artifact/executor.rbs +66 -0
  561. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  562. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  563. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  564. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  565. data/sig/ibex/table_artifact/validator.rbs +66 -0
  566. data/sig/ibex/table_artifact.rbs +32 -0
  567. data/sig/ibex/table_simulation/result.rbs +36 -0
  568. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  569. data/sig/ibex/table_simulation/step.rbs +42 -0
  570. data/sig/ibex/table_simulation/text.rbs +14 -0
  571. data/sig/ibex/table_simulation.rbs +7 -0
  572. data/sig/ibex/tables.rbs +10 -35
  573. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  574. data/sig/ibex/verification_report/builder.rbs +53 -0
  575. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  576. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  577. data/sig/ibex/verification_report/validator.rbs +114 -0
  578. data/sig/ibex/verification_report.rbs +44 -0
  579. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  580. data/sig/ibex/verify/language_witness.rbs +112 -0
  581. data/sig/ibex/verify/reference_collection.rbs +63 -0
  582. data/sig/ibex/verify/result.rbs +52 -0
  583. data/sig/ibex/verify/verifier.rbs +170 -0
  584. data/sig/ibex/verify.rbs +6 -0
  585. data/sig/ibex/watch/runner.rbs +58 -0
  586. data/sig/ibex/watch/source_snapshot.rbs +46 -0
  587. data/sig/ibex/watch.rbs +7 -0
  588. data/sig/ibex.rbs +2 -0
  589. metadata +524 -19
  590. data/.rubocop.yml +0 -43
  591. data/CHANGELOG.md +0 -30
  592. data/Rakefile +0 -25
  593. data/Steepfile +0 -10
  594. data/docs/compat-notes.md +0 -37
  595. data/docs/lexer-coverage.md +0 -14
  596. data/docs/phase10-extensions.md +0 -27
  597. data/gemfiles/Gemfile +0 -7
  598. data/gemfiles/Gemfile.lock +0 -98
  599. data/lib/ibex/frontend/grammar.y +0 -156
  600. data/lib/ibex/runtime/parser.rb +0 -360
  601. data/lib/ibex/runtime.rb +0 -8
  602. data/sig/ibex/runtime/parser.rbs +0 -167
  603. data/sig/ibex/runtime.rbs +0 -6
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Owns open buffers, parsed snapshots, include closures, and reverse dependencies.
6
+ class DocumentStore
7
+ include DocumentStoreValidation
8
+ include DocumentStoreDiagnostics
9
+
10
+ # @rbs!
11
+ # type snapshot = {
12
+ # uri: String,
13
+ # path: String,
14
+ # version: Integer?,
15
+ # source: String,
16
+ # open: bool,
17
+ # document: Frontend::SourceDocument?
18
+ # }
19
+ # type publication = {
20
+ # uri: String,
21
+ # ?version: Integer,
22
+ # diagnostics: Array[WorkspaceAnalyzer::lsp_diagnostic]
23
+ # }
24
+
25
+ attr_reader :loader #: Frontend::SourceLoader
26
+ attr_reader :workspace #: Workspace
27
+
28
+ # @rbs (Workspace workspace, Frontend::SourceLoader loader) -> void
29
+ def initialize(workspace, loader)
30
+ @workspace = workspace
31
+ @loader = loader
32
+ @analyzer = WorkspaceAnalyzer.new(workspace, loader)
33
+ @snapshots = {} #: Hash[String, snapshot]
34
+ @roots = {} #: Hash[String, bool]
35
+ @closures = {} #: Hash[String, Array[String]]
36
+ @reverse_dependencies = {} #: Hash[String, Array[String]]
37
+ @resolutions = {} #: Hash[String, Frontend::Resolution]
38
+ @document_diagnostics = {} #: Hash[String, Array[WorkspaceAnalyzer::lsp_diagnostic]]
39
+ @root_diagnostics = {} #: Hash[String, Hash[String, Array[WorkspaceAnalyzer::lsp_diagnostic]]]
40
+ end
41
+
42
+ # @rbs (String uri, Integer version, String source) -> Array[publication]
43
+ def open(uri, version, source)
44
+ path = workspace.path(uri)
45
+ raise ProtocolError.new("document is already open: #{uri}", code: -32_602) if @snapshots.dig(path, :open)
46
+
47
+ validate_version(version)
48
+ validate_source(source)
49
+ loader.set_overlay(path, source)
50
+ @snapshots[path] = snapshot(uri, path, version, source, true, nil)
51
+ refresh(path)
52
+ end
53
+
54
+ # @rbs (String uri, Integer version, String source) -> Array[publication]
55
+ def change(uri, version, source)
56
+ path = workspace.path(uri)
57
+ current = open_snapshot(path, uri)
58
+ validate_version(version)
59
+ unless current.fetch(:version) && version > current.fetch(:version)
60
+ raise ProtocolError.new("document version must increase monotonically", code: -32_602)
61
+ end
62
+
63
+ validate_source(source)
64
+ loader.set_overlay(path, source)
65
+ @snapshots[path] = snapshot(uri, path, version, source, true, nil)
66
+ refresh(path)
67
+ end
68
+
69
+ # @rbs (String uri, ?source: String?) -> Array[publication]
70
+ def save(uri, source: nil)
71
+ path = workspace.path(uri)
72
+ current = open_snapshot(path, uri)
73
+ if source
74
+ validate_source(source)
75
+ loader.set_overlay(path, source)
76
+ current = snapshot(uri, path, current.fetch(:version), source, true, nil)
77
+ @snapshots[path] = current
78
+ end
79
+ refresh(path)
80
+ end
81
+
82
+ # Clear the open version first, then replace it with a disk snapshot if one exists.
83
+ # @rbs (String uri) -> Array[publication]
84
+ def close(uri)
85
+ path = workspace.path(uri)
86
+ open_snapshot(path, uri)
87
+ clear = { uri: uri, diagnostics: [] } #: publication
88
+ old_files = files_for(path)
89
+ was_root = @roots[path]
90
+ disk_path = disk_path_for_close(path, uri)
91
+ disk_source = loader.disk_source(disk_path) if disk_path && loader.disk_file?(disk_path)
92
+ loader.delete_overlay(path)
93
+ if disk_source
94
+ @snapshots[path] = snapshot(uri, path, nil, disk_source, false, nil)
95
+ if was_root
96
+ analyzed = @analyzer.analyze(path)
97
+ update_snapshot(path, analyzed)
98
+ remove_root_state(path)
99
+ [clear] + publish_paths((old_files + [path]).uniq)
100
+ else
101
+ [clear] + refresh(path)
102
+ end
103
+ else
104
+ remove_path(path)
105
+ [clear] + refresh_dependents(path)
106
+ end
107
+ end
108
+
109
+ # @rbs (String path) -> snapshot?
110
+ def snapshot_for(path)
111
+ @snapshots[path]
112
+ end
113
+
114
+ # Preserve the URI spelling used to open a document; closed files use their canonical URI.
115
+ # @rbs (String path) -> String
116
+ def uri_for(path)
117
+ entry = @snapshots[path]
118
+ return entry.fetch(:uri) if entry&.fetch(:open)
119
+
120
+ workspace.uri(path)
121
+ end
122
+
123
+ # @rbs (String path) -> Array[String]
124
+ def files_for(path)
125
+ roots = affected_roots(path)
126
+ files = roots.flat_map { |root| @closures.fetch(root, [root]) }
127
+ (files + [path]).uniq
128
+ end
129
+
130
+ # @rbs (String path) -> Array[Frontend::Resolution]
131
+ def resolutions_for(path)
132
+ affected_roots(path).filter_map { |root| @resolutions[root] }
133
+ end
134
+
135
+ # @rbs (String path) -> Array[String]
136
+ def roots_for(path)
137
+ affected_roots(path)
138
+ end
139
+
140
+ private
141
+
142
+ # @rbs (String path) -> Array[publication]
143
+ def refresh(path)
144
+ old_files = files_for(path)
145
+ previous_roots = affected_roots(path)
146
+ was_root = @roots[path]
147
+ analyzed = @analyzer.analyze(path)
148
+ update_snapshot(path, analyzed)
149
+ update_root_membership(path, analyzed.fetch(:document))
150
+ remove_root_state(path) if was_root && !@roots[path]
151
+ roots = (previous_roots + affected_roots(path)).uniq
152
+ roots.delete(path) unless @roots[path]
153
+ roots.each { |root| refresh_root(root) }
154
+ publish_paths((old_files + files_for(path) + [path]).uniq)
155
+ end
156
+
157
+ # @rbs (String path) -> Array[publication]
158
+ def refresh_dependents(path)
159
+ roots = affected_roots(path)
160
+ roots.each { |root| refresh_root(root) }
161
+ publish_paths(roots.flat_map { |root| @closures.fetch(root, [root]) }.uniq)
162
+ end
163
+
164
+ # @rbs (String root) -> void
165
+ def refresh_root(root)
166
+ files, analyzed = @analyzer.closure(root)
167
+ @closures[root] = files
168
+ rebuild_reverse_dependencies
169
+ analyzed.each { |path, result| update_snapshot(path, result, own_diagnostics: false) }
170
+ parse_failed = analyzed.any? do |path, result|
171
+ !result.fetch(:diagnostics).empty? && loader.file?(path)
172
+ end
173
+ resolution, errors = parse_failed ? [nil, []] : @analyzer.resolve(root)
174
+ resolution ? @resolutions[root] = resolution : @resolutions.delete(root)
175
+ replace_root_diagnostics(root, files, analyzed, errors)
176
+ end
177
+
178
+ # @rbs () -> void
179
+ def rebuild_reverse_dependencies
180
+ reverse = Hash.new { |hash, key| hash[key] = [] } #: Hash[String, Array[String]]
181
+ @closures.each { |root, files| files.each { |file| reverse[file] << root } }
182
+ @reverse_dependencies = reverse
183
+ end
184
+
185
+ # @rbs (String path) -> Array[String]
186
+ def affected_roots(path)
187
+ roots = @reverse_dependencies.fetch(path, empty_paths).dup
188
+ roots << path if @roots[path]
189
+ roots.uniq
190
+ end
191
+
192
+ # @rbs (String path, WorkspaceAnalyzer::analyzed_document analyzed, ?own_diagnostics: bool) -> void
193
+ def update_snapshot(path, analyzed, own_diagnostics: true)
194
+ current = @snapshots[path]
195
+ uri = current&.fetch(:uri) || workspace.uri(path)
196
+ version = current&.fetch(:version)
197
+ open = current&.fetch(:open) || false
198
+ source = open ? current.fetch(:source) : analyzed.fetch(:source)
199
+ document = analyzed.fetch(:document)
200
+ @snapshots[path] = snapshot(uri, path, version, source, open, document)
201
+ @document_diagnostics[path] = analyzed.fetch(:diagnostics) if own_diagnostics
202
+ end
203
+
204
+ # @rbs (String path, Frontend::SourceDocument? document) -> void
205
+ def update_root_membership(path, document)
206
+ if document&.ast.is_a?(Frontend::AST::Root)
207
+ @roots[path] = true
208
+ else
209
+ @roots.delete(path)
210
+ end
211
+ end
212
+
213
+ # @rbs (Array[String] paths) -> Array[publication]
214
+ def publish_paths(paths)
215
+ paths.filter_map do |path|
216
+ entry = @snapshots[path]
217
+ next unless entry
218
+
219
+ publication = {
220
+ uri: entry.fetch(:uri),
221
+ diagnostics: aggregated_diagnostics(path)
222
+ } #: publication
223
+ publication[:version] = entry.fetch(:version) if entry.fetch(:open) && entry.fetch(:version)
224
+ publication
225
+ end
226
+ end
227
+
228
+ # @rbs (String uri, String path, Integer? version, String source, bool open,
229
+ # Frontend::SourceDocument? document) -> snapshot
230
+ def snapshot(uri, path, version, source, open, document)
231
+ { uri: uri, path: path, version: version, source: source, open: open, document: document }
232
+ end
233
+
234
+ # @rbs (String path, String uri) -> snapshot
235
+ def open_snapshot(path, uri)
236
+ entry = @snapshots[path]
237
+ return entry if entry&.fetch(:open) && entry.fetch(:uri) == uri
238
+
239
+ raise ProtocolError.new("document is not open: #{uri}", code: -32_602)
240
+ end
241
+
242
+ # @rbs () -> Array[String]
243
+ def empty_paths
244
+ [] #: Array[String]
245
+ end
246
+
247
+ # @rbs (String path) -> void
248
+ def remove_path(path)
249
+ @snapshots.delete(path)
250
+ @document_diagnostics.delete(path)
251
+ remove_root_state(path)
252
+ end
253
+
254
+ # @rbs (String path) -> void
255
+ def remove_root_state(path)
256
+ @roots.delete(path)
257
+ @closures.delete(path)
258
+ @resolutions.delete(path)
259
+ @root_diagnostics.delete(path)
260
+ rebuild_reverse_dependencies
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Owns per-document and per-root diagnostic aggregation for DocumentStore.
6
+ module DocumentStoreDiagnostics
7
+ private
8
+
9
+ # @rbs (String root, Array[String] files, Hash[String, WorkspaceAnalyzer::analyzed_document] analyzed,
10
+ # Array[WorkspaceAnalyzer::lsp_diagnostic] errors) -> void
11
+ def replace_root_diagnostics(root, files, analyzed, errors)
12
+ # @type self: DocumentStore
13
+ owned = {} #: Hash[String, Array[WorkspaceAnalyzer::lsp_diagnostic]]
14
+ files.each { |path| owned[path] = analyzed.dig(path, :diagnostics) || [] }
15
+ errors.each do |diagnostic|
16
+ file = diagnostic.dig("data", "file")
17
+ next unless file
18
+
19
+ existing = owned[file] || []
20
+ duplicate = existing.any? do |entry|
21
+ entry["range"] == diagnostic["range"] && entry["message"] == diagnostic["message"]
22
+ end
23
+ owned[file] = existing + [diagnostic] unless duplicate
24
+ end
25
+ @root_diagnostics[root] = owned
26
+ end
27
+
28
+ # @rbs (String path) -> Array[WorkspaceAnalyzer::lsp_diagnostic]
29
+ def aggregated_diagnostics(path)
30
+ # @type self: DocumentStore
31
+ diagnostics = @document_diagnostics.fetch(path, empty_diagnostics).dup
32
+ @root_diagnostics.each_value do |owned|
33
+ diagnostics.concat(owned.fetch(path, empty_diagnostics))
34
+ end
35
+ diagnostics.uniq
36
+ end
37
+
38
+ # @rbs () -> Array[WorkspaceAnalyzer::lsp_diagnostic]
39
+ def empty_diagnostics
40
+ [] #: Array[WorkspaceAnalyzer::lsp_diagnostic]
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Validates versions, source bounds, and prospective multi-file workspace edits.
6
+ module DocumentStoreValidation
7
+ # @rbs (Hash[String, String] replacements) -> bool
8
+ def valid_replacements?(replacements)
9
+ # @type self: DocumentStore
10
+ candidate = Frontend::SourceLoader.new
11
+ @snapshots.each_value do |entry|
12
+ candidate.set_overlay(entry.fetch(:path), entry.fetch(:source)) if entry.fetch(:open)
13
+ end
14
+ replacements.each do |path, source|
15
+ candidate.set_overlay(path, source)
16
+ parse_candidate(path, source)
17
+ end
18
+ roots = replacements.keys.flat_map { |path| affected_roots(path) }.uniq
19
+ roots.each { |root| Frontend::Resolver.new(root, mode: :extended, loader: candidate).resolve }
20
+ true
21
+ rescue Ibex::Error, SystemCallError
22
+ false
23
+ end
24
+
25
+ private
26
+
27
+ # @rbs (Integer version) -> void
28
+ def validate_version(version)
29
+ raise ProtocolError.new("document version must be a non-negative integer", code: -32_602) unless
30
+ version.is_a?(Integer) && !version.negative?
31
+ end
32
+
33
+ # @rbs (String source) -> void
34
+ def validate_source(source)
35
+ raise ProtocolError.new("document text must be a string", code: -32_602) unless source.is_a?(String)
36
+ return if source.bytesize <= Limits::MAX_DOCUMENT_BYTES
37
+
38
+ raise ProtocolError.new("document exceeds #{Limits::MAX_DOCUMENT_BYTES} bytes", code: -32_602)
39
+ end
40
+
41
+ # @rbs (String path, String source) -> void
42
+ def parse_candidate(path, source)
43
+ Frontend::Parser.new(source, file: path, mode: :extended).parse_source_document
44
+ end
45
+
46
+ # Resolve disk independently from overlay aliases before removing an open buffer.
47
+ # @rbs (String path, String uri) -> String?
48
+ def disk_path_for_close(path, uri)
49
+ # @type self: DocumentStore
50
+ canonical = loader.disk_path(path)
51
+ return canonical if workspace.root_for(canonical)
52
+
53
+ raise ProtocolError.new("document disk target is outside workspace roots: #{uri}", code: -32_602)
54
+ rescue Errno::ENOENT, Errno::ENOTDIR
55
+ nil
56
+ rescue SystemCallError => e
57
+ raise ProtocolError.new("cannot resolve document disk target #{uri.inspect}: #{e.message}", code: -32_602)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Handles initialize/initialized/shutdown/exit lifecycle transitions.
6
+ module InitializationHandlers
7
+ include RequestSupport
8
+
9
+ private
10
+
11
+ # @rbs (lsp_value? raw_params) -> lsp_object
12
+ def initialize_workspace(raw_params)
13
+ raise ProtocolError.new("server is already initialized", code: -32_600) unless @state == :uninitialized
14
+
15
+ params = params_hash(raw_params)
16
+ loader = Frontend::SourceLoader.new
17
+ @workspace = Workspace.new(initialization_roots(params), loader)
18
+ @store = DocumentStore.new(@workspace, loader)
19
+ @state = :initialized
20
+ {
21
+ "capabilities" => capabilities,
22
+ "serverInfo" => { "name" => "ibex", "version" => Ibex::VERSION }
23
+ }
24
+ end
25
+
26
+ # @rbs (lsp_value? params) -> nil
27
+ def initialized_notification(_params)
28
+ require_state!(:initialized)
29
+ @state = :running
30
+ nil
31
+ end
32
+
33
+ # @rbs (lsp_value? params) -> nil
34
+ def shutdown_request(_params)
35
+ require_state!(:running)
36
+ @state = :shutdown
37
+ nil
38
+ end
39
+
40
+ # @rbs (lsp_value? params) -> nil
41
+ def exit_notification(_params)
42
+ @exit_status = @state == :shutdown ? 0 : 1
43
+ @exit_requested = true
44
+ nil
45
+ end
46
+
47
+ # @rbs () -> lsp_object
48
+ def capabilities
49
+ {
50
+ "positionEncoding" => "utf-16",
51
+ "textDocumentSync" => { "openClose" => true, "change" => 1, "save" => { "includeText" => true } },
52
+ "definitionProvider" => true,
53
+ "referencesProvider" => true,
54
+ "renameProvider" => { "prepareProvider" => true },
55
+ "hoverProvider" => true,
56
+ "completionProvider" => { "resolveProvider" => false },
57
+ "workspace" => { "workspaceFolders" => { "supported" => true, "changeNotifications" => false } }
58
+ }
59
+ end
60
+
61
+ # @rbs (lsp_object params) -> Array[String]
62
+ def initialization_roots(params)
63
+ folders = params["workspaceFolders"]
64
+ if folders.is_a?(Array) && !folders.empty?
65
+ return folders.map do |folder|
66
+ raise ProtocolError.new("workspaceFolders entries must be objects", code: -32_602) unless folder.is_a?(Hash)
67
+
68
+ folder_object = folder #: lsp_object
69
+ string_member(folder_object, "uri")
70
+ end
71
+ end
72
+
73
+ root = params["rootUri"]
74
+ return [root] if root.is_a?(String)
75
+
76
+ raise ProtocolError.new("initialize requires rootUri or workspaceFolders", code: -32_602)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Serves symbol navigation, rename, and hover requests.
6
+ module NavigationHandlers
7
+ include RequestSupport
8
+
9
+ private
10
+
11
+ # @rbs (lsp_object? raw_params) -> Array[lsp_object]
12
+ def definition(raw_params)
13
+ with_index(raw_params) { |index, path, position| index.definition(path, position) } #: Array[lsp_object]
14
+ end
15
+
16
+ # @rbs (lsp_object? raw_params) -> Array[lsp_object]
17
+ def references(raw_params)
18
+ params = params_hash(raw_params)
19
+ context = hash_member(params, "context")
20
+ include_declaration = context["includeDeclaration"] == true
21
+ with_index(params) do |index, path, position|
22
+ index.references(path, position, include_declaration: include_declaration)
23
+ end #: Array[lsp_object]
24
+ end
25
+
26
+ # @rbs (lsp_object? raw_params) -> lsp_object?
27
+ def prepare_rename(raw_params)
28
+ with_index(raw_params) { |index, path, position| index.prepare_rename(path, position) } #: lsp_object?
29
+ end
30
+
31
+ # @rbs (lsp_object? raw_params) -> lsp_object
32
+ def rename(raw_params)
33
+ params = params_hash(raw_params)
34
+ new_name = string_member(params, "newName")
35
+ with_index(params) { |index, path, position| index.rename(path, position, new_name) } #: lsp_object
36
+ end
37
+
38
+ # @rbs (lsp_object? raw_params) -> lsp_object?
39
+ def hover(raw_params)
40
+ with_index(raw_params) do |index, path, position|
41
+ index.hover(path, position) || ParserConfigurationAssistance.new(store, path).hover(position)
42
+ end #: lsp_object?
43
+ end
44
+
45
+ # @rbs (lsp_object? raw_params) -> lsp_object
46
+ def completion(raw_params)
47
+ require_running!
48
+ params = params_hash(raw_params)
49
+ document = hash_member(params, "textDocument")
50
+ path = workspace.path(string_member(document, "uri"))
51
+ position = hash_member(params, "position")
52
+ ParserConfigurationAssistance.new(store, path).completion(position)
53
+ rescue ArgumentError => e
54
+ raise ProtocolError.new(e.message, code: -32_602)
55
+ end
56
+
57
+ # @rbs (lsp_object? raw_params) { (SymbolIndex, String, lsp_object) -> Object? } -> Object?
58
+ def with_index(raw_params)
59
+ require_running!
60
+ params = params_hash(raw_params)
61
+ document = hash_member(params, "textDocument")
62
+ path = workspace.path(string_member(document, "uri"))
63
+ position = hash_member(params, "position")
64
+ yield SymbolIndex.new(store, path), path, position
65
+ rescue ArgumentError => e
66
+ raise ProtocolError.new(e.message, code: -32_602)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Provides static editor assistance for the root parser declaration without evaluating grammar code.
6
+ class ParserConfigurationAssistance
7
+ SETTING_VALUES = Frontend::ParserConfigurationSupport::PARSER_SETTING_VALUES #: Hash[String, Array[String]]
8
+ SETTING_DOCUMENTATION = {
9
+ "algorithm" => "`parser.algorithm` selects parser-table construction. Values: `slr`, `lalr`, `ielr`, `lr1`.",
10
+ "entries" => "`parser.entries` selects shared or isolated construction for multiple start symbols. " \
11
+ "Values: `shared`, `isolated`.",
12
+ "cst_trivia" => "`cst.trivia` selects CST trivia ownership. Values: `leading`, `balanced`, `drop`; " \
13
+ "requires `pragma cst`."
14
+ }.freeze #: Hash[String, String]
15
+ VALUE_DOCUMENTATION = {
16
+ "slr" => "`slr` — SLR parser-table construction.",
17
+ "lalr" => "`lalr` — LALR parser-table construction.",
18
+ "ielr" => "`ielr` — IELR parser-table construction with canonical LR(1) verification support.",
19
+ "lr1" => "`lr1` — canonical LR(1) parser-table construction.",
20
+ "shared" => "`shared` — construct multiple entries in one shared automaton.",
21
+ "isolated" => "`isolated` — construct each of multiple entries independently.",
22
+ "leading" => "`leading` — attach leading trivia to the following CST node.",
23
+ "balanced" => "`balanced` — attach trivia between the surrounding CST nodes.",
24
+ "drop" => "`drop` — omit CST trivia; location and incremental APIs are unavailable."
25
+ }.freeze #: Hash[String, String]
26
+
27
+ # @rbs (DocumentStore store, String path) -> void
28
+ def initialize(store, path)
29
+ @store = store
30
+ @path = path
31
+ end
32
+
33
+ # @rbs (lsp_object position) -> lsp_object
34
+ def completion(position)
35
+ source = source!
36
+ codec = PositionCodec.new(source)
37
+ offset = codec.byte_offset(position)
38
+ line_start = line_start(source, offset)
39
+ return completion_list([]) unless parser_block_open?(source.byteslice(0, line_start) || "")
40
+
41
+ prefix = source.byteslice(line_start, offset - line_start) || ""
42
+ value_match = prefix.match(/\A\s*(algorithm|entries|cst_trivia)\s+([A-Za-z_]*)\z/)
43
+ if value_match
44
+ setting = value_match[1] || raise("parser setting capture is missing")
45
+ return completion_list(value_items(setting))
46
+ end
47
+ return completion_list(setting_items) if prefix.match?(/\A\s*[A-Za-z_]*\z/)
48
+
49
+ completion_list([])
50
+ end
51
+
52
+ # @rbs (lsp_object position) -> lsp_object?
53
+ def hover(position)
54
+ source = source!
55
+ codec = PositionCodec.new(source)
56
+ offset = codec.byte_offset(position)
57
+ start = line_start(source, offset)
58
+ return unless parser_block_open?(source.byteslice(0, start) || "")
59
+
60
+ finish = source.index("\n", start) || source.bytesize
61
+ line = source.byteslice(start, finish - start) || ""
62
+ match = line.match(
63
+ /\A\s*(algorithm|entries|cst_trivia)\s+(slr|lalr|ielr|lr1|shared|isolated|leading|balanced|drop)\s*(?:#.*)?\z/
64
+ )
65
+ return unless match
66
+
67
+ token, token_start, token_end = hovered_token(match, line, start, offset)
68
+ return unless token
69
+
70
+ documentation = SETTING_DOCUMENTATION[token] || VALUE_DOCUMENTATION[token]
71
+ {
72
+ "contents" => { "kind" => "markdown", "value" => documentation },
73
+ "range" => { "start" => codec.position(token_start), "end" => codec.position(token_end) }
74
+ }
75
+ end
76
+
77
+ private
78
+
79
+ # @rbs () -> String
80
+ def source!
81
+ snapshot = @store.snapshot_for(@path)
82
+ raise ArgumentError, "document is unavailable" unless snapshot
83
+
84
+ snapshot.fetch(:source)
85
+ end
86
+
87
+ # @rbs (String source, Integer offset) -> Integer
88
+ def line_start(source, offset)
89
+ newline = offset.positive? ? source.rindex("\n", offset - 1) : nil
90
+ newline ? newline + 1 : 0
91
+ end
92
+
93
+ # @rbs (String source) -> bool
94
+ def parser_block_open?(source)
95
+ root = false
96
+ open = false
97
+ source.each_line do |line|
98
+ content = line.sub(/#.*/, "").strip
99
+ next if content.empty?
100
+
101
+ root = true if content.match?(/\Aclass\b/)
102
+ root = false if content.match?(/\Afragment\b/)
103
+ open = true if root && content == "parser"
104
+ open = false if open && content == "end"
105
+ return false if content.match?(/\Arule\b/)
106
+ end
107
+ root && open
108
+ end
109
+
110
+ # @rbs () -> Array[lsp_object]
111
+ def setting_items
112
+ SETTING_VALUES.keys.map do |name|
113
+ completion_item(name, 10, SETTING_DOCUMENTATION.fetch(name))
114
+ end
115
+ end
116
+
117
+ # @rbs (String setting) -> Array[lsp_object]
118
+ def value_items(setting)
119
+ SETTING_VALUES.fetch(setting).map do |name|
120
+ completion_item(name, 12, VALUE_DOCUMENTATION.fetch(name))
121
+ end
122
+ end
123
+
124
+ # @rbs (String label, Integer kind, String documentation) -> lsp_object
125
+ def completion_item(label, kind, documentation)
126
+ { "label" => label, "kind" => kind, "documentation" => { "kind" => "markdown", "value" => documentation } }
127
+ end
128
+
129
+ # @rbs (Array[lsp_object] items) -> lsp_object
130
+ def completion_list(items)
131
+ { "isIncomplete" => false, "items" => items }
132
+ end
133
+
134
+ # @rbs (MatchData match, String line, Integer line_start, Integer offset) -> [String?, Integer, Integer]
135
+ def hovered_token(match, line, line_start, offset)
136
+ [1, 2].each do |capture|
137
+ token = match[capture]
138
+ next unless token
139
+
140
+ before = line[0...match.begin(capture)] || ""
141
+ start = line_start + before.bytesize
142
+ finish = start + token.bytesize
143
+ return [token, start, finish] if offset.between?(start, finish - 1)
144
+ end
145
+ [nil, offset, offset]
146
+ end
147
+ end
148
+ end
149
+ end