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,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Structural, sharing-preserving substitution for parameterized user rules.
5
+ module NormalizeParameterSubstitution
6
+ private
7
+
8
+ # @rbs (Frontend::AST::Alternative alternative, Hash[String, Frontend::AST::item] bindings) ->
9
+ # Frontend::AST::Alternative
10
+ def substitute_parameter_alternative(alternative, bindings)
11
+ # @type self: Normalizer
12
+ Frontend::AST::Alternative.new(
13
+ items: alternative.items.map { |item| substitute_parameter_item(item, bindings) },
14
+ action: alternative.action, precedence: substitute_parameter_precedence(alternative, bindings),
15
+ node_annotation: alternative.node_annotation, loc: alternative.loc
16
+ )
17
+ end
18
+
19
+ # @rbs (Frontend::AST::Alternative alternative, Hash[String, Frontend::AST::item] bindings) -> String?
20
+ def substitute_parameter_precedence(alternative, bindings)
21
+ # @type self: Normalizer
22
+ precedence = alternative.precedence
23
+ return precedence unless precedence && bindings.key?(precedence)
24
+
25
+ argument = bindings.fetch(precedence)
26
+ unless argument.is_a?(Frontend::AST::SymbolReference) && !argument.named_reference
27
+ fail_at(alternative.loc, "formal precedence #{precedence} requires one plain symbol argument")
28
+ end
29
+ argument.name
30
+ end
31
+
32
+ # @rbs (Frontend::AST::item item, Hash[String, Frontend::AST::item] bindings) -> Frontend::AST::item
33
+ def substitute_parameter_item(item, bindings)
34
+ # @type self: Normalizer
35
+ if item.is_a?(Frontend::AST::SymbolReference) && bindings.key?(item.name)
36
+ return substitute_formal_reference(item, bindings.fetch(item.name))
37
+ end
38
+
39
+ clone_parameter_item(item, bindings)
40
+ end
41
+
42
+ # @rbs (Frontend::AST::SymbolReference formal, Frontend::AST::item argument) -> Frontend::AST::item
43
+ def substitute_formal_reference(formal, argument)
44
+ # @type self: Normalizer
45
+ name = formal.named_reference
46
+ return argument unless name
47
+
48
+ case argument
49
+ when Frontend::AST::SymbolReference
50
+ Frontend::AST::SymbolReference.new(name: argument.name, named_reference: name, loc: argument.loc)
51
+ when Frontend::AST::ParameterizedReference
52
+ Frontend::AST::ParameterizedReference.new(
53
+ name: argument.name, arguments: argument.arguments, named_reference: name, loc: argument.loc
54
+ )
55
+ else
56
+ fail_at(formal.loc, "named formal #{formal.name} requires a plain symbol or parameterized argument")
57
+ end
58
+ end
59
+
60
+ # @rbs (Frontend::AST::item item, ?Hash[String, Frontend::AST::item] bindings) -> Frontend::AST::item
61
+ def clone_parameter_item(item, bindings = {})
62
+ # @type self: Normalizer
63
+ case item
64
+ when Frontend::AST::SymbolReference
65
+ clone_parameter_symbol(item, bindings)
66
+ when Frontend::AST::ParameterizedReference
67
+ clone_parameter_call(item, bindings)
68
+ when Frontend::AST::Group
69
+ clone_parameter_group(item, bindings)
70
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
71
+ clone_parameter_suffix(item, bindings)
72
+ when Frontend::AST::SeparatedList
73
+ clone_parameter_separated_list(item, bindings)
74
+ else
75
+ item
76
+ end
77
+ end
78
+
79
+ # @rbs (Frontend::AST::SymbolReference item, Hash[String, Frontend::AST::item] bindings) -> Frontend::AST::item
80
+ def clone_parameter_symbol(item, bindings)
81
+ # @type self: Normalizer
82
+ return substitute_parameter_item(item, bindings) if bindings.key?(item.name)
83
+
84
+ Frontend::AST::SymbolReference.new(name: item.name, named_reference: item.named_reference, loc: item.loc)
85
+ end
86
+
87
+ # @rbs (Frontend::AST::ParameterizedReference item, Hash[String, Frontend::AST::item] bindings) ->
88
+ # Frontend::AST::ParameterizedReference
89
+ def clone_parameter_call(item, bindings)
90
+ # @type self: Normalizer
91
+ fail_at(item.loc, "formal #{item.name} cannot be used as a parameterized rule name") if bindings.key?(item.name)
92
+ Frontend::AST::ParameterizedReference.new(
93
+ name: item.name, arguments: item.arguments.map { |argument| substitute_parameter_item(argument, bindings) },
94
+ named_reference: item.named_reference, loc: item.loc
95
+ )
96
+ end
97
+
98
+ # @rbs (Frontend::AST::Group item, Hash[String, Frontend::AST::item] bindings) -> Frontend::AST::Group
99
+ def clone_parameter_group(item, bindings)
100
+ # @type self: Normalizer
101
+ alternatives = item.alternatives.map do |items|
102
+ items.map { |child| substitute_parameter_item(child, bindings) }
103
+ end
104
+ Frontend::AST::Group.new(alternatives: alternatives, loc: item.loc)
105
+ end
106
+
107
+ # @rbs (Frontend::AST::Optional | Frontend::AST::Star | Frontend::AST::Plus item,
108
+ # Hash[String, Frontend::AST::item] bindings) -> Frontend::AST::item
109
+ def clone_parameter_suffix(item, bindings)
110
+ # @type self: Normalizer
111
+ item.class.new(item: substitute_parameter_item(item.item, bindings), loc: item.loc)
112
+ end
113
+
114
+ # @rbs (Frontend::AST::SeparatedList item, Hash[String, Frontend::AST::item] bindings) ->
115
+ # Frontend::AST::SeparatedList
116
+ def clone_parameter_separated_list(item, bindings)
117
+ # @type self: Normalizer
118
+ Frontend::AST::SeparatedList.new(
119
+ item: substitute_parameter_item(item.item, bindings),
120
+ separator: substitute_parameter_item(item.separator, bindings),
121
+ nonempty: item.nonempty, loc: item.loc
122
+ )
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Static validation and collection of parameterized user rule definitions.
5
+ module NormalizeParameterValidation
6
+ private
7
+
8
+ # @rbs () -> void
9
+ def gather_parameter_templates
10
+ # @type self: Normalizer
11
+ @parameter_templates = {} #: Hash[String, Array[Frontend::AST::Rule]]
12
+ @parameter_formals = {} #: Hash[String, Array[String]]
13
+ plain_rules = {} #: Hash[String, Frontend::AST::Rule]
14
+ @rule_documentation = validated_rule_documentation
15
+
16
+ @ast.rules.each do |rule|
17
+ if parameterized_rule?(rule)
18
+ gather_parameterized_rule(rule, plain_rules)
19
+ else
20
+ reject_mixed_parameterized_rule(rule) if @parameter_templates.key?(rule.lhs)
21
+ plain_rules[rule.lhs] ||= rule
22
+ end
23
+ end
24
+ validate_parameter_terminal_collisions
25
+ @ast.rules.each { |rule| validate_parameter_references(rule) }
26
+ end
27
+
28
+ # @rbs (Frontend::AST::Rule rule, Hash[String, Frontend::AST::Rule] plain_rules) -> void
29
+ def gather_parameterized_rule(rule, plain_rules)
30
+ # @type self: Normalizer
31
+ reject_mixed_parameterized_rule(rule) if plain_rules.key?(rule.lhs)
32
+ duplicate = rule.parameters.tally.find { |_name, count| count > 1 }&.first
33
+ fail_at(rule.loc, "duplicate parameter #{duplicate} in rule #{rule.lhs}") if duplicate
34
+
35
+ validate_parameter_formals(rule)
36
+ @parameter_formals[rule.lhs] ||= rule.parameters
37
+ (@parameter_templates[rule.lhs] ||= Array.new(0)) << rule
38
+ end
39
+
40
+ # @rbs (Frontend::AST::Rule rule) -> void
41
+ def validate_parameter_formals(rule)
42
+ # @type self: Normalizer
43
+ expected = @parameter_formals[rule.lhs]
44
+ return unless expected && expected != rule.parameters
45
+
46
+ fail_at(
47
+ rule.loc,
48
+ "parameterized rule #{rule.lhs} uses inconsistent parameters " \
49
+ "(expected #{expected.join(', ')}, got #{rule.parameters.join(', ')})"
50
+ )
51
+ end
52
+
53
+ # @rbs (Frontend::AST::Rule rule) -> bot
54
+ def reject_mixed_parameterized_rule(rule)
55
+ # @type self: Normalizer
56
+ fail_at(rule.loc, "rule #{rule.lhs} has both plain and parameterized definitions")
57
+ end
58
+
59
+ # @rbs () -> void
60
+ def validate_parameter_terminal_collisions
61
+ # @type self: Normalizer
62
+ @parameter_templates.each do |name, rules|
63
+ next unless @declared_tokens.key?(name) || @precedence.key?(name)
64
+
65
+ fail_at(rules.fetch(0).loc, "parameterized rule #{name} collides with terminal #{name}")
66
+ end
67
+ end
68
+
69
+ # @rbs (Frontend::AST::Rule rule) -> void
70
+ def validate_parameter_references(rule)
71
+ # @type self: Normalizer
72
+ rule.alternatives.each do |alternative|
73
+ alternative.items.each do |item|
74
+ validate_parameter_item(item, rule.parameters, inside_argument: false)
75
+ end
76
+ end
77
+ end
78
+
79
+ # @rbs (Frontend::AST::item item, Array[String] formals, inside_argument: bool) -> void
80
+ def validate_parameter_item(item, formals, inside_argument:)
81
+ # @type self: Normalizer
82
+ case item
83
+ when Frontend::AST::ParameterizedReference
84
+ validate_parameterized_item(item, formals, inside_argument: inside_argument)
85
+ when Frontend::AST::SymbolReference
86
+ reject_argument_named_reference(item) if inside_argument && item.named_reference
87
+ when Frontend::AST::Group
88
+ item.alternatives.flatten.each do |child|
89
+ validate_parameter_item(child, formals, inside_argument: inside_argument)
90
+ end
91
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus
92
+ validate_parameter_item(item.item, formals, inside_argument: inside_argument)
93
+ when Frontend::AST::SeparatedList
94
+ validate_parameter_item(item.item, formals, inside_argument: inside_argument)
95
+ validate_parameter_item(item.separator, formals, inside_argument: inside_argument)
96
+ end
97
+ end
98
+
99
+ # @rbs (Frontend::AST::ParameterizedReference item, Array[String] formals, inside_argument: bool) -> void
100
+ def validate_parameterized_item(item, formals, inside_argument:)
101
+ # @type self: Normalizer
102
+ if formals.include?(item.name)
103
+ fail_at(item.loc, "formal #{item.name} cannot be used as a parameterized rule name")
104
+ end
105
+ validate_parameter_call(item)
106
+ reject_argument_named_reference(item) if inside_argument && item.named_reference
107
+ item.arguments.each { |argument| validate_parameter_item(argument, formals, inside_argument: true) }
108
+ end
109
+
110
+ # @rbs (Frontend::AST::SymbolReference | Frontend::AST::ParameterizedReference item) -> bot
111
+ def reject_argument_named_reference(item)
112
+ # @type self: Normalizer
113
+ fail_at(item.loc, "named references are not allowed in parameter arguments")
114
+ end
115
+
116
+ # @rbs (Frontend::AST::ParameterizedReference reference) -> void
117
+ def validate_parameter_call(reference)
118
+ # @type self: Normalizer
119
+ formals = @parameter_formals[reference.name]
120
+ fail_at(reference.loc, "undefined parameterized rule #{reference.name}") unless formals
121
+ return if reference.arguments.length == formals.length
122
+
123
+ fail_at(
124
+ reference.loc,
125
+ "parameterized rule #{reference.name} expects #{formals.length} arguments, " \
126
+ "got #{reference.arguments.length}"
127
+ )
128
+ end
129
+
130
+ # @rbs (Frontend::AST::Rule rule) -> bool
131
+ def parameterized_rule?(rule)
132
+ !rule.parameters.empty?
133
+ end
134
+
135
+ # @rbs (String name) -> bool
136
+ def parameter_template?(name)
137
+ @parameter_templates.key?(name)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Iterative, hygienic specialization of validated parameterized user rules.
5
+ module NormalizeParameters
6
+ private
7
+
8
+ # @rbs (Frontend::AST::ParameterizedReference reference) -> String
9
+ def specialize_parameterized_reference(reference)
10
+ # @type self: Normalizer
11
+ helper, scheduled = schedule_parameter_specialization(reference)
12
+ if scheduled && @parameter_worklist_active
13
+ raise Ibex::Error, "#{reference.loc}: internal parameter worklist ordering failure"
14
+ end
15
+
16
+ drain_parameter_worklist unless @parameter_worklist_active
17
+ helper
18
+ end
19
+
20
+ # @rbs (Frontend::AST::ParameterizedReference reference) -> [String, bool]
21
+ def schedule_parameter_specialization(reference)
22
+ # @type self: Normalizer
23
+ arguments = reference.arguments
24
+ rendered_arguments = arguments.map { |argument| NormalizeExpression.render(argument) }
25
+ key = [reference.name, rendered_arguments] #: [String, Array[String]]
26
+ existing = @parameter_specializations[key]
27
+ return [existing, false] if existing
28
+
29
+ enforce_parameter_limits!(reference)
30
+ helper = new_parameter_helper(reference)
31
+ @parameter_specializations[key] = helper
32
+ @parameter_worklist << parameter_frame(reference, helper, arguments, rendered_arguments)
33
+ [helper, true]
34
+ end
35
+
36
+ # @rbs (Frontend::AST::ParameterizedReference reference) -> void
37
+ def enforce_parameter_limits!(reference)
38
+ # @type self: Normalizer
39
+ cyclic = @parameter_worklist.reverse.find do |frame|
40
+ frame.fetch(:reference).name == reference.name &&
41
+ growing_parameter_arguments?(reference.arguments, frame.fetch(:arguments))
42
+ end
43
+ if cyclic
44
+ path = (@parameter_worklist.drop_while { |frame| frame != cyclic } + [{ reference: reference }])
45
+ .map { |frame| frame.fetch(:reference).name }
46
+ fail_at(reference.loc, "cyclic parameter specialization #{path.join(' -> ')}")
47
+ end
48
+ return unless @parameter_specializations.length >= @max_parameter_specializations
49
+
50
+ fail_at(
51
+ reference.loc,
52
+ "parameter specialization limit of #{@max_parameter_specializations} exceeded"
53
+ )
54
+ end
55
+
56
+ # A constructor-growing recursive call can create infinitely many distinct
57
+ # specializations. Calls whose arguments shrink or merely change are
58
+ # allowed; they may reach a memoized fixed point after finite expansion.
59
+ # @rbs (Array[Frontend::AST::item] candidates, Array[Frontend::AST::item] ancestors) -> bool
60
+ def growing_parameter_arguments?(candidates, ancestors)
61
+ return false unless candidates.length == ancestors.length
62
+
63
+ contained = candidates.each_index.all? do |index|
64
+ candidate = candidates.fetch(index)
65
+ ancestor = ancestors.fetch(index)
66
+ parameter_argument_contains?(candidate, NormalizeExpression.render(ancestor))
67
+ end
68
+ contained && candidates.each_index.any? do |index|
69
+ candidate = candidates.fetch(index)
70
+ ancestor = ancestors.fetch(index)
71
+ NormalizeExpression.render(candidate) != NormalizeExpression.render(ancestor)
72
+ end
73
+ end
74
+
75
+ # @rbs (Frontend::AST::item candidate, String target) -> bool
76
+ def parameter_argument_contains?(candidate, target)
77
+ pending = [candidate] #: Array[Frontend::AST::item]
78
+ until pending.empty?
79
+ item = pending.pop
80
+ raise Ibex::Error, "missing parameter argument" unless item
81
+
82
+ return true if NormalizeExpression.render(item) == target
83
+
84
+ case item
85
+ when Frontend::AST::ParameterizedReference then pending.concat(item.arguments)
86
+ when Frontend::AST::Group then item.alternatives.each { |alternative| pending.concat(alternative) }
87
+ when Frontend::AST::Optional, Frontend::AST::Star, Frontend::AST::Plus then pending << item.item
88
+ when Frontend::AST::SeparatedList then pending.push(item.item, item.separator)
89
+ end
90
+ end
91
+ false
92
+ end
93
+
94
+ # @rbs (Frontend::AST::ParameterizedReference reference) -> String
95
+ def new_parameter_helper(reference)
96
+ # @type self: Normalizer
97
+ @helper_sequence += 1
98
+ name = "$parameter_#{@helper_sequence}"
99
+ definition = intern(
100
+ name, :nonterminal,
101
+ location: reference.loc.to_h,
102
+ documentation: @rule_documentation[reference.name],
103
+ metadata_name: reference.name
104
+ )
105
+ if @inline_rule_names.include?(reference.name)
106
+ @inline_symbol_ids << definition.id
107
+ @inline_rule_by_symbol[definition.id] = reference.name
108
+ end
109
+ name
110
+ end
111
+
112
+ # @rbs (Frontend::AST::ParameterizedReference reference, String helper,
113
+ # Array[Frontend::AST::item] arguments, Array[String] rendered_arguments) ->
114
+ # Hash[Symbol, untyped]
115
+ def parameter_frame(reference, helper, arguments, rendered_arguments)
116
+ # @type self: Normalizer
117
+ formals = @parameter_formals.fetch(reference.name)
118
+ {
119
+ reference: reference,
120
+ arguments: arguments,
121
+ helper: helper,
122
+ bindings: formals.zip(arguments).to_h,
123
+ rendered_arguments: rendered_arguments,
124
+ templates: @parameter_templates.fetch(reference.name),
125
+ template_index: 0,
126
+ alternative_index: 0,
127
+ current: nil,
128
+ item_index: 0,
129
+ rhs: [],
130
+ named_refs: [],
131
+ operations: [],
132
+ values: []
133
+ }
134
+ end
135
+
136
+ # @rbs () -> void
137
+ def drain_parameter_worklist
138
+ # @type self: Normalizer
139
+ @parameter_worklist_active = true
140
+ until @parameter_worklist.empty?
141
+ frame = @parameter_worklist.last
142
+ unless frame[:current] || prepare_parameter_alternative?(frame)
143
+ @parameter_worklist.pop
144
+ next
145
+ end
146
+
147
+ advance_parameter_alternative(frame)
148
+ end
149
+ ensure
150
+ @parameter_worklist_active = false
151
+ end
152
+
153
+ # @rbs (Hash[Symbol, untyped] frame) -> bool
154
+ def prepare_parameter_alternative?(frame)
155
+ # @type self: Normalizer
156
+ templates = frame.fetch(:templates)
157
+ while frame.fetch(:template_index) < templates.length
158
+ template = templates.fetch(frame.fetch(:template_index))
159
+ index = frame.fetch(:alternative_index)
160
+ if index < template.alternatives.length
161
+ prepare_parameter_alternative_entry(frame, template, index)
162
+ return true
163
+ end
164
+ frame[:template_index] += 1
165
+ frame[:alternative_index] = 0
166
+ end
167
+ false
168
+ end
169
+
170
+ # @rbs (Hash[Symbol, untyped] frame, Frontend::AST::Rule template, Integer index) -> void
171
+ def prepare_parameter_alternative_entry(frame, template, index)
172
+ # @type self: Normalizer
173
+ alternative = substitute_parameter_alternative(
174
+ template.alternatives.fetch(index), frame.fetch(:bindings)
175
+ )
176
+ rule = Frontend::AST::Rule.new(
177
+ lhs: frame.fetch(:helper), parameters: [], alternatives: [alternative], loc: template.loc,
178
+ documentation: template.documentation, inline: false
179
+ )
180
+ frame[:alternative_index] = index + 1
181
+ frame[:current] = [template, rule, alternative]
182
+ frame[:item_index] = 0
183
+ frame[:rhs] = []
184
+ frame[:named_refs] = []
185
+ frame[:operations] = []
186
+ frame[:values] = []
187
+ end
188
+
189
+ # @rbs (Hash[Symbol, untyped] frame) -> void
190
+ def clear_parameter_alternative(frame)
191
+ frame[:current] = nil
192
+ frame[:item_index] = 0
193
+ frame[:rhs] = []
194
+ frame[:named_refs] = []
195
+ frame[:operations] = []
196
+ frame[:values] = []
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ # Recovery declaration extraction and post-interning symbol validation.
5
+ module NormalizeRecoveryDeclarations
6
+ private
7
+
8
+ # @rbs (Frontend::AST::Start | Frontend::AST::Recovery | Frontend::AST::OnErrorReduce |
9
+ # Frontend::AST::GrammarTest declaration) -> void
10
+ def read_parser_control_declaration(declaration)
11
+ # @type self: Normalizer
12
+ case declaration
13
+ when Frontend::AST::Start then read_start_declaration(declaration)
14
+ when Frontend::AST::Recovery then read_recovery_declaration(declaration)
15
+ when Frontend::AST::OnErrorReduce then read_on_error_reduce_declaration(declaration)
16
+ when Frontend::AST::GrammarTest then read_grammar_test(declaration)
17
+ end
18
+ end
19
+
20
+ # @rbs (Frontend::AST::GrammarTest declaration) -> void
21
+ def read_grammar_test(declaration)
22
+ # @type self: Normalizer
23
+ fail_at(declaration.loc, "%test requires extended mode") unless @mode == :extended
24
+ unless %i[accept reject].include?(declaration.expectation)
25
+ fail_at(declaration.loc, "unknown %test expectation #{declaration.expectation.inspect}")
26
+ end
27
+ if @grammar_tests.any? do |test|
28
+ test[:expectation] == declaration.expectation && test[:source] == declaration.source
29
+ end
30
+ fail_at(declaration.loc, "duplicate %test #{declaration.expectation} source")
31
+ end
32
+
33
+ @grammar_tests << {
34
+ expectation: declaration.expectation,
35
+ source: declaration.source,
36
+ loc: declaration.loc.to_h
37
+ }
38
+ end
39
+
40
+ # @rbs (Frontend::AST::Recovery declaration) -> void
41
+ def read_recovery_declaration(declaration)
42
+ # @type self: Normalizer
43
+ fail_at(declaration.loc, "duplicate %recover declaration") if @recovery_sync_location
44
+ fail_at(declaration.loc, "%recover sync requires at least one token") if declaration.sync_tokens.empty?
45
+ unless declaration.sync_tokens.uniq.length == declaration.sync_tokens.length
46
+ fail_at(declaration.loc, "%recover sync tokens must be unique")
47
+ end
48
+
49
+ @recovery_sync_tokens = declaration.sync_tokens
50
+ @recovery_sync_location = declaration.loc
51
+ end
52
+
53
+ # @rbs (Frontend::AST::OnErrorReduce declaration) -> void
54
+ def read_on_error_reduce_declaration(declaration)
55
+ # @type self: Normalizer
56
+ fail_at(declaration.loc, "%on_error_reduce requires at least one nonterminal") if declaration.names.empty?
57
+ declaration.names.each do |name|
58
+ fail_at(declaration.loc, "duplicate %on_error_reduce symbol #{name}") if
59
+ @on_error_reduce_locations.key?(name)
60
+
61
+ @on_error_reduce_locations[name] = declaration.loc
62
+ end
63
+ @on_error_reduce_groups << declaration.names
64
+ end
65
+
66
+ # @rbs () -> void
67
+ def validate_recovery_declarations
68
+ # @type self: Normalizer
69
+ @recovery_sync_tokens.each do |name|
70
+ definition = @symbols_by_name[name]
71
+ unless definition&.terminal? && definition.name != "error"
72
+ fail_at(@recovery_sync_location || @ast.loc, "%recover sync references nonterminal or missing token #{name}")
73
+ end
74
+ end
75
+ @on_error_reduce_groups.flatten.each do |name|
76
+ definition = @symbols_by_name[name]
77
+ unless definition&.nonterminal?
78
+ location = @on_error_reduce_locations.fetch(name)
79
+ fail_at(location, "%on_error_reduce references terminal or missing nonterminal #{name}")
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end