ibex 0.1.0 → 0.2.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 (384) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +247 -104
  3. data/docs/architecture.md +322 -28
  4. data/docs/cst-migration.md +107 -0
  5. data/docs/cst.md +213 -0
  6. data/docs/development.md +129 -0
  7. data/docs/editor-setup.md +25 -0
  8. data/docs/error-ux.md +60 -0
  9. data/docs/grammar-reference.md +458 -18
  10. data/docs/lexer-migration.md +51 -0
  11. data/docs/racc-migration.md +34 -6
  12. data/docs/release-readiness.md +163 -0
  13. data/docs/stability.md +124 -0
  14. data/examples/README.md +60 -0
  15. data/examples/calculator.y +44 -0
  16. data/examples/csv.y +32 -0
  17. data/examples/ini.y +70 -0
  18. data/examples/json.y +48 -0
  19. data/examples/tiny_language.y +75 -0
  20. data/lib/ibex/analysis/sets.rb +5 -4
  21. data/lib/ibex/artifact_set.rb +63 -0
  22. data/lib/ibex/cli/ambiguity.rb +66 -0
  23. data/lib/ibex/cli/counterexample_options.rb +6 -2
  24. data/lib/ibex/cli/coverage.rb +173 -0
  25. data/lib/ibex/cli/debug.rb +106 -0
  26. data/lib/ibex/cli/diagnostics.rb +116 -0
  27. data/lib/ibex/cli/documentation.rb +67 -0
  28. data/lib/ibex/cli/error_messages.rb +177 -0
  29. data/lib/ibex/cli/explain.rb +76 -0
  30. data/lib/ibex/cli/formatting.rb +386 -0
  31. data/lib/ibex/cli/generation_artifacts.rb +138 -0
  32. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  33. data/lib/ibex/cli/grammar_tests.rb +122 -0
  34. data/lib/ibex/cli/ir_tools.rb +184 -0
  35. data/lib/ibex/cli/lsp.rb +33 -0
  36. data/lib/ibex/cli/outputs.rb +91 -8
  37. data/lib/ibex/cli/racc_migration.rb +87 -0
  38. data/lib/ibex/cli/samples.rb +92 -0
  39. data/lib/ibex/cli/watch.rb +103 -0
  40. data/lib/ibex/cli.rb +506 -37
  41. data/lib/ibex/codegen/action_locations.rb +103 -0
  42. data/lib/ibex/codegen/action_method_source.rb +210 -0
  43. data/lib/ibex/codegen/action_source.rb +118 -0
  44. data/lib/ibex/codegen/ambiguity.rb +173 -0
  45. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  46. data/lib/ibex/codegen/documentation.rb +170 -0
  47. data/lib/ibex/codegen/explain.rb +312 -0
  48. data/lib/ibex/codegen/generated_action_abi.rb +288 -0
  49. data/lib/ibex/codegen/html.rb +94 -10
  50. data/lib/ibex/codegen/mermaid.rb +43 -0
  51. data/lib/ibex/codegen/railroad.rb +197 -0
  52. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  53. data/lib/ibex/codegen/rbs.rb +323 -2
  54. data/lib/ibex/codegen/report.rb +46 -6
  55. data/lib/ibex/codegen/ruby.rb +334 -59
  56. data/lib/ibex/codegen/ruby_actions.rb +143 -0
  57. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  58. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  59. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  60. data/lib/ibex/codegen/ruby_syntax.rb +90 -0
  61. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  62. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  63. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  64. data/lib/ibex/coverage/collector.rb +188 -0
  65. data/lib/ibex/coverage/event_stream.rb +97 -0
  66. data/lib/ibex/coverage/report.rb +259 -0
  67. data/lib/ibex/coverage/runtime_event_validator.rb +160 -0
  68. data/lib/ibex/coverage.rb +13 -0
  69. data/lib/ibex/error_messages/parser.rb +159 -0
  70. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  71. data/lib/ibex/error_messages/renderer.rb +65 -0
  72. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  73. data/lib/ibex/error_messages/update.rb +169 -0
  74. data/lib/ibex/error_messages.rb +165 -0
  75. data/lib/ibex/frontend/ast.rb +145 -6
  76. data/lib/ibex/frontend/bootstrap_parser.rb +47 -4
  77. data/lib/ibex/frontend/diagnostic.rb +81 -0
  78. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  79. data/lib/ibex/frontend/dsl.rb +66 -7
  80. data/lib/ibex/frontend/formatter.rb +407 -0
  81. data/lib/ibex/frontend/generated_parser.rb +614 -190
  82. data/lib/ibex/frontend/generated_parser_base.rb +164 -30
  83. data/lib/ibex/frontend/generated_parser_includes.rb +61 -0
  84. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  85. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  86. data/lib/ibex/frontend/generation.rb +33 -0
  87. data/lib/ibex/frontend/lexer.rb +162 -10
  88. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  89. data/lib/ibex/frontend/parser/declarations.rb +247 -11
  90. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  91. data/lib/ibex/frontend/parser/rules.rb +43 -6
  92. data/lib/ibex/frontend/parser.rb +182 -4
  93. data/lib/ibex/frontend/regenerator.rb +26 -1
  94. data/lib/ibex/frontend/resolution.rb +69 -0
  95. data/lib/ibex/frontend/resolver.rb +217 -0
  96. data/lib/ibex/frontend/rule_documentation.rb +103 -0
  97. data/lib/ibex/frontend/source_cursor.rb +132 -8
  98. data/lib/ibex/frontend/source_document.rb +229 -0
  99. data/lib/ibex/frontend/source_loader.rb +150 -0
  100. data/lib/ibex/frontend/source_span.rb +81 -0
  101. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  102. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  103. data/lib/ibex/frontend/token_adapter/declaration_state.rb +216 -26
  104. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  105. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  106. data/lib/ibex/frontend/token_adapter.rb +8 -3
  107. data/lib/ibex/frontend.rb +13 -2
  108. data/lib/ibex/generation_input.rb +57 -0
  109. data/lib/ibex/generation_manifest.rb +200 -0
  110. data/lib/ibex/generation_transaction.rb +261 -0
  111. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  112. data/lib/ibex/generation_transaction_validation.rb +196 -0
  113. data/lib/ibex/grammar_tests.rb +206 -0
  114. data/lib/ibex/ir/automaton_ir.rb +38 -5
  115. data/lib/ibex/ir/grammar_ir.rb +137 -24
  116. data/lib/ibex/ir/lexer_ir.rb +76 -0
  117. data/lib/ibex/ir/migration.rb +120 -0
  118. data/lib/ibex/ir/serialize.rb +110 -19
  119. data/lib/ibex/ir/validator/automaton.rb +345 -0
  120. data/lib/ibex/ir/validator/base.rb +129 -0
  121. data/lib/ibex/ir/validator/grammar.rb +604 -0
  122. data/lib/ibex/ir/validator/lexer.rb +113 -0
  123. data/lib/ibex/ir/validator.rb +62 -0
  124. data/lib/ibex/ir.rb +57 -4
  125. data/lib/ibex/lalr/build_metrics.rb +23 -0
  126. data/lib/ibex/lalr/builder.rb +379 -52
  127. data/lib/ibex/lalr/conflict.rb +1 -0
  128. data/lib/ibex/lalr/conflict_search.rb +11 -5
  129. data/lib/ibex/lalr/counterexample.rb +20 -5
  130. data/lib/ibex/lalr/direct_lookaheads.rb +236 -0
  131. data/lib/ibex/lalr/ielr_partition.rb +152 -0
  132. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  133. data/lib/ibex/lalr.rb +7 -0
  134. data/lib/ibex/location.rb +129 -0
  135. data/lib/ibex/lsp/document_handlers.rb +66 -0
  136. data/lib/ibex/lsp/document_store.rb +264 -0
  137. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  138. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  139. data/lib/ibex/lsp/initialization_handlers.rb +78 -0
  140. data/lib/ibex/lsp/navigation_handlers.rb +56 -0
  141. data/lib/ibex/lsp/position_codec.rb +109 -0
  142. data/lib/ibex/lsp/protocol_error.rb +33 -0
  143. data/lib/ibex/lsp/request_handlers.rb +45 -0
  144. data/lib/ibex/lsp/request_support.rb +87 -0
  145. data/lib/ibex/lsp/server.rb +146 -0
  146. data/lib/ibex/lsp/symbol_index.rb +241 -0
  147. data/lib/ibex/lsp/symbol_index_builder.rb +267 -0
  148. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  149. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  150. data/lib/ibex/lsp/symbol_occurrence.rb +17 -0
  151. data/lib/ibex/lsp/transport.rb +118 -0
  152. data/lib/ibex/lsp/workspace.rb +127 -0
  153. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  154. data/lib/ibex/lsp.rb +32 -0
  155. data/lib/ibex/normalize/declarations.rb +140 -7
  156. data/lib/ibex/normalize/diagnostics.rb +50 -5
  157. data/lib/ibex/normalize/expander.rb +59 -55
  158. data/lib/ibex/normalize/expression.rb +60 -39
  159. data/lib/ibex/normalize/inline_expansion.rb +414 -0
  160. data/lib/ibex/normalize/inline_validation.rb +174 -0
  161. data/lib/ibex/normalize/lexer.rb +131 -0
  162. data/lib/ibex/normalize/named_references.rb +60 -0
  163. data/lib/ibex/normalize/nodes.rb +46 -0
  164. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +69 -0
  165. data/lib/ibex/normalize/parameter_lowering.rb +126 -0
  166. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  167. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  168. data/lib/ibex/normalize/parameters.rb +199 -0
  169. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  170. data/lib/ibex/normalize.rb +179 -14
  171. data/lib/ibex/racc_migration/checker.rb +122 -0
  172. data/lib/ibex/racc_migration/harness.rb +177 -0
  173. data/lib/ibex/racc_migration/report.rb +94 -0
  174. data/lib/ibex/racc_migration.rb +12 -0
  175. data/lib/ibex/rake_task.rb +116 -0
  176. data/lib/ibex/samples.rb +186 -0
  177. data/lib/ibex/table_simulation/result.rb +51 -0
  178. data/lib/ibex/table_simulation/simulator.rb +253 -0
  179. data/lib/ibex/table_simulation/step.rb +60 -0
  180. data/lib/ibex/table_simulation/text.rb +31 -0
  181. data/lib/ibex/table_simulation.rb +13 -0
  182. data/lib/ibex/tables.rb +9 -70
  183. data/lib/ibex/version.rb +1 -1
  184. data/lib/ibex/watch/runner.rb +172 -0
  185. data/lib/ibex/watch/source_snapshot.rb +93 -0
  186. data/lib/ibex/watch.rb +11 -0
  187. data/lib/ibex.rb +25 -1
  188. data/schema/automaton-ir-v1.schema.json +401 -0
  189. data/schema/automaton-ir-v2.schema.json +58 -0
  190. data/schema/benchmark-v1.schema.json +212 -0
  191. data/schema/benchmark-v2.schema.json +61 -0
  192. data/schema/cst-v1.json +170 -0
  193. data/schema/error-ux-v1.schema.json +258 -0
  194. data/schema/explain-v1.schema.json +433 -0
  195. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  196. data/schema/generation-manifest-v1.schema.json +115 -0
  197. data/schema/grammar-ir-v1.schema.json +426 -0
  198. data/schema/grammar-ir-v2.schema.json +779 -0
  199. data/schema/lexer-ir-v1.schema.json +215 -0
  200. data/schema/migration-check-v1.schema.json +60 -0
  201. data/schema/performance-comparison-v1.schema.json +395 -0
  202. data/schema/public-performance-comparison-v1.schema.json +506 -0
  203. data/schema/public-performance-profile-v1.schema.json +360 -0
  204. data/schema/runtime-coverage-v1.schema.json +86 -0
  205. data/schema/runtime-event-v1.schema.json +308 -0
  206. data/schema/table-simulation-v1.schema.json +70 -0
  207. data/sig/ibex/artifact_set.rbs +37 -0
  208. data/sig/ibex/cli/ambiguity.rbs +22 -0
  209. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  210. data/sig/ibex/cli/coverage.rbs +53 -0
  211. data/sig/ibex/cli/debug.rbs +28 -0
  212. data/sig/ibex/cli/diagnostics.rbs +38 -0
  213. data/sig/ibex/cli/documentation.rbs +25 -0
  214. data/sig/ibex/cli/error_messages.rbs +57 -0
  215. data/sig/ibex/cli/explain.rbs +25 -0
  216. data/sig/ibex/cli/formatting.rbs +103 -0
  217. data/sig/ibex/cli/generation_artifacts.rbs +50 -0
  218. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  219. data/sig/ibex/cli/grammar_tests.rbs +36 -0
  220. data/sig/ibex/cli/ir_tools.rbs +51 -0
  221. data/sig/ibex/cli/lsp.rbs +14 -0
  222. data/sig/ibex/cli/outputs.rbs +17 -0
  223. data/sig/ibex/cli/racc_migration.rbs +30 -0
  224. data/sig/ibex/cli/samples.rbs +30 -0
  225. data/sig/ibex/cli/watch.rbs +43 -0
  226. data/sig/ibex/cli.rbs +104 -5
  227. data/sig/ibex/codegen/action_locations.rbs +45 -0
  228. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  229. data/sig/ibex/codegen/action_source.rbs +50 -0
  230. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  231. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  232. data/sig/ibex/codegen/documentation.rbs +50 -0
  233. data/sig/ibex/codegen/explain.rbs +85 -0
  234. data/sig/ibex/codegen/generated_action_abi.rbs +101 -0
  235. data/sig/ibex/codegen/html.rbs +18 -2
  236. data/sig/ibex/codegen/mermaid.rbs +16 -0
  237. data/sig/ibex/codegen/railroad.rbs +82 -0
  238. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  239. data/sig/ibex/codegen/rbs.rbs +84 -4
  240. data/sig/ibex/codegen/report.rbs +8 -0
  241. data/sig/ibex/codegen/ruby.rbs +97 -23
  242. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  243. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  244. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  245. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  246. data/sig/ibex/codegen/ruby_syntax.rbs +25 -0
  247. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  248. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  249. data/sig/ibex/coverage/collector.rbs +76 -0
  250. data/sig/ibex/coverage/event_stream.rbs +42 -0
  251. data/sig/ibex/coverage/report.rbs +100 -0
  252. data/sig/ibex/coverage/runtime_event_validator.rbs +68 -0
  253. data/sig/ibex/coverage.rbs +7 -0
  254. data/sig/ibex/error_messages/parser.rbs +58 -0
  255. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  256. data/sig/ibex/error_messages/renderer.rbs +23 -0
  257. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  258. data/sig/ibex/error_messages/update.rbs +43 -0
  259. data/sig/ibex/error_messages.rbs +85 -0
  260. data/sig/ibex/frontend/ast.rbs +208 -19
  261. data/sig/ibex/frontend/bootstrap_parser.rbs +11 -0
  262. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  263. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  264. data/sig/ibex/frontend/dsl.rbs +33 -4
  265. data/sig/ibex/frontend/formatter.rbs +135 -0
  266. data/sig/ibex/frontend/generated_parser.rbs +218 -68
  267. data/sig/ibex/frontend/generated_parser_base.rbs +61 -10
  268. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  269. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  270. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  271. data/sig/ibex/frontend/generation.rbs +6 -0
  272. data/sig/ibex/frontend/lexer.rbs +49 -2
  273. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  274. data/sig/ibex/frontend/parser/declarations.rbs +54 -0
  275. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  276. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  277. data/sig/ibex/frontend/parser.rbs +66 -0
  278. data/sig/ibex/frontend/regenerator.rbs +11 -0
  279. data/sig/ibex/frontend/resolution.rbs +33 -0
  280. data/sig/ibex/frontend/resolver.rbs +91 -0
  281. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  282. data/sig/ibex/frontend/source_cursor.rbs +36 -3
  283. data/sig/ibex/frontend/source_document.rbs +119 -0
  284. data/sig/ibex/frontend/source_loader.rbs +66 -0
  285. data/sig/ibex/frontend/source_span.rbs +53 -0
  286. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  287. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  288. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +73 -5
  289. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  290. data/sig/ibex/frontend/token_adapter.rbs +5 -2
  291. data/sig/ibex/frontend.rbs +1 -1
  292. data/sig/ibex/generation_input.rbs +37 -0
  293. data/sig/ibex/generation_manifest.rbs +67 -0
  294. data/sig/ibex/generation_transaction.rbs +82 -0
  295. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  296. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  297. data/sig/ibex/grammar_tests.rbs +93 -0
  298. data/sig/ibex/ir/automaton_ir.rbs +8 -2
  299. data/sig/ibex/ir/grammar_ir.rbs +75 -15
  300. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  301. data/sig/ibex/ir/migration.rbs +34 -0
  302. data/sig/ibex/ir/serialize.rbs +23 -6
  303. data/sig/ibex/ir/validator/automaton.rbs +109 -0
  304. data/sig/ibex/ir/validator/base.rbs +65 -0
  305. data/sig/ibex/ir/validator/grammar.rbs +184 -0
  306. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  307. data/sig/ibex/ir/validator.rbs +16 -0
  308. data/sig/ibex/ir.rbs +38 -4
  309. data/sig/ibex/lalr/build_metrics.rbs +20 -0
  310. data/sig/ibex/lalr/builder.rbs +95 -15
  311. data/sig/ibex/lalr/conflict_search.rbs +7 -3
  312. data/sig/ibex/lalr/counterexample.rbs +5 -2
  313. data/sig/ibex/lalr/direct_lookaheads.rbs +86 -0
  314. data/sig/ibex/lalr/ielr_partition.rbs +59 -0
  315. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  316. data/sig/ibex/lalr.rbs +6 -0
  317. data/sig/ibex/location.rbs +67 -0
  318. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  319. data/sig/ibex/lsp/document_store.rbs +94 -0
  320. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  321. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  322. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  323. data/sig/ibex/lsp/navigation_handlers.rbs +30 -0
  324. data/sig/ibex/lsp/position_codec.rbs +40 -0
  325. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  326. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  327. data/sig/ibex/lsp/request_support.rbs +40 -0
  328. data/sig/ibex/lsp/server.rbs +55 -0
  329. data/sig/ibex/lsp/symbol_index.rbs +78 -0
  330. data/sig/ibex/lsp/symbol_index_builder.rbs +87 -0
  331. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  332. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  333. data/sig/ibex/lsp/symbol_occurrence.rbs +25 -0
  334. data/sig/ibex/lsp/transport.rbs +35 -0
  335. data/sig/ibex/lsp/workspace.rbs +41 -0
  336. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  337. data/sig/ibex/lsp.rbs +7 -0
  338. data/sig/ibex/normalize/declarations.rbs +31 -0
  339. data/sig/ibex/normalize/diagnostics.rbs +9 -0
  340. data/sig/ibex/normalize/expander.rbs +20 -14
  341. data/sig/ibex/normalize/expression.rbs +10 -10
  342. data/sig/ibex/normalize/inline_expansion.rbs +120 -0
  343. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  344. data/sig/ibex/normalize/lexer.rbs +37 -0
  345. data/sig/ibex/normalize/named_references.rbs +20 -0
  346. data/sig/ibex/normalize/nodes.rbs +14 -0
  347. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +32 -0
  348. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  349. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  350. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  351. data/sig/ibex/normalize/parameters.rbs +46 -0
  352. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  353. data/sig/ibex/normalize.rbs +123 -18
  354. data/sig/ibex/racc_migration/checker.rbs +36 -0
  355. data/sig/ibex/racc_migration/harness.rbs +16 -0
  356. data/sig/ibex/racc_migration/report.rbs +53 -0
  357. data/sig/ibex/racc_migration.rbs +8 -0
  358. data/sig/ibex/rake_task.rbs +51 -0
  359. data/sig/ibex/samples.rbs +51 -0
  360. data/sig/ibex/table_simulation/result.rbs +32 -0
  361. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  362. data/sig/ibex/table_simulation/step.rbs +40 -0
  363. data/sig/ibex/table_simulation/text.rbs +14 -0
  364. data/sig/ibex/table_simulation.rbs +7 -0
  365. data/sig/ibex/tables.rbs +0 -26
  366. data/sig/ibex/watch/runner.rbs +48 -0
  367. data/sig/ibex/watch/source_snapshot.rbs +42 -0
  368. data/sig/ibex/watch.rbs +7 -0
  369. data/sig/ibex.rbs +2 -0
  370. metadata +301 -16
  371. data/.rubocop.yml +0 -43
  372. data/CHANGELOG.md +0 -30
  373. data/Rakefile +0 -25
  374. data/Steepfile +0 -10
  375. data/docs/compat-notes.md +0 -37
  376. data/docs/lexer-coverage.md +0 -14
  377. data/docs/phase10-extensions.md +0 -27
  378. data/gemfiles/Gemfile +0 -7
  379. data/gemfiles/Gemfile.lock +0 -98
  380. data/lib/ibex/frontend/grammar.y +0 -156
  381. data/lib/ibex/runtime/parser.rb +0 -360
  382. data/lib/ibex/runtime.rb +0 -8
  383. data/sig/ibex/runtime/parser.rbs +0 -167
  384. data/sig/ibex/runtime.rbs +0 -6
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Shared publication, state, and parameter validation for request handlers.
6
+ module RequestSupport
7
+ private
8
+
9
+ # @rbs (Array[DocumentStore::publication] publications) -> void
10
+ def publish(publications)
11
+ publications.each do |publication|
12
+ version = publication[:version]
13
+ next if version && stale_publication?(publication.fetch(:uri), version)
14
+
15
+ params = {
16
+ "uri" => publication.fetch(:uri),
17
+ "diagnostics" => publication.fetch(:diagnostics)
18
+ } #: Hash[String, untyped]
19
+ params["version"] = version if version
20
+ @transport.write_message(
21
+ "jsonrpc" => "2.0", "method" => "textDocument/publishDiagnostics", "params" => params
22
+ )
23
+ end
24
+ end
25
+
26
+ # @rbs (String uri, Integer version) -> bool
27
+ def stale_publication?(uri, version)
28
+ path = workspace.path(uri)
29
+ store.snapshot_for(path)&.fetch(:version) != version
30
+ end
31
+
32
+ # @rbs (untyped value) -> Hash[String, untyped]
33
+ def params_hash(value)
34
+ return {} if value.nil?
35
+ return value if value.is_a?(Hash)
36
+
37
+ raise ProtocolError.new("params must be an object", code: -32_602)
38
+ end
39
+
40
+ # @rbs (Hash[String, untyped] value, String name) -> Hash[String, untyped]
41
+ def hash_member(value, name)
42
+ member = value[name]
43
+ return member if member.is_a?(Hash)
44
+
45
+ raise ProtocolError.new("#{name} must be an object", code: -32_602)
46
+ end
47
+
48
+ # @rbs (Hash[String, untyped] value, String name) -> String
49
+ def string_member(value, name)
50
+ member = value[name]
51
+ return member if member.is_a?(String)
52
+
53
+ raise ProtocolError.new("#{name} must be a string", code: -32_602)
54
+ end
55
+
56
+ # @rbs (Hash[String, untyped] value, String name) -> Integer
57
+ def integer_member(value, name)
58
+ member = value[name]
59
+ return member if member.is_a?(Integer)
60
+
61
+ raise ProtocolError.new("#{name} must be an integer", code: -32_602)
62
+ end
63
+
64
+ # @rbs (Symbol state) -> void
65
+ def require_state!(state)
66
+ return if @state == state
67
+
68
+ raise ProtocolError.new("request requires #{state} server state", code: -32_600)
69
+ end
70
+
71
+ # @rbs () -> void
72
+ def require_running!
73
+ require_state!(:running)
74
+ end
75
+
76
+ # @rbs () -> DocumentStore
77
+ def store
78
+ @store || raise(ProtocolError.new("server is not initialized", code: -32_002))
79
+ end
80
+
81
+ # @rbs () -> Workspace
82
+ def workspace
83
+ @workspace || raise(ProtocolError.new("server is not initialized", code: -32_002))
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Coordinates JSON-RPC lifecycle, request responses, and protocol-safe logging.
6
+ class Server
7
+ include RequestHandlers
8
+
9
+ REQUEST_METHODS = %w[
10
+ initialize shutdown textDocument/definition textDocument/references textDocument/prepareRename
11
+ textDocument/rename textDocument/hover
12
+ ].freeze #: Array[String]
13
+ NOTIFICATION_METHODS = %w[
14
+ initialized exit textDocument/didOpen textDocument/didChange textDocument/didSave textDocument/didClose
15
+ $/cancelRequest
16
+ ].freeze #: Array[String]
17
+
18
+ # @rbs (stdin: untyped, stdout: untyped, stderr: untyped) -> void
19
+ def initialize(stdin:, stdout:, stderr:)
20
+ @transport = Transport.new(stdin, stdout)
21
+ @stderr = stderr
22
+ @state = :uninitialized
23
+ @exit_requested = false
24
+ @exit_status = nil #: Integer?
25
+ end
26
+
27
+ # @rbs () -> Integer
28
+ def run
29
+ until @exit_requested
30
+ message = read_message
31
+ break unless message
32
+
33
+ process_message(message)
34
+ end
35
+ @exit_status || 1
36
+ end
37
+
38
+ private
39
+
40
+ # @rbs () -> Hash[String, untyped]?
41
+ def read_message
42
+ @transport.read_message
43
+ rescue ProtocolError => e
44
+ send_error(nil, e)
45
+ @exit_requested = true if e.fatal
46
+ retry unless e.fatal
47
+ nil
48
+ end
49
+
50
+ # @rbs (Hash[String, untyped] message) -> void
51
+ def process_message(message)
52
+ request_id = safe_request_id(message)
53
+ notification = notification_envelope?(message)
54
+ request_id = validate_envelope(message)
55
+ method = message.fetch("method")
56
+ validate_message_kind!(method, message.key?("id"))
57
+ return if request_id.nil? && method.start_with?("$/")
58
+
59
+ validate_lifecycle!(method)
60
+ result = dispatch(method, message["params"])
61
+ send_result(request_id, result) if request_id
62
+ rescue ProtocolError => e
63
+ notification ? log(e.message) : send_error(request_id, e)
64
+ rescue StandardError => e
65
+ error = ProtocolError.new("internal error: #{e.message}", code: -32_603)
66
+ notification ? log(error.message) : send_error(request_id, error)
67
+ end
68
+
69
+ # @rbs (Hash[String, untyped] message) -> (String | Integer)?
70
+ def safe_request_id(message)
71
+ value = message["id"]
72
+ value if valid_request_id?(value)
73
+ end
74
+
75
+ # @rbs (Hash[String, untyped] message) -> bool
76
+ def notification_envelope?(message)
77
+ !message.key?("id") && message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
78
+ end
79
+
80
+ # @rbs (String method, bool request) -> void
81
+ def validate_message_kind!(method, request)
82
+ if REQUEST_METHODS.include?(method) && !request
83
+ raise ProtocolError.new("#{method} must be a request", code: -32_600)
84
+ end
85
+ return unless NOTIFICATION_METHODS.include?(method) && request
86
+
87
+ raise ProtocolError.new("#{method} must be a notification", code: -32_600)
88
+ end
89
+
90
+ # @rbs (Hash[String, untyped] message) -> (String | Integer)?
91
+ def validate_envelope(message)
92
+ unless message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
93
+ raise ProtocolError.new("invalid JSON-RPC request", code: -32_600)
94
+ end
95
+ return nil unless message.key?("id")
96
+
97
+ request_id = message["id"]
98
+ unless valid_request_id?(request_id)
99
+ raise ProtocolError.new("request id must be a bounded string or integer", code: -32_600)
100
+ end
101
+
102
+ request_id
103
+ end
104
+
105
+ # @rbs (untyped value) -> bool
106
+ def valid_request_id?(value)
107
+ return false unless value.is_a?(String) || value.is_a?(Integer)
108
+
109
+ value.to_s.bytesize <= Limits::MAX_REQUEST_ID_BYTES
110
+ end
111
+
112
+ # @rbs (String method) -> void
113
+ def validate_lifecycle!(method)
114
+ return if method == "exit"
115
+ return if @state == :uninitialized && method == "initialize"
116
+ return if @state == :initialized && %w[initialized shutdown].include?(method)
117
+ return if @state == :running
118
+
119
+ code = @state == :uninitialized ? -32_002 : -32_600
120
+ raise ProtocolError.new("request is invalid in #{@state} server state", code: code)
121
+ end
122
+
123
+ # @rbs (String | Integer request_id, untyped result) -> void
124
+ def send_result(request_id, result)
125
+ @transport.write_message("jsonrpc" => "2.0", "id" => request_id, "result" => result)
126
+ rescue ProtocolError => e
127
+ send_error(request_id, e)
128
+ end
129
+
130
+ # @rbs (String | Integer | nil request_id, ProtocolError error) -> void
131
+ def send_error(request_id, error)
132
+ @transport.write_message(
133
+ "jsonrpc" => "2.0", "id" => request_id,
134
+ "error" => { "code" => error.code, "message" => error.message }
135
+ )
136
+ rescue ProtocolError => e
137
+ log(e.message)
138
+ end
139
+
140
+ # @rbs (String message) -> void
141
+ def log(message)
142
+ @stderr.puts(message)
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module LSP
5
+ # Answers source navigation and guarded workspace rename operations.
6
+ class SymbolIndex
7
+ IDENTIFIER = /\A[A-Za-z_][A-Za-z0-9_]*\z/ #: Regexp
8
+ RESERVED = %w[
9
+ class fragment include token prechigh preclow left right nonassoc options expect start
10
+ recover sync on_error_reduce convert display type pragma extended rule end
11
+ separated_list separated_nonempty_list
12
+ ].freeze #: Array[String]
13
+
14
+ # @rbs (DocumentStore store, String path) -> void
15
+ def initialize(store, path)
16
+ @store = store
17
+ @path = path
18
+ files = store.files_for(path)
19
+ @occurrences, @documents = SymbolIndexBuilder.new(store, files).build
20
+ @snapshot_state = files.to_h do |file|
21
+ snapshot = store.snapshot_for(file)
22
+ [file, snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]]
23
+ end #: Hash[String, Array[untyped]?]
24
+ end
25
+
26
+ # @rbs (String path, Hash[String, untyped] position) -> Array[Hash[String, untyped]]
27
+ def definition(path, position)
28
+ occurrence = occurrence_at(path, position)
29
+ return [] unless occurrence
30
+ return [include_target_location(occurrence)] if occurrence.kind == :include
31
+
32
+ matching(occurrence.key, role: :definition).map { |entry| location(entry) }
33
+ end
34
+
35
+ # @rbs (String path, Hash[String, untyped] position, ?include_declaration: bool) ->
36
+ # Array[Hash[String, untyped]]
37
+ def references(path, position, include_declaration: false)
38
+ occurrence = occurrence_at(path, position)
39
+ return [] unless occurrence
40
+
41
+ entries = matching(occurrence.key)
42
+ entries = entries.reject { |entry| entry.role == :definition } unless include_declaration
43
+ entries.map { |entry| location(entry) }
44
+ end
45
+
46
+ # @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
47
+ def prepare_rename(path, position)
48
+ occurrence = renameable_occurrence(path, position)
49
+ { "range" => range(occurrence), "placeholder" => occurrence.name }
50
+ end
51
+
52
+ # @rbs (String path, Hash[String, untyped] position, String new_name) -> Hash[String, untyped]
53
+ def rename(path, position, new_name)
54
+ ensure_fresh!
55
+ occurrence = renameable_occurrence(path, position)
56
+ validate_new_name(occurrence, new_name)
57
+ entries = matching(occurrence.key)
58
+ validate_unshared(entries)
59
+ validate_nonoverlapping(entries)
60
+ changes = entries.group_by(&:path).transform_values do |path_entries|
61
+ path_entries.sort_by { |entry| entry.span.start_byte }.map do |entry|
62
+ { "range" => range(entry), "newText" => new_name }
63
+ end
64
+ end
65
+ replacements = changed_sources(entries, new_name)
66
+ unless @store.valid_replacements?(replacements)
67
+ raise ProtocolError.new("rename would make the affected grammar closure invalid", code: -32_602)
68
+ end
69
+
70
+ document_changes = changes.sort.map do |changed_path, edits|
71
+ snapshot = @store.snapshot_for(changed_path)
72
+ version = snapshot&.fetch(:open) ? snapshot.fetch(:version) : nil
73
+ {
74
+ "textDocument" => { "uri" => @store.uri_for(changed_path), "version" => version },
75
+ "edits" => edits
76
+ }
77
+ end
78
+ { "documentChanges" => document_changes }
79
+ end
80
+
81
+ # @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
82
+ def hover(path, position)
83
+ occurrence = occurrence_at(path, position)
84
+ return unless occurrence
85
+
86
+ value = hover_value(occurrence)
87
+ return unless value
88
+
89
+ {
90
+ "contents" => { "kind" => "markdown", "value" => value },
91
+ "range" => range(occurrence)
92
+ }
93
+ end
94
+
95
+ private
96
+
97
+ # @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence?
98
+ def occurrence_at(path, position)
99
+ document = @documents[path]
100
+ return unless document
101
+
102
+ offset = PositionCodec.new(document.source).byte_offset(position)
103
+ candidates = @occurrences.select do |entry|
104
+ entry.path == path && entry.span.start_byte <= offset && offset < entry.span.end_byte
105
+ end
106
+ candidates.min_by { |entry| entry.span.length }
107
+ end
108
+
109
+ # @rbs (Array[untyped] key, ?role: Symbol?) -> Array[SymbolOccurrence]
110
+ def matching(key, role: nil)
111
+ @occurrences.select { |entry| entry.key == key && (!role || entry.role == role) }
112
+ end
113
+
114
+ # @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
115
+ def location(occurrence)
116
+ { "uri" => @store.uri_for(occurrence.path), "range" => range(occurrence) }
117
+ end
118
+
119
+ # @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
120
+ def include_target_location(occurrence)
121
+ target = occurrence.data.fetch(:target)
122
+ point = { "line" => 0, "character" => 0 }
123
+ { "uri" => @store.uri_for(target), "range" => { "start" => point, "end" => point.dup } }
124
+ end
125
+
126
+ # @rbs (SymbolOccurrence occurrence) -> Hash[String, Hash[String, Integer]]
127
+ def range(occurrence)
128
+ document = @documents.fetch(occurrence.path)
129
+ PositionCodec.new(document.source).range(occurrence.span)
130
+ end
131
+
132
+ # @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence
133
+ def renameable_occurrence(path, position)
134
+ occurrence = occurrence_at(path, position)
135
+ unless occurrence && %i[rule terminal parameter].include?(occurrence.kind) &&
136
+ occurrence.name.match?(IDENTIFIER) && !RESERVED.include?(occurrence.name)
137
+ raise ProtocolError.new("symbol at position cannot be renamed", code: -32_602)
138
+ end
139
+ unless matching(occurrence.key, role: :definition).any?
140
+ raise ProtocolError.new("unresolved symbol cannot be renamed", code: -32_602)
141
+ end
142
+
143
+ occurrence
144
+ end
145
+
146
+ # @rbs (SymbolOccurrence occurrence, String new_name) -> void
147
+ def validate_new_name(occurrence, new_name)
148
+ unless new_name.is_a?(String) && new_name.match?(IDENTIFIER) && !RESERVED.include?(new_name)
149
+ raise ProtocolError.new("new name must be a non-reserved grammar identifier", code: -32_602)
150
+ end
151
+
152
+ collision = @occurrences.any? do |entry|
153
+ entry.role == :definition && entry.name == new_name && entry.key != occurrence.key &&
154
+ collision_scope?(entry, occurrence)
155
+ end
156
+ raise ProtocolError.new("rename collides with existing symbol #{new_name}", code: -32_602) if collision
157
+ end
158
+
159
+ # @rbs (SymbolOccurrence candidate, SymbolOccurrence occurrence) -> bool
160
+ def collision_scope?(candidate, occurrence)
161
+ return candidate.key.take(3) == occurrence.key.take(3) if occurrence.kind == :parameter
162
+
163
+ candidate.kind != :parameter
164
+ end
165
+
166
+ # @rbs (Array[SymbolOccurrence] entries) -> void
167
+ def validate_nonoverlapping(entries)
168
+ entries.group_by(&:path).each_value do |path_entries|
169
+ ordered = path_entries.sort_by { |entry| [entry.span.start_byte, entry.span.end_byte] }
170
+ overlap = (1...ordered.length).any? do |index|
171
+ ordered.fetch(index - 1).span.end_byte > ordered.fetch(index).span.start_byte
172
+ end
173
+ raise ProtocolError.new("rename contains overlapping source edits", code: -32_603) if overlap
174
+ end
175
+ end
176
+
177
+ # @rbs (Array[SymbolOccurrence] entries) -> void
178
+ def validate_unshared(entries)
179
+ return unless entries.any? { |entry| @store.roots_for(entry.path).length > 1 }
180
+
181
+ raise ProtocolError.new("rename affecting a fragment shared by multiple roots is ambiguous", code: -32_602)
182
+ end
183
+
184
+ # @rbs () -> void
185
+ def ensure_fresh!
186
+ stale = @snapshot_state.any? do |path, expected|
187
+ snapshot = @store.snapshot_for(path)
188
+ actual = snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]
189
+ actual != expected
190
+ end
191
+ raise ProtocolError.new("symbol snapshot is stale; retry the request", code: -32_602) if stale
192
+ end
193
+
194
+ # @rbs (Array[SymbolOccurrence] entries, String new_name) -> Hash[String, String]
195
+ def changed_sources(entries, new_name)
196
+ entries.group_by(&:path).to_h do |path, path_entries|
197
+ document = @documents.fetch(path)
198
+ source = document.source.dup
199
+ path_entries.sort_by { |entry| -entry.span.start_byte }.each do |entry|
200
+ prefix = source.byteslice(0, entry.span.start_byte) || ""
201
+ suffix = source.byteslice(entry.span.end_byte, source.bytesize - entry.span.end_byte) || ""
202
+ source = prefix + new_name + suffix
203
+ end
204
+ [path, source]
205
+ end
206
+ end
207
+
208
+ # @rbs (SymbolOccurrence occurrence) -> String?
209
+ def hover_value(occurrence)
210
+ case occurrence.kind
211
+ when :rule then rule_hover(occurrence)
212
+ when :terminal then terminal_hover(occurrence)
213
+ when :parameter then "`#{occurrence.name}` — formal parameter of `#{occurrence.data[:rule]}`"
214
+ when :include then "Includes `#{occurrence.data[:target]}`"
215
+ end
216
+ end
217
+
218
+ # @rbs (SymbolOccurrence occurrence) -> String
219
+ def rule_hover(occurrence)
220
+ definition = matching(occurrence.key, role: :definition).first
221
+ data = definition&.data || occurrence.data
222
+ lines = ["```ibex", data[:signature] || occurrence.name, "```"]
223
+ lines << data[:documentation] if data[:documentation]
224
+ lines.join("\n")
225
+ end
226
+
227
+ # @rbs (SymbolOccurrence occurrence) -> String
228
+ def terminal_hover(occurrence)
229
+ definition = matching(occurrence.key, role: :definition).first
230
+ data = definition&.data || occurrence.data
231
+ lines = ["`#{occurrence.name}` — terminal"]
232
+ lines << "Display: #{data[:display]}" if data[:display]
233
+ lines << "Type: `#{data[:type]}`" if data[:type]
234
+ if (precedence = data[:precedence])
235
+ lines << "Precedence: #{precedence[:associativity]} level #{precedence[:level]}"
236
+ end
237
+ lines.join("\n\n")
238
+ end
239
+ end
240
+ end
241
+ end