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,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Builds source occurrences and hover metadata from lossless frontend documents.
6
+ class SymbolIndexBuilder
7
+ include SymbolIndexSourceQueries
8
+ include SymbolIndexPrecedenceReferences
9
+
10
+ # @rbs (DocumentStore store, Array[String] files) -> void
11
+ def initialize(store, files)
12
+ @store = store
13
+ @files = files
14
+ @occurrences = [] #: Array[SymbolOccurrence]
15
+ @documents = {} #: Hash[String, Frontend::SourceDocument]
16
+ @global_kinds = {} #: Hash[String, Symbol]
17
+ @rule_data = {} #: Hash[String, symbol_data]
18
+ @terminal_data = Hash.new { |hash, key| hash[key] = {} } #: Hash[String, symbol_data]
19
+ end
20
+
21
+ # @rbs () -> [Array[SymbolOccurrence], Hash[String, Frontend::SourceDocument]]
22
+ def build
23
+ collect_documents
24
+ # Definitions from every closure file must exist before references are classified.
25
+ # rubocop:disable Style/CombinableLoops
26
+ @documents.each { |path, document| collect_definitions(path, document) }
27
+ @documents.each { |path, document| collect_references(path, document) }
28
+ # rubocop:enable Style/CombinableLoops
29
+ [@occurrences.freeze, @documents.freeze]
30
+ end
31
+
32
+ private
33
+
34
+ # @rbs () -> void
35
+ def collect_documents
36
+ @files.each do |path|
37
+ snapshot = @store.snapshot_for(path)
38
+ document = snapshot&.fetch(:document)
39
+ @documents[path] = document if document
40
+ end
41
+ end
42
+
43
+ # @rbs (String path, Frontend::SourceDocument document) -> void
44
+ def collect_definitions(path, document)
45
+ ast = document.ast
46
+ return unless ast
47
+
48
+ declarations = ast.declarations
49
+ declarations.each_with_index do |declaration, index|
50
+ following = declarations[index + 1]&.loc || ast.rules.first&.loc
51
+ collect_declaration(path, document, declaration, following)
52
+ end
53
+ ast.rules.each { |rule| collect_rule_definition(path, document, rule) }
54
+ end
55
+
56
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::declaration declaration,
57
+ # Frontend::Location? following) -> void
58
+ def collect_declaration(path, document, declaration, following)
59
+ tokens = tokens_between(document, declaration.loc, following)
60
+ case declaration
61
+ when Frontend::AST::Tokens
62
+ add_named_tokens(path, tokens.drop(1), declaration.names, :terminal, :definition)
63
+ when Frontend::AST::DisplayName
64
+ @terminal_data[declaration.name][:display] = declaration.value
65
+ when Frontend::AST::SemanticType
66
+ @terminal_data[declaration.name][:type] = declaration.value
67
+ when Frontend::AST::Precedence
68
+ collect_precedence(declaration)
69
+ when Frontend::AST::Include
70
+ collect_include(path, tokens, declaration)
71
+ end
72
+ end
73
+
74
+ # @rbs (Frontend::AST::Precedence declaration) -> void
75
+ def collect_precedence(declaration)
76
+ declaration.levels.each_with_index do |level, index|
77
+ level.symbols.each do |name|
78
+ @terminal_data[name][:precedence] = {
79
+ direction: declaration.direction, associativity: level.associativity, level: index
80
+ }
81
+ end
82
+ end
83
+ end
84
+
85
+ # @rbs (String path, Array[Frontend::Token] tokens, Frontend::AST::Include declaration) -> void
86
+ def collect_include(path, tokens, declaration)
87
+ token = tokens.find { |candidate| candidate.type == :literal }
88
+ span = token&.span
89
+ return unless span
90
+
91
+ target = canonical_include_target(declaration)
92
+ return unless target
93
+
94
+ add_occurrence(
95
+ name: declaration.path, kind: :include, role: :reference, key: [:include, target],
96
+ path: path, span: span, data: { target: target }
97
+ )
98
+ end
99
+
100
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule) -> void
101
+ def collect_rule_definition(path, document, rule)
102
+ token = token_at(document, rule.loc, rule.lhs)
103
+ span = token&.span
104
+ return unless span
105
+
106
+ lhs_token = token #: Frontend::Token
107
+
108
+ @global_kinds[rule.lhs] ||= :rule
109
+ signature = "#{rule.lhs}#{parameter_signature(rule.parameters)}"
110
+ signature = "%inline #{signature}" if rule.inline
111
+ data = {
112
+ signature: signature,
113
+ documentation: rule.documentation,
114
+ inline: rule.inline,
115
+ parameters: rule.parameters
116
+ }
117
+ @rule_data[rule.lhs] ||= data
118
+ add_occurrence(
119
+ name: rule.lhs, kind: :rule, role: :definition, key: global_key(rule.lhs),
120
+ path: path, span: span, data: data
121
+ )
122
+ collect_parameters(path, document, rule, lhs_token)
123
+ end
124
+
125
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule,
126
+ # Frontend::Token lhs_token) -> void
127
+ def collect_parameters(path, document, rule, lhs_token)
128
+ return if rule.parameters.empty?
129
+
130
+ rule_id = lhs_token.span&.start_byte || 0
131
+ rule.parameters.zip(parameter_tokens(document, lhs_token)).each do |parameter, token|
132
+ span = token&.span
133
+ next unless span
134
+
135
+ add_occurrence(
136
+ name: parameter, kind: :parameter, role: :definition,
137
+ key: parameter_key(path, rule_id, parameter), path: path, span: span,
138
+ data: { rule: rule.lhs }
139
+ )
140
+ end
141
+ end
142
+
143
+ # @rbs (String path, Frontend::SourceDocument document) -> void
144
+ def collect_references(path, document)
145
+ ast = document.ast
146
+ return unless ast
147
+
148
+ ast.declarations.each_with_index do |declaration, index|
149
+ following = ast.declarations[index + 1]&.loc || ast.rules.first&.loc
150
+ collect_declaration_references(path, document, declaration, following)
151
+ end
152
+ ast.rules.each_with_index do |rule, index|
153
+ collect_rule_references(path, document, rule, ast.rules[index + 1]&.loc)
154
+ end
155
+ end
156
+
157
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::declaration declaration,
158
+ # Frontend::Location? following) -> void
159
+ def collect_declaration_references(path, document, declaration, following)
160
+ names = declaration_reference_names(declaration)
161
+ return if names.empty?
162
+
163
+ remaining = tokens_between(document, declaration.loc, following).drop(1)
164
+ names.each do |name|
165
+ index = remaining.index { |token| token.value == name }
166
+ token = index && remaining.delete_at(index)
167
+ add_global_reference(path, token, name) if token
168
+ end
169
+ end
170
+
171
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Rule rule,
172
+ # Frontend::Location? following_rule) -> void
173
+ def collect_rule_references(path, document, rule, following_rule)
174
+ definition = token_at(document, rule.loc, rule.lhs)
175
+ rule_id = definition&.span&.start_byte || 0
176
+ rule.alternatives.each_with_index do |alternative, index|
177
+ alternative.items.each { |item| collect_item(path, document, item, rule, rule_id) }
178
+ following = rule.alternatives[index + 1]&.loc || following_rule
179
+ collect_alternative_precedence(path, document, alternative, following, rule, rule_id)
180
+ end
181
+ end
182
+
183
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::item item,
184
+ # Frontend::AST::Rule rule, Integer rule_id) -> void
185
+ def collect_item(path, document, item, rule, rule_id)
186
+ case item
187
+ when Frontend::AST::SymbolReference, Frontend::AST::ParameterizedReference
188
+ collect_named_item(path, document, item, rule, rule_id)
189
+ item.arguments.each { |child| collect_item(path, document, child, rule, rule_id) } if
190
+ item.is_a?(Frontend::AST::ParameterizedReference)
191
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
192
+ collect_item(path, document, item.item, rule, rule_id)
193
+ when Frontend::AST::Group
194
+ item.alternatives.flatten.each { |child| collect_item(path, document, child, rule, rule_id) }
195
+ when Frontend::AST::SeparatedList
196
+ collect_item(path, document, item.item, rule, rule_id)
197
+ collect_item(path, document, item.separator, rule, rule_id)
198
+ end
199
+ end
200
+
201
+ # @rbs (String path, Frontend::SourceDocument document,
202
+ # Frontend::AST::SymbolReference | Frontend::AST::ParameterizedReference item,
203
+ # Frontend::AST::Rule rule, Integer rule_id) -> void
204
+ def collect_named_item(path, document, item, rule, rule_id)
205
+ token = token_at(document, item.loc, item.name)
206
+ return unless token&.span
207
+
208
+ add_rule_reference(path, token, item.name, rule, rule_id)
209
+ end
210
+
211
+ # @rbs (String path, Frontend::Token token, String name) -> void
212
+ def add_global_reference(path, token, name)
213
+ span = token.span
214
+ return unless span
215
+
216
+ kind = @global_kinds[name] || :terminal
217
+ data = symbol_data(kind, name)
218
+ add_occurrence(name: name, kind: kind, role: :reference, key: global_key(name),
219
+ path: path, span: span, data: data)
220
+ end
221
+
222
+ # @rbs (Symbol kind, String name) -> symbol_data
223
+ def symbol_data(kind, name)
224
+ data = kind == :rule ? @rule_data[name] : @terminal_data[name]
225
+ empty = {} #: symbol_data
226
+ data || empty
227
+ end
228
+
229
+ # @rbs (String path, Array[Frontend::Token] tokens, Array[String] names, Symbol kind, Symbol role) -> void
230
+ def add_named_tokens(path, tokens, names, kind, role)
231
+ remaining = tokens.dup
232
+ names.each do |name|
233
+ index = remaining.index { |token| token.value == name }
234
+ token = index && remaining.delete_at(index)
235
+ span = token&.span
236
+ next unless span
237
+
238
+ @global_kinds[name] ||= kind
239
+ add_occurrence(name: name, kind: kind, role: role, key: global_key(name),
240
+ path: path, span: span, data: @terminal_data[name])
241
+ end
242
+ end
243
+
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
+ )
250
+ end
251
+
252
+ # @rbs (String name) -> symbol_key
253
+ def global_key(name)
254
+ [:symbol, name]
255
+ end
256
+
257
+ # @rbs (String path, Integer rule_id, String name) -> symbol_key
258
+ def parameter_key(path, rule_id, name)
259
+ [:parameter, path, rule_id, name]
260
+ end
261
+
262
+ # @rbs (Array[String] parameters) -> String
263
+ def parameter_signature(parameters)
264
+ parameters.empty? ? "" : "(#{parameters.join(', ')})"
265
+ end
266
+
267
+ # @rbs (Frontend::AST::Include declaration) -> String?
268
+ def canonical_include_target(declaration)
269
+ candidate = File.expand_path(declaration.path, File.dirname(declaration.loc.file))
270
+ target = @store.loader.canonical_path(candidate, allow_missing: true)
271
+ @store.workspace.root_for(target) && target
272
+ rescue SystemCallError
273
+ nil
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Indexes rule-scoped item and alternative precedence references.
6
+ module SymbolIndexPrecedenceReferences
7
+ private
8
+
9
+ # @rbs (String path, Frontend::SourceDocument document, Frontend::AST::Alternative alternative,
10
+ # Frontend::Location? following, Frontend::AST::Rule rule, Integer rule_id) -> void
11
+ def collect_alternative_precedence(path, document, alternative, following, rule, rule_id)
12
+ # @type self: SymbolIndexBuilder
13
+ name = alternative.precedence
14
+ return unless name
15
+
16
+ tokens = tokens_between(document, alternative.loc, following)
17
+ index = (0...(tokens.length - 1)).to_a.reverse.find do |candidate|
18
+ tokens.fetch(candidate).value == "=" && tokens.fetch(candidate + 1).value == name
19
+ end
20
+ token = index && tokens[index + 1]
21
+ add_rule_reference(path, token, name, rule, rule_id) if token
22
+ end
23
+
24
+ # @rbs (String path, Frontend::Token token, String name, Frontend::AST::Rule rule,
25
+ # Integer rule_id) -> void
26
+ def add_rule_reference(path, token, name, rule, rule_id)
27
+ # @type self: SymbolIndexBuilder
28
+ return unless token.span
29
+
30
+ if rule.parameters.include?(name)
31
+ key = parameter_key(path, rule_id, name)
32
+ kind = :parameter
33
+ data = { rule: rule.lhs }
34
+ else
35
+ key = global_key(name)
36
+ kind = @global_kinds[name] || :rule
37
+ data = symbol_data(kind, name)
38
+ end
39
+ add_occurrence(name: name, kind: kind, role: :reference, key: key,
40
+ path: path, span: token.span, data: data)
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
+ # Locates lossless frontend tokens used by the symbol index.
6
+ module SymbolIndexSourceQueries
7
+ private
8
+
9
+ # @rbs (Frontend::SourceDocument document, Frontend::Location start,
10
+ # Frontend::Location? finish) -> Array[Frontend::Token]
11
+ def tokens_between(document, start, finish)
12
+ document.tokens.select do |token|
13
+ after = !location_before?(token.location, start)
14
+ before = finish.nil? || location_before?(token.location, finish)
15
+ after && before
16
+ end
17
+ end
18
+
19
+ # @rbs (Frontend::SourceDocument document, Frontend::Location location, String value) -> Frontend::Token?
20
+ def token_at(document, location, value)
21
+ document.tokens.find do |token|
22
+ token.location.line == location.line && token.location.column == location.column && token.value == value
23
+ end
24
+ end
25
+
26
+ # @rbs (Frontend::SourceDocument document, Frontend::Token lhs_token) -> Array[Frontend::Token]
27
+ def parameter_tokens(document, lhs_token)
28
+ start_index = document.tokens.index(lhs_token)
29
+ return [] unless start_index
30
+
31
+ tail = document.tokens.drop(start_index + 1)
32
+ return [] unless tail.first&.type == :"("
33
+
34
+ tail.take_while { |token| token.type != :")" }.select { |token| token.type == :identifier }
35
+ end
36
+
37
+ # @rbs (Frontend::AST::declaration declaration) -> Array[String]
38
+ def declaration_reference_names(declaration)
39
+ case declaration
40
+ when Frontend::AST::Start, Frontend::AST::OnErrorReduce
41
+ declaration.names
42
+ when Frontend::AST::Recovery
43
+ declaration.sync_tokens
44
+ when Frontend::AST::DisplayName, Frontend::AST::SemanticType
45
+ [declaration.name]
46
+ when Frontend::AST::Convert
47
+ declaration.pairs.map(&:name)
48
+ when Frontend::AST::Precedence
49
+ declaration.levels.flat_map(&:symbols)
50
+ else
51
+ []
52
+ end
53
+ end
54
+
55
+ # @rbs (Frontend::Location left, Frontend::Location right) -> bool
56
+ def location_before?(left, right)
57
+ left.line < right.line || (left.line == right.line && left.column < right.column)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
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
+
11
+ # A source-backed grammar symbol definition or reference.
12
+ SymbolOccurrence = Struct.new(
13
+ :name, #: String
14
+ :kind, #: Symbol
15
+ :role, #: Symbol
16
+ :key, #: symbol_key
17
+ :path, #: String
18
+ :span, #: Frontend::SourceSpan
19
+ :data, #: symbol_data
20
+ keyword_init: true
21
+ )
22
+ end
23
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Reads and writes bounded LSP JSON-RPC messages over Content-Length framing.
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
+
17
+ HEADER_SEPARATOR = "\r\n\r\n"
18
+
19
+ # @rbs (_Input input, _Output output) -> void
20
+ def initialize(input, output)
21
+ @input = input
22
+ @output = output
23
+ @buffer = String.new(encoding: Encoding::BINARY)
24
+ end
25
+
26
+ # @rbs () -> LSP::lsp_object?
27
+ def read_message
28
+ header = read_header
29
+ return unless header
30
+
31
+ length = content_length(header)
32
+ body = read_bytes(length)
33
+ parsed = JSON.parse(body)
34
+ raise ProtocolError.new("JSON-RPC message must be an object", code: -32_600) unless parsed.is_a?(Hash)
35
+
36
+ parsed
37
+ rescue JSON::ParserError => e
38
+ raise ProtocolError.new("malformed JSON: #{e.message}", code: -32_700)
39
+ end
40
+
41
+ # @rbs (LSP::lsp_object message) -> void
42
+ def write_message(message)
43
+ body = JSON.generate(message)
44
+ if body.bytesize > Limits::MAX_OUTPUT_BYTES
45
+ raise ProtocolError.new("JSON-RPC output exceeds #{Limits::MAX_OUTPUT_BYTES} bytes", code: -32_603)
46
+ end
47
+
48
+ @output.write("Content-Length: #{body.bytesize}\r\n\r\n")
49
+ @output.write(body)
50
+ @output.flush if @output.respond_to?(:flush)
51
+ end
52
+
53
+ private
54
+
55
+ # @rbs () -> String?
56
+ def read_header
57
+ loop do
58
+ index = @buffer.index(HEADER_SEPARATOR)
59
+ if index
60
+ if index > Limits::MAX_HEADER_BYTES
61
+ raise ProtocolError.new("JSON-RPC header exceeds #{Limits::MAX_HEADER_BYTES} bytes",
62
+ code: -32_700, fatal: true)
63
+ end
64
+
65
+ header = @buffer.byteslice(0, index) || ""
66
+ @buffer = @buffer.byteslice(index + HEADER_SEPARATOR.bytesize, @buffer.bytesize) || +""
67
+ return header
68
+ end
69
+ if @buffer.bytesize > Limits::MAX_HEADER_BYTES
70
+ raise ProtocolError.new("JSON-RPC header exceeds #{Limits::MAX_HEADER_BYTES} bytes",
71
+ code: -32_700, fatal: true)
72
+ end
73
+
74
+ chunk = read_chunk(4096)
75
+ return nil if chunk.nil? && @buffer.empty?
76
+ raise ProtocolError.new("truncated JSON-RPC header", code: -32_700, fatal: true) unless chunk
77
+
78
+ @buffer << chunk.b
79
+ end
80
+ end
81
+
82
+ # @rbs (String header) -> Integer
83
+ def content_length(header)
84
+ values = header.split("\r\n").filter_map do |line|
85
+ name, value = line.split(":", 2)
86
+ raise ProtocolError.new("malformed JSON-RPC header", code: -32_700, fatal: true) unless value
87
+
88
+ value.strip if name&.casecmp?("Content-Length")
89
+ end
90
+ unless values.one? && values.fetch(0).match?(/\A\d+\z/)
91
+ raise ProtocolError.new("exactly one numeric Content-Length header is required",
92
+ code: -32_700, fatal: true)
93
+ end
94
+
95
+ length = Integer(values.fetch(0), 10)
96
+ if length > Limits::MAX_MESSAGE_BYTES
97
+ raise ProtocolError.new("JSON-RPC message exceeds #{Limits::MAX_MESSAGE_BYTES} bytes",
98
+ code: -32_700, fatal: true)
99
+ end
100
+ length
101
+ end
102
+
103
+ # @rbs (Integer length) -> String
104
+ def read_bytes(length)
105
+ while @buffer.bytesize < length
106
+ chunk = read_chunk([4096, length - @buffer.bytesize].min)
107
+ raise ProtocolError.new("truncated JSON-RPC body", code: -32_700, fatal: true) unless chunk
108
+
109
+ @buffer << chunk.b
110
+ end
111
+ body = @buffer.byteslice(0, length) || ""
112
+ @buffer = @buffer.byteslice(length, @buffer.bytesize) || +""
113
+ body.force_encoding(Encoding::UTF_8)
114
+ end
115
+
116
+ # IO#read(length) may wait for the entire length on a live pipe. readpartial
117
+ # lets the stdio server process the bytes that are already available.
118
+ # @rbs (Integer length) -> String?
119
+ def read_chunk(length)
120
+ return @input.read(length) unless @input.respond_to?(:readpartial)
121
+
122
+ @input.readpartial(length)
123
+ rescue EOFError
124
+ nil
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Converts file URIs to canonical paths constrained to initialized workspace roots.
6
+ class Workspace
7
+ attr_reader :roots #: Array[String]
8
+
9
+ # @rbs (Array[String] root_uris, Frontend::SourceLoader loader) -> void
10
+ def initialize(root_uris, loader)
11
+ raise ProtocolError.new("initialize requires a workspace root", code: -32_602) if root_uris.empty?
12
+
13
+ @loader = loader
14
+ @roots = root_uris.map { |uri| canonical_root(uri) }.uniq.sort.freeze
15
+ end
16
+
17
+ # @rbs (String uri, ?allow_missing: bool) -> String
18
+ def path(uri, allow_missing: true)
19
+ parsed = parse_file_uri(uri)
20
+ decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
21
+
22
+ canonical = @loader.canonical_path(decoded, allow_missing: allow_missing)
23
+ return canonical if root_for(canonical)
24
+
25
+ raise ProtocolError.new("document is outside initialized workspace roots: #{uri}", code: -32_602)
26
+ rescue URI::InvalidURIError, ArgumentError => e
27
+ raise ProtocolError.new("invalid file URI #{uri.inspect}: #{e.message}", code: -32_602)
28
+ rescue SystemCallError => e
29
+ raise ProtocolError.new("cannot resolve file URI #{uri.inspect}: #{e.message}", code: -32_602)
30
+ end
31
+
32
+ # @rbs (String path) -> String
33
+ def uri(path)
34
+ canonical = @loader.canonical_path(path, allow_missing: true)
35
+ parser = begin
36
+ URI::RFC2396_PARSER
37
+ rescue NameError
38
+ URI::DEFAULT_PARSER
39
+ end
40
+ "file://#{parser.escape(canonical)}"
41
+ end
42
+
43
+ # @rbs (String path) -> String?
44
+ def root_for(path)
45
+ roots.select { |root| inside?(path, root) }.max_by(&:length)
46
+ end
47
+
48
+ private
49
+
50
+ # URI is a stdlib boundary whose implementation class varies by scheme.
51
+ # URI parsing returns a scheme-specific URI::Generic subclass.
52
+ # @rbs (String uri) -> URI::Generic
53
+ def parse_file_uri(uri)
54
+ validate_raw_authority!(uri)
55
+ parsed = URI.parse(uri)
56
+ path = parsed.path || raise(ArgumentError, "file URI must contain an absolute path")
57
+ local_host = parsed.host.nil? || parsed.host.empty? || parsed.host.casecmp?("localhost")
58
+ unless parsed.scheme == "file" && local_host &&
59
+ parsed.query.nil? && parsed.fragment.nil? && path&.start_with?("/")
60
+ raise ArgumentError, "only absolute local file URIs are supported"
61
+ end
62
+
63
+ parsed
64
+ end
65
+
66
+ # Ruby's URI::File may discard userinfo and port, so validate the raw authority first.
67
+ # @rbs (String uri) -> void
68
+ def validate_raw_authority!(uri)
69
+ match = uri.match(%r{\Afile://([^/]*)}i)
70
+ return unless match
71
+
72
+ authority = match[1] || ""
73
+ return if authority.empty? || authority.casecmp?("localhost")
74
+
75
+ raise ArgumentError, "only an empty authority or localhost is supported"
76
+ end
77
+
78
+ # @rbs (String uri) -> String
79
+ def canonical_root(uri)
80
+ parsed = parse_file_uri(uri)
81
+ decoded = decode_path(parsed.path || raise(ArgumentError, "file URI must contain an absolute path"))
82
+ canonical = File.realpath(decoded)
83
+ unless File.directory?(canonical)
84
+ raise ProtocolError.new("workspace root is not a directory: #{uri}", code: -32_602)
85
+ end
86
+
87
+ canonical
88
+ rescue URI::InvalidURIError, ArgumentError, SystemCallError => e
89
+ raise ProtocolError.new("invalid workspace root #{uri.inspect}: #{e.message}", code: -32_602)
90
+ end
91
+
92
+ # @rbs (String encoded) -> String
93
+ def decode_path(encoded)
94
+ raise ArgumentError, "file URI contains an invalid percent escape" if
95
+ encoded.match?(/%(?![0-9A-Fa-f]{2})/)
96
+ if encoded.match?(/%(?:2f|5c|00)/i)
97
+ raise ArgumentError, "file URI must not percent-encode a path separator or NUL"
98
+ end
99
+
100
+ parser = begin
101
+ URI::RFC2396_PARSER
102
+ rescue NameError
103
+ URI::DEFAULT_PARSER
104
+ end
105
+ decoded = parser.unescape(encoded)
106
+ raise ArgumentError, "file URI path must be valid UTF-8" unless decoded.valid_encoding?
107
+ raise ArgumentError, "file URI path must not contain NUL" if decoded.include?("\0")
108
+ raise ArgumentError, "file URI path must not contain parent traversal" if
109
+ decoded.split(%r{[\\/]}).include?("..")
110
+
111
+ decoded
112
+ end
113
+
114
+ # @rbs (String path, String root) -> bool
115
+ def inside?(path, root)
116
+ cursor = path
117
+ loop do
118
+ return true if cursor == root
119
+
120
+ parent = File.dirname(cursor)
121
+ return false if parent == cursor
122
+
123
+ cursor = parent
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end