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
@@ -3,9 +3,14 @@
3
3
  module Ibex
4
4
  module Frontend
5
5
  # Parses the declaration section of a grammar.
6
+ # rubocop:disable Metrics/ModuleLength, Metrics/CyclomaticComplexity
7
+ # Bootstrap declarations intentionally mirror the generated frontend's complete declaration vocabulary.
6
8
  module BootstrapParserDeclarations
7
- DECLARATIONS = %w[token prechigh preclow options expect start convert pragma rule].freeze #: Array[String]
8
- ASSOCIATIVITIES = %w[left right nonassoc].freeze #: Array[String]
9
+ DECLARATIONS = %w[
10
+ include import token prechigh preclow options expect expect_rr start recover on_error_reduce
11
+ test lexer convert display type param printer pragma rule
12
+ ].freeze #: Array[String]
13
+ ASSOCIATIVITIES = %w[left right nonassoc precedence].freeze #: Array[String]
9
14
 
10
15
  private
11
16
 
@@ -20,18 +25,16 @@ module Ibex
20
25
  # @rbs () -> void
21
26
  def parse_pragmas
22
27
  # @type self: BootstrapParser
23
- seen = false
24
28
  while keyword?("pragma")
25
29
  keyword = current
26
- fail_at(keyword.location, "duplicate pragma extended") if seen
27
-
28
30
  advance
29
31
  value = expect(:identifier)
30
32
  name = token_string(value)
31
- fail_at(value.location, "unknown pragma #{name}") unless name == "extended"
33
+ fail_at(value.location, "unknown pragma #{name}") unless %w[extended cst].include?(name)
34
+ fail_at(keyword.location, "duplicate pragma #{name}") if @pragmas[name]
32
35
 
36
+ @pragmas[name] = true
33
37
  @mode = :extended
34
- seen = true
35
38
  end
36
39
  end
37
40
 
@@ -39,24 +42,62 @@ module Ibex
39
42
  def parse_declaration
40
43
  # @type self: BootstrapParser
41
44
  case current.value
45
+ when "include", "import" then parse_import
42
46
  when "token" then parse_tokens
43
47
  when "prechigh", "preclow" then parse_precedence
44
48
  when "options" then parse_options
45
49
  when "expect" then parse_expect
50
+ when "expect_rr" then parse_expect_rr
46
51
  when "start" then parse_start
52
+ when "recover" then parse_recovery
53
+ when "on_error_reduce" then parse_on_error_reduce
54
+ when "test" then parse_grammar_test
55
+ when "lexer" then parse_lexer
47
56
  when "convert" then parse_convert
57
+ when "display" then parse_symbol_metadata(AST::DisplayName, "display")
58
+ when "type" then parse_symbol_metadata(AST::SemanticType, "type")
59
+ when "param" then parse_parameter
60
+ when "printer" then parse_printer
48
61
  when "pragma" then fail_at(current.location, "expected rule, got pragma")
49
62
  else fail_expected("a declaration or rule")
50
63
  end
51
64
  end
52
65
 
66
+ # @rbs () -> AST::Include
67
+ def parse_import
68
+ # @type self: BootstrapParser
69
+ keyword = advance
70
+ extended_only!(keyword.location, "#{keyword.value}s")
71
+ path = expect(:literal)
72
+ value = token_string(path)
73
+ unless value.start_with?('"') && value.end_with?('"')
74
+ fail_at(path.location, "#{keyword.value} path must use a double-quoted string")
75
+ end
76
+
77
+ decoded = begin
78
+ value.undump
79
+ rescue RuntimeError => e
80
+ fail_at(path.location, "invalid #{keyword.value} path: #{e.message}")
81
+ end
82
+ AST::Include.new(path: decoded, loc: keyword.location)
83
+ end
84
+
53
85
  # @rbs () -> AST::Tokens
54
86
  def parse_tokens
55
87
  # @type self: BootstrapParser
56
88
  location = advance.location
57
89
  names = [] #: Array[String]
58
- names << parse_symbol_name until declaration_start?
59
- AST::Tokens.new(names: names, loc: location)
90
+ aliases = {} #: Hash[String, String]
91
+ until declaration_start?
92
+ name_token = expect_symbol
93
+ name = token_string(name_token)
94
+ names << name
95
+ next unless @mode == :extended && name_token.type == :identifier &&
96
+ current.type == :literal && current.location.line == name_token.location.line
97
+
98
+ aliases[name] = decode_quoted_literal(advance, "token alias")
99
+ end
100
+ AST::Tokens.new(names: names, aliases: aliases.empty? ? nil : aliases, loc: location)
60
101
  end
61
102
 
62
103
  # @rbs () -> AST::Precedence
@@ -77,6 +118,7 @@ module Ibex
77
118
  levels = [] #: Array[AST::PrecedenceLevel]
78
119
  until keyword?(closing) || current.type == :eof
79
120
  association = expect_one_of(ASSOCIATIVITIES)
121
+ extended_only!(association.location, "%precedence") if token_string(association) == "precedence"
80
122
  symbols = [] #: Array[String]
81
123
  symbols << parse_symbol_name until association_start? || keyword?(closing) || current.type == :eof
82
124
  fail_at(association.location, "expected at least one precedence symbol") if symbols.empty?
@@ -102,11 +144,152 @@ module Ibex
102
144
  AST::Expect.new(conflicts: token_integer(expect(:integer)), loc: location)
103
145
  end
104
146
 
147
+ # @rbs () -> AST::ExpectRR
148
+ def parse_expect_rr
149
+ # @type self: BootstrapParser
150
+ location = advance.location
151
+ extended_only!(location, "expect-rr declarations")
152
+ AST::ExpectRR.new(conflicts: token_integer(expect(:integer)), loc: location)
153
+ end
154
+
155
+ # @rbs () -> AST::Parameter
156
+ def parse_parameter
157
+ # @type self: BootstrapParser
158
+ keyword = advance
159
+ extended_only!(keyword.location, "%param")
160
+ name = expect(:identifier)
161
+ type = current.type == :literal ? advance : nil
162
+ if type && (keyword.location.line != name.location.line || name.location.line != type.location.line)
163
+ fail_at(keyword.location, "%param declaration must be written on one line")
164
+ end
165
+
166
+ semantic_type = type && decode_quoted_literal(type, "%param")
167
+ AST::Parameter.new(name: token_string(name), semantic_type: semantic_type, loc: keyword.location)
168
+ end
169
+
170
+ # @rbs () -> AST::Printer
171
+ def parse_printer
172
+ # @type self: BootstrapParser
173
+ keyword = advance
174
+ extended_only!(keyword.location, "%printer")
175
+ name = parse_symbol_name
176
+ action = expect(:action)
177
+ AST::Printer.new(name: name, code: token_string(action), loc: keyword.location)
178
+ end
179
+
105
180
  # @rbs () -> AST::Start
106
181
  def parse_start
107
182
  # @type self: BootstrapParser
108
183
  location = advance.location
109
- AST::Start.new(name: parse_symbol_name, loc: location)
184
+ names = [parse_symbol_name]
185
+ names << parse_symbol_name until declaration_start?
186
+ extended_only!(location, "multiple start symbols") if names.length > 1
187
+ AST::Start.new(names: names, loc: location)
188
+ end
189
+
190
+ # @rbs () -> AST::Recovery
191
+ def parse_recovery
192
+ # @type self: BootstrapParser
193
+ keyword = advance
194
+ extended_only!(keyword.location, "%recover")
195
+ kind = expect(:identifier)
196
+ fail_at(kind.location, "expected sync, got #{kind.value}") unless token_string(kind) == "sync"
197
+ expect(:":")
198
+ tokens = [parse_symbol_name]
199
+ tokens << parse_symbol_name until declaration_start?
200
+ AST::Recovery.new(sync_tokens: tokens, loc: keyword.location)
201
+ end
202
+
203
+ # @rbs () -> AST::OnErrorReduce
204
+ def parse_on_error_reduce
205
+ # @type self: BootstrapParser
206
+ keyword = advance
207
+ extended_only!(keyword.location, "%on_error_reduce")
208
+ names = [parse_symbol_name]
209
+ names << parse_symbol_name until declaration_start?
210
+ AST::OnErrorReduce.new(names: names, loc: keyword.location)
211
+ end
212
+
213
+ # @rbs () -> AST::GrammarTest
214
+ def parse_grammar_test
215
+ # @type self: BootstrapParser
216
+ keyword = advance
217
+ extended_only!(keyword.location, "%test")
218
+ expectation = token_string(expect(:identifier))
219
+ fail_at(keyword.location, "expected accept or reject, got #{expectation}") unless
220
+ %w[accept reject].include?(expectation)
221
+ source = expect(:literal)
222
+ literal = token_string(source)
223
+ fail_at(source.location, "%test source must use a double-quoted string") unless literal.start_with?('"')
224
+ decoded = begin
225
+ literal.undump
226
+ rescue RuntimeError => e
227
+ fail_at(source.location, "invalid %test source: #{e.message}")
228
+ end
229
+
230
+ AST::GrammarTest.new(expectation: expectation.to_sym, source: decoded, loc: keyword.location)
231
+ end
232
+
233
+ # @rbs () -> AST::Lexer
234
+ def parse_lexer
235
+ # @type self: BootstrapParser
236
+ keyword = advance
237
+ extended_only!(keyword.location, "lexer declarations")
238
+ entries = parse_lexer_entries
239
+ expect_keyword("end")
240
+ AST::Lexer.new(definitions: entries, loc: keyword.location)
241
+ end
242
+
243
+ # @rbs () -> Array[AST::lexer_entry]
244
+ def parse_lexer_entries
245
+ # @type self: BootstrapParser
246
+ entries = [] #: Array[AST::lexer_entry]
247
+ entries << parse_lexer_entry until keyword?("end") || current.type == :eof
248
+ entries
249
+ end
250
+
251
+ # @rbs () -> AST::lexer_entry
252
+ def parse_lexer_entry
253
+ # @type self: BootstrapParser
254
+ return parse_lexer_state if keyword?("state")
255
+
256
+ marker = expect(:identifier)
257
+ kind = case token_string(marker)
258
+ when "skip" then :skip
259
+ when "on" then :on
260
+ else :token
261
+ end
262
+ pattern = expect_lexer_pattern
263
+ action = current.type == :action ? advance : nil
264
+ fail_at(marker.location, "on lexer rules require an action") if kind == :on && !action
265
+ build_bootstrap_lexer_rule(kind, marker, pattern, action)
266
+ end
267
+
268
+ # @rbs () -> AST::LexerState
269
+ def parse_lexer_state
270
+ # @type self: BootstrapParser
271
+ marker = advance
272
+ name = expect(:identifier)
273
+ expect_keyword("do")
274
+ entries = parse_lexer_entries
275
+ expect_keyword("end")
276
+ AST::LexerState.new(name: token_string(name), definitions: entries, loc: marker.location)
277
+ end
278
+
279
+ # @rbs () -> Token
280
+ def expect_lexer_pattern
281
+ # @type self: BootstrapParser
282
+ return advance if %i[regexp literal].include?(current.type)
283
+
284
+ fail_expected("a regular expression or quoted literal")
285
+ end
286
+
287
+ # @rbs (Symbol kind, Token marker, Token pattern, Token? action) -> AST::LexerRule
288
+ def build_bootstrap_lexer_rule(kind, marker, pattern, action)
289
+ # @type self: BootstrapParser
290
+ token = kind == :token ? token_string(marker) : nil
291
+ AST::LexerRule.new(kind: kind, token: token, pattern: token_string(pattern),
292
+ pattern_kind: pattern.type, action: action && token_string(action), loc: marker.location)
110
293
  end
111
294
 
112
295
  # @rbs () -> AST::Convert
@@ -124,6 +307,27 @@ module Ibex
124
307
  AST::Convert.new(pairs: pairs, loc: location)
125
308
  end
126
309
 
310
+ # @rbs (singleton(AST::DisplayName) | singleton(AST::SemanticType) node_class, String feature) ->
311
+ # (AST::DisplayName | AST::SemanticType)
312
+ def parse_symbol_metadata(node_class, feature)
313
+ # @type self: BootstrapParser
314
+ keyword = advance
315
+ extended_only!(keyword.location, "#{feature} declarations")
316
+ name = expect_symbol
317
+ value = expect_metadata_value
318
+ validate_metadata_line(keyword, name, value, feature)
319
+ decoded = decode_quoted_literal(value, feature)
320
+ node_class.new(name: token_string(name), value: decoded, loc: keyword.location)
321
+ end
322
+
323
+ # @rbs () -> Token
324
+ def expect_metadata_value
325
+ # @type self: BootstrapParser
326
+ return advance if current.type == :literal
327
+
328
+ fail_expected("a quoted string")
329
+ end
330
+
127
331
  # @rbs (Integer line) -> Array[Token]
128
332
  def tokens_on_line(line)
129
333
  # @type self: BootstrapParser
@@ -147,10 +351,41 @@ module Ibex
147
351
  fail_at(location, "invalid conversion expression: #{e.message}")
148
352
  end
149
353
 
354
+ # @rbs (Token keyword, Token name, Token value, String feature) -> void
355
+ def validate_metadata_line(keyword, name, value, feature)
356
+ # @type self: BootstrapParser
357
+ return if keyword.location.line == name.location.line && name.location.line == value.location.line
358
+
359
+ fail_at(keyword.location, "#{feature} declaration must be written on one line")
360
+ end
361
+
362
+ # @rbs (Token token, String feature) -> String
363
+ def decode_quoted_literal(token, feature)
364
+ # @type self: BootstrapParser
365
+ literal = token_string(token)
366
+ decoded = if literal.start_with?('"')
367
+ literal.undump
368
+ else
369
+ (literal[1...-1] || "").gsub("\\'", "'").gsub("\\\\", "\\")
370
+ end
371
+ fail_at(token.location, "#{feature} value must not be empty") if decoded.strip.empty?
372
+ fail_at(token.location, "#{feature} value must be a single line") if decoded.match?(/[\r\n]/)
373
+ fail_at(token.location, "#{feature} value must not contain control characters") if
374
+ decoded.match?(/[[:cntrl:]]/)
375
+
376
+ decoded
377
+ rescue RuntimeError => e
378
+ fail_at(token.location, "invalid #{feature} value: #{e.message}")
379
+ end
380
+
150
381
  # @rbs () -> bool
151
382
  def declaration_start?
152
383
  # @type self: BootstrapParser
153
- current.type == :eof || (current.type == :identifier && DECLARATIONS.include?(current.value))
384
+ return true if current.type == :eof
385
+ return false unless current.type == :identifier && DECLARATIONS.include?(current.value)
386
+ return false if %w[display type param printer lexer].include?(current.value) && @mode != :extended
387
+
388
+ true
154
389
  end
155
390
 
156
391
  # @rbs () -> bool
@@ -159,5 +394,6 @@ module Ibex
159
394
  current.type == :identifier && ASSOCIATIVITIES.include?(current.value)
160
395
  end
161
396
  end
397
+ # rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
162
398
  end
163
399
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module Frontend
5
+ # Parses extended-mode parameter lists and parameterized references during bootstrap.
6
+ module BootstrapParserParameters
7
+ private
8
+
9
+ # @rbs (Token lhs) -> Array[String]
10
+ def parse_rule_parameters(lhs)
11
+ # @type self: BootstrapParser
12
+ return [] unless current.type == :"(" && adjacent_tokens?(lhs, current)
13
+
14
+ opening = advance
15
+ extended_only!(opening.location, "parameterized rules")
16
+ parameters = [token_string(expect(:identifier))]
17
+ parameters << token_string(expect(:identifier)) while accept(:",")
18
+ expect(:")")
19
+ parameters
20
+ end
21
+
22
+ # @rbs () -> AST::item
23
+ def parse_parameterized_reference
24
+ # @type self: BootstrapParser
25
+ callee = advance
26
+ opening = expect(:"(")
27
+ extended_only!(opening.location, "parameterized rules")
28
+ arguments = [] #: Array[AST::item]
29
+ unless current.type == :")"
30
+ loop do
31
+ fail_at(current.location, "actions are not valid parameter arguments") if current.type == :action
32
+
33
+ arguments << parse_item
34
+ break unless accept(:",")
35
+ end
36
+ end
37
+ expect(:")")
38
+ item = AST::ParameterizedReference.new(
39
+ name: token_string(callee), arguments: arguments, named_reference: parse_named_reference, loc: callee.location
40
+ )
41
+ parse_suffix(item)
42
+ end
43
+
44
+ # @rbs () -> bool
45
+ def parameterized_call?
46
+ # @type self: BootstrapParser
47
+ current.type == :identifier && lookahead.type == :"(" && adjacent_tokens?(current, lookahead)
48
+ end
49
+
50
+ # @rbs () -> bool
51
+ def parameterized_rule_start?
52
+ # @type self: BootstrapParser
53
+ opening = lookahead
54
+ return false unless opening.type == :"(" && adjacent_tokens?(current, opening)
55
+
56
+ parameter_definition_tail?(@tokens.drop(@index + 2))
57
+ end
58
+
59
+ # @rbs (Array[Token] tail) -> bool
60
+ def parameter_definition_tail?(tail)
61
+ # @type self: BootstrapParser
62
+ closing = tail.index { |token| token.type == :")" }
63
+ return false unless closing && tail[closing + 1]&.type == :":"
64
+
65
+ formals = tail.take(closing)
66
+ !formals.empty? && formals.length.odd? &&
67
+ formals.each_with_index.all? { |token, index| token.type == (index.even? ? :identifier : :",") }
68
+ end
69
+
70
+ # @rbs (Token left, Token right) -> bool
71
+ def adjacent_tokens?(left, right)
72
+ # @type self: BootstrapParser
73
+ left_span = left.span
74
+ right_span = right.span
75
+ return left_span.end_byte == right_span.start_byte if left_span && right_span
76
+
77
+ left.location.line == right.location.line &&
78
+ left.location.column + token_string(left).length == right.location.column
79
+ end
80
+ end
81
+ end
82
+ end
@@ -14,7 +14,7 @@ module Ibex
14
14
  def parse_rules
15
15
  # @type self: BootstrapParser
16
16
  rules = [] #: Array[AST::Rule]
17
- rules << parse_rule until keyword?("end") || current.type == :eof
17
+ rules << parse_rule until keyword?("end") || %i[eof user_code].include?(current.type)
18
18
  fail_expected("at least one rule") if rules.empty?
19
19
  rules
20
20
  end
@@ -22,7 +22,10 @@ module Ibex
22
22
  # @rbs () -> AST::Rule
23
23
  def parse_rule
24
24
  # @type self: BootstrapParser
25
+ inline = accept(:inline)
26
+ extended_only!(inline.location, "inline rules") if inline
25
27
  lhs = expect(:identifier)
28
+ parameters = parse_rule_parameters(lhs)
26
29
  expect(:":")
27
30
  alternatives = [] #: Array[AST::Alternative]
28
31
  loop do
@@ -32,7 +35,10 @@ module Ibex
32
35
  accept(:";")
33
36
  break
34
37
  end
35
- AST::Rule.new(lhs: token_string(lhs), alternatives: alternatives, loc: lhs.location)
38
+ AST::Rule.new(
39
+ lhs: token_string(lhs), parameters: parameters, alternatives: alternatives, loc: lhs.location,
40
+ inline: !!inline
41
+ )
36
42
  end
37
43
 
38
44
  # @rbs (Token lhs) -> AST::Alternative
@@ -54,14 +60,42 @@ module Ibex
54
60
  items.pop
55
61
  action = last_item
56
62
  end
57
- AST::Alternative.new(items: items, action: action, precedence: precedence, loc: location)
63
+ node_annotation = parse_node_annotation
64
+ AST::Alternative.new(
65
+ items: items, action: action, precedence: precedence, node_annotation: node_annotation, loc: location
66
+ )
67
+ end
68
+
69
+ # @rbs () -> AST::NodeAnnotation?
70
+ def parse_node_annotation
71
+ # @type self: BootstrapParser
72
+ marker = accept(:node)
73
+ return unless marker
74
+
75
+ extended_only!(marker.location, "@node")
76
+ name = expect(:identifier)
77
+ expect(:"(")
78
+ fields = [] #: Array[String]
79
+ unless current.type == :")"
80
+ fields << token_string(expect(:identifier))
81
+ fields << token_string(expect(:identifier)) while accept(:",")
82
+ end
83
+ expect(:")")
84
+ AST::NodeAnnotation.new(name: token_string(name), fields: fields, loc: marker.location)
58
85
  end
59
86
 
60
87
  # @rbs () -> AST::item
61
88
  def parse_item
62
89
  # @type self: BootstrapParser
63
90
  return parse_action if current.type == :action
91
+
92
+ if current.type == :empty
93
+ token = advance
94
+ extended_only!(token.location, "%empty")
95
+ return AST::Empty.new(loc: token.location)
96
+ end
64
97
  return parse_separated_list if separated_list?
98
+ return parse_parameterized_reference if parameterized_call?
65
99
  return parse_group if current.type == :"("
66
100
 
67
101
  token = expect_symbol
@@ -105,7 +139,7 @@ module Ibex
105
139
  extended_only!(opening.location, "EBNF groups")
106
140
  alternatives = [[]] #: Array[Array[AST::item]]
107
141
  until current.type == :")"
108
- fail_at(opening.location, "unterminated EBNF group") if current.type == :eof || keyword?("end")
142
+ fail_at(opening.location, "unterminated EBNF group") if current.type == :eof
109
143
  if accept(:|)
110
144
  alternatives << []
111
145
  next
@@ -135,13 +169,16 @@ module Ibex
135
169
  # @rbs (Token lhs) -> bool
136
170
  def alternative_end?(lhs)
137
171
  # @type self: BootstrapParser
138
- %i[| ; eof].include?(current.type) || keyword?("end") || rule_start?(lhs)
172
+ %i[| ; inline node eof user_code].include?(current.type) || keyword?("end") || rule_start?(lhs)
139
173
  end
140
174
 
141
175
  # @rbs (Token lhs) -> bool
142
176
  def rule_start?(lhs)
143
177
  # @type self: BootstrapParser
144
- current.type == :identifier && lookahead.type == :":" && current.location.column <= lhs.location.column
178
+ return false unless current.type == :identifier && current.location.column <= lhs.location.column
179
+ return true if lookahead.type == :":"
180
+
181
+ parameterized_rule_start?
145
182
  end
146
183
 
147
184
  # @rbs () -> bool