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,143 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "action_method_source"
5
+ require_relative "ruby_ast"
6
+
7
+ module Ibex
8
+ module Codegen
9
+ # Semantic-action method generation shared by direct and source-mapped
10
+ # Ruby output.
11
+ module RubyActions
12
+ include RubyAST
13
+
14
+ # @rbs @grammar: IR::Grammar
15
+ # @rbs @line_convert: bool
16
+ # @rbs @omit_action_call: bool
17
+ # @rbs @action_method_source: ActionMethodSource?
18
+
19
+ private
20
+
21
+ # @rbs (Array[String] lines) -> void
22
+ def append_actions(lines)
23
+ @grammar.productions.each do |production|
24
+ next unless action_method?(production)
25
+
26
+ if production.node
27
+ source = ast_node_action_source(production)
28
+ source.lines.each { |line| lines << " #{line.rstrip}" }
29
+ lines << ""
30
+ elsif composed_action?(production)
31
+ append_composed_action_method(lines, production)
32
+ elsif production.action && @line_convert
33
+ append_compiled_action_method(lines, production)
34
+ else
35
+ append_action_method(lines, production)
36
+ end
37
+ end
38
+ end
39
+
40
+ # @rbs (Array[String] lines, IR::Production production) -> void
41
+ def append_composed_action_method(lines, production)
42
+ action = production.action || raise(Ibex::Error, "missing composed semantic action")
43
+ plan = action.composition&.dig(:plan) || raise(Ibex::Error, "missing action composition plan")
44
+ steps = plan.fetch(:steps)
45
+ steps.each_with_index do |step, index|
46
+ append_composed_fragment_method(lines, production, step, index) if step[:code]
47
+ end
48
+ append_composed_orchestrator(lines, production, plan)
49
+ end
50
+
51
+ # @rbs (Array[String] lines, IR::Production production, Hash[Symbol, untyped] step, Integer index) -> void
52
+ def append_composed_fragment_method(lines, production, step, index)
53
+ source = action_method_source.composed_fragment_method_source(production, step, index)
54
+ if @line_convert
55
+ location = step.fetch(:loc)
56
+ lines << " class_eval(#{source.dump}, #{location[:file].inspect}, #{location[:line]})"
57
+ elsif action_method_source.column_sensitive?(step.fetch(:code))
58
+ lines << source
59
+ else
60
+ source.lines.each { |line| lines << " #{line.rstrip}" }
61
+ end
62
+ lines << ""
63
+ end
64
+
65
+ # @rbs (IR::Production production, Integer index) -> String
66
+ def composed_fragment_name(production, index)
67
+ action_method_source.composed_fragment_name(production, index)
68
+ end
69
+
70
+ # @rbs (Array[String] lines, IR::Production production, Hash[Symbol, untyped] plan) -> void
71
+ def append_composed_orchestrator(lines, production, plan)
72
+ lines << " private def _ibex_action_#{production.id}" \
73
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location, " \
74
+ "_ibex_lookahead_location)"
75
+ lines << " _ibex_composed_values = val.dup"
76
+ lines << " _ibex_composed_locations = _ibex_locations.dup"
77
+ plan.fetch(:steps).each_with_index do |step, index|
78
+ append_composed_step(lines, production, step, index)
79
+ end
80
+ lines.push(" _ibex_composed_values.last", " end", "")
81
+ end
82
+
83
+ # @rbs (Array[String] lines, IR::Production production, Hash[Symbol, untyped] step, Integer index) -> void
84
+ def append_composed_step(lines, production, step, index)
85
+ inputs = step.fetch(:inputs)
86
+ lines << " _ibex_step_values = _ibex_composed_values.values_at(#{inputs.join(', ')})"
87
+ lines << " _ibex_step_locations = _ibex_composed_locations.values_at(#{inputs.join(', ')})"
88
+ lookahead = step[:lookahead]
89
+ boundary = lookahead ? "_ibex_locations[#{lookahead}]" : "_ibex_lookahead_location"
90
+ lines << " _ibex_step_location = Ibex::Runtime::LocationSpan.for_reduction(" \
91
+ "_ibex_step_locations, lookahead: #{boundary})"
92
+ result = if step[:code]
93
+ stack_inputs = step.fetch(:stack_inputs)
94
+ "#{composed_fragment_name(production, index)}(" \
95
+ "_ibex_step_values, _values + _ibex_composed_values.values_at(#{stack_inputs.join(', ')}), " \
96
+ "_ibex_step_locations, _ibex_location_stack + " \
97
+ "_ibex_composed_locations.values_at(#{stack_inputs.join(', ')}), _ibex_step_location)"
98
+ else
99
+ "_ibex_step_values[0]"
100
+ end
101
+ lines << " _ibex_composed_values << #{result}"
102
+ lines << " _ibex_composed_locations << _ibex_step_location"
103
+ lines << " return _ibex_composed_values.last if @accept_requested || @semantic_error"
104
+ end
105
+
106
+ # @rbs (Array[String] lines, IR::Production production) -> void
107
+ def append_compiled_action_method(lines, production)
108
+ action = production.action || raise(Ibex::Error, "missing semantic action")
109
+ source = action_method_source.compiled_action_method_source(production)
110
+ lines << " class_eval(#{source.dump}, #{action.location[:file].inspect}, #{action.location[:line]})"
111
+ lines << ""
112
+ end
113
+
114
+ # @rbs (Array[String] lines, IR::Production production) -> void
115
+ def append_action_method(lines, production)
116
+ source = action_method_source.direct_action_method_source(production)
117
+ if production.action && action_method_source.column_sensitive?(production.action.code)
118
+ lines << source
119
+ else
120
+ source.lines.each { |line| lines << " #{line.rstrip}" }
121
+ end
122
+ lines << ""
123
+ end
124
+
125
+ # @rbs (IR::Production production) -> bool
126
+ def action_method?(production)
127
+ !!(production.node || production.action || !@omit_action_call)
128
+ end
129
+
130
+ # @rbs (IR::Production production) -> bool
131
+ def composed_action?(production)
132
+ production.action&.composition&.dig(:plan, :version) == 1
133
+ end
134
+
135
+ # @rbs () -> ActionMethodSource
136
+ def action_method_source
137
+ @action_method_source ||= ActionMethodSource.new(
138
+ @grammar, generated_action_abi: @generated_action_abi
139
+ )
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Generates typed AST data classes and traversal bases from @node metadata.
7
+ module RubyAST
8
+ private
9
+
10
+ # @rbs (Array[String] lines) -> void
11
+ def append_ast(lines)
12
+ definitions = ast_node_definitions
13
+ return if definitions.empty?
14
+
15
+ lines << " module AST"
16
+ definitions.each_value do |node|
17
+ members = node.fetch(:fields).map { |field| ":#{field}" }.join(", ")
18
+ lines << " #{node.fetch(:name)} = Ibex::Runtime::ASTData.define(#{members})"
19
+ end
20
+ lines << ""
21
+ append_visitor(lines, definitions)
22
+ lines << ""
23
+ append_listener(lines, definitions)
24
+ lines.push(" end", "")
25
+ end
26
+
27
+ # @rbs () -> Hash[String, IR::node_annotation]
28
+ def ast_node_definitions
29
+ @grammar.productions.filter_map(&:node).to_h { |node| [node.fetch(:name), node] }
30
+ end
31
+
32
+ # @rbs (Array[String] lines, Hash[String, IR::node_annotation] definitions) -> void
33
+ def append_visitor(lines, definitions)
34
+ lines.push(" class Visitor", " def visit(node)", " case node")
35
+ definitions.each_value do |node|
36
+ lines << " when #{node.fetch(:name)} then visit_#{ast_method_name(node.fetch(:name))}(node)"
37
+ end
38
+ lines.push(" else visit_children(node)", " end", " end", "")
39
+ definitions.each_value do |node|
40
+ method = ast_method_name(node.fetch(:name))
41
+ lines.push(" def visit_#{method}(node)", " visit_children(node)", " end", "")
42
+ end
43
+ append_visit_children(lines)
44
+ lines << " end"
45
+ end
46
+
47
+ # @rbs (Array[String] lines) -> void
48
+ def append_visit_children(lines)
49
+ lines.push(
50
+ " def visit_children(node)",
51
+ " children = if node.is_a?(Array)",
52
+ " node",
53
+ " elsif node.respond_to?(:deconstruct)",
54
+ " node.deconstruct",
55
+ " else",
56
+ " []",
57
+ " end",
58
+ " children.each { |child| visit(child) }",
59
+ " node",
60
+ " end"
61
+ )
62
+ end
63
+
64
+ # @rbs (Array[String] lines, Hash[String, IR::node_annotation] definitions) -> void
65
+ def append_listener(lines, definitions)
66
+ lines.push(" class Listener", " def walk(node)", " enter(node)",
67
+ " listener_children(node).each { |child| walk(child) }", " exit(node)", " node",
68
+ " end", "")
69
+ append_listener_dispatch(lines, definitions, :enter)
70
+ lines << ""
71
+ append_listener_dispatch(lines, definitions, :exit)
72
+ lines << ""
73
+ definitions.each_value do |node|
74
+ method = ast_method_name(node.fetch(:name))
75
+ lines.push(" def enter_#{method}(_node); end", " def exit_#{method}(_node); end")
76
+ end
77
+ lines << ""
78
+ lines.push(
79
+ " def listener_children(node)",
80
+ " return node if node.is_a?(Array)",
81
+ " return node.deconstruct if node.respond_to?(:deconstruct)",
82
+ "",
83
+ " []",
84
+ " end",
85
+ " end"
86
+ )
87
+ end
88
+
89
+ # @rbs (Array[String] lines, Hash[String, IR::node_annotation] definitions, :enter | :exit kind) -> void
90
+ def append_listener_dispatch(lines, definitions, kind)
91
+ lines.push(" def #{kind}(node)", " case node")
92
+ definitions.each_value do |node|
93
+ method = ast_method_name(node.fetch(:name))
94
+ lines << " when #{node.fetch(:name)} then #{kind}_#{method}(node)"
95
+ end
96
+ lines.push(" end", " end")
97
+ end
98
+
99
+ # @rbs (IR::Production production) -> String
100
+ def ast_node_action_source(production)
101
+ node = production.node || raise(Ibex::Error, "missing AST node metadata")
102
+ parameters = node.fetch(:fields).each_index.map { |index| "v#{index}" }
103
+ arguments = node.fetch(:fields).each_index.map do |index|
104
+ "#{node.fetch(:fields).fetch(index)}: v#{index}"
105
+ end
106
+ [
107
+ "private def _ibex_action_#{production.id}(#{parameters.join(', ')})",
108
+ " AST::#{node.fetch(:name)}.new(#{arguments.join(', ')})",
109
+ "end"
110
+ ].join("\n")
111
+ end
112
+
113
+ # @rbs (String name) -> String
114
+ def ast_method_name(name)
115
+ name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
116
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
117
+ .downcase
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibex
4
+ module Codegen
5
+ # Serializes immutable example-keyed error records into generated Ruby.
6
+ module RubyErrorMessages
7
+ private
8
+
9
+ # @rbs () -> String
10
+ def error_messages_literal
11
+ # @type self: Ruby
12
+ return "{}" if @error_messages.empty?
13
+
14
+ entries = @error_messages.map { |state, message| "#{state} => #{error_message_literal(message)}" }
15
+ "{ #{entries.join(', ')} }"
16
+ end
17
+
18
+ # @rbs (String | { id: String, message: String } message) -> String
19
+ def error_message_literal(message)
20
+ return message.inspect unless message.is_a?(Hash)
21
+
22
+ error_id = message.fetch(:id)
23
+ text = message.fetch(:message)
24
+ "{ id: #{error_id.inspect}, message: #{text.inspect} }.freeze"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Generated lexer tables and action methods.
7
+ module RubyLexer
8
+ private
9
+
10
+ # @rbs (Array[String] lines) -> void
11
+ def append_lexer(lines)
12
+ # @type self: Ruby
13
+ lexer = @grammar.lexer
14
+ return unless lexer
15
+
16
+ lines << " include Ibex::Runtime::GeneratedLexer"
17
+ lines << " LEXER_STATES = #{lexer.states.inspect}.freeze"
18
+ append_lexer_rules(lines, lexer)
19
+ append_lexer_actions(lines, lexer)
20
+ end
21
+
22
+ # @rbs (Array[String] lines, IR::Lexer lexer) -> void
23
+ def append_lexer_rules(lines, lexer)
24
+ # @type self: Ruby
25
+ by_state = lexer.states.to_h do |state|
26
+ rules = lexer.rules.select { |rule| rule.state == state }.map { |rule| lexer_rule_literal(rule) }
27
+ [state.to_sym, "[#{rules.join(', ')}].freeze"]
28
+ end
29
+ source = by_state.map { |state, rules| "#{state.inspect} => #{rules}" }.join(", ")
30
+ lines << " LEXER_RULES_BY_STATE = { #{source} }.freeze"
31
+ lines << ""
32
+ end
33
+
34
+ # @rbs (IR::LexerRule rule) -> String
35
+ def lexer_rule_literal(rule)
36
+ # @type self: Ruby
37
+ flags = 0
38
+ flags |= Regexp::IGNORECASE if rule.options.include?("i")
39
+ flags |= Regexp::MULTILINE if rule.options.include?("m")
40
+ flags |= Regexp::EXTENDED if rule.options.include?("x")
41
+ action = rule.action ? ":_ibex_lexer_action_#{rule.id}" : "nil"
42
+ terminal = rule.token && @grammar.symbol(rule.token)
43
+ token = terminal ? external_token_expression(terminal) : "nil"
44
+ regexp = "Regexp.new(#{"\\A(?:#{rule.pattern})".dump}, #{flags}).freeze"
45
+ "{ id: #{rule.id}, kind: #{rule.kind.inspect}, token: #{token}, " \
46
+ "regexp: #{regexp}, action: #{action} }.freeze"
47
+ end
48
+
49
+ # @rbs (Array[String] lines, IR::Lexer lexer) -> void
50
+ def append_lexer_actions(lines, lexer)
51
+ # @type self: Ruby
52
+ lexer.rules.each do |rule|
53
+ next unless rule.action
54
+
55
+ source = lexer_action_source(rule)
56
+ if @line_convert
57
+ location = rule.location
58
+ lines << " class_eval(#{source.dump}, #{location[:file].inspect}, #{location[:line]})"
59
+ else
60
+ source.lines.each { |line| lines << " #{line.rstrip}" }
61
+ end
62
+ lines << ""
63
+ end
64
+ end
65
+
66
+ # @rbs (IR::LexerRule rule) -> String
67
+ def lexer_action_source(rule)
68
+ action = rule.action || ""
69
+ binding = nil #: String?
70
+ if (match = action.match(/\A\s*\|([a-z_][a-zA-Z0-9_]*)\|\s*(.*)\z/m))
71
+ parameter = match[1] || "s"
72
+ binding = "#{parameter} = _ibex_lexeme"
73
+ action = match[2] || ""
74
+ end
75
+ lines = ["private def _ibex_lexer_action_#{rule.id}(_ibex_lexeme)"]
76
+ lines << " #{binding}" if binding
77
+ lines << " #{action}"
78
+ lines << "end"
79
+ "#{lines.join("\n")}\n"
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Generates typed Red syntax views from @node metadata.
7
+ module RubySyntax
8
+ private
9
+
10
+ # @rbs (Array[String] lines) -> void
11
+ def append_syntax(lines)
12
+ # @type self: Ruby
13
+ definitions = syntax_node_definitions
14
+ return if definitions.empty? || !cst?
15
+
16
+ lines << " module Syntax"
17
+ definitions.each_value { |definition| append_syntax_node(lines, definition) }
18
+ lines.push(" end", "")
19
+ end
20
+
21
+ # @rbs () -> Hash[String, Hash[Symbol, untyped]]
22
+ def syntax_node_definitions
23
+ # @type self: Ruby
24
+ slots = cst_metadata.fetch(:slots)
25
+ definitions = {} #: Hash[String, Hash[Symbol, untyped]]
26
+ @grammar.productions.each do |production|
27
+ node = production.node
28
+ next unless node
29
+
30
+ slot = slots.fetch(production.id)
31
+ name = node.fetch(:name)
32
+ previous = definitions[name]
33
+ fields = previous ? merge_syntax_fields(previous.fetch(:fields), slot.fetch(:fields)) : slot.fetch(:fields)
34
+ definitions[name] = { name: name, kind: slot.fetch(:node_kind), fields: fields }.freeze
35
+ end
36
+ definitions
37
+ end
38
+
39
+ # @rbs (Hash[String, untyped] left, Hash[String, untyped] right) -> Hash[String, untyped]
40
+ def merge_syntax_fields(left, right)
41
+ left.to_h do |name, left_slot|
42
+ right_slot = right.fetch(name)
43
+ left_index = left_slot.is_a?(Hash) ? left_slot.fetch(:index) : left_slot
44
+ right_index = right_slot.is_a?(Hash) ? right_slot.fetch(:index) : right_slot
45
+ raise Ibex::Error, "inconsistent CST slot for #{name}" unless left_index == right_index
46
+
47
+ [name, left_slot == right_slot ? left_slot : left_index]
48
+ end.freeze
49
+ end
50
+
51
+ # @rbs (Array[String] lines, Hash[Symbol, untyped] definition) -> void
52
+ def append_syntax_node(lines, definition)
53
+ name = definition.fetch(:name)
54
+ fields = definition.fetch(:fields)
55
+ lines.push(
56
+ " class #{name} < Ibex::Runtime::CST::TypedNode",
57
+ " KIND = #{definition.fetch(:kind)}",
58
+ " def self.cast(node) = node.kind == KIND ? new(node) : nil"
59
+ )
60
+ fields.each do |field, slot|
61
+ index = slot.is_a?(Hash) ? slot.fetch(:index) : slot
62
+ lines << " def #{field} = child_at_slot(#{index})"
63
+ end
64
+ append_repetition_accessors(lines, fields)
65
+ lines.push(" end", "")
66
+ end
67
+
68
+ # @rbs (Array[String] lines, Hash[String, untyped] fields) -> void
69
+ def append_repetition_accessors(lines, fields)
70
+ repeated = fields.select { |_field, slot| slot.is_a?(Hash) && slot[:extraction] }
71
+ repeated.each do |field, slot|
72
+ index = slot.fetch(:index)
73
+ separated = slot.fetch(:extraction) == :separated_list
74
+ lines << " def each_#{field}_element = list_items(#{index}, separated: #{separated})"
75
+ next unless separated
76
+
77
+ method = "each_#{field}_separator"
78
+ lines << " def #{method} = list_items(#{index}, separated: true, separators: true)"
79
+ end
80
+ return unless repeated.one?
81
+
82
+ field, slot = repeated.first
83
+ lines << " alias each_element each_#{field}_element"
84
+ return unless slot.fetch(:extraction) == :separated_list
85
+
86
+ lines << " alias each_separator each_#{field}_separator"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Emits immutable identity and size metadata for generated parser tables.
7
+ module RubyTableMetadata
8
+ # @rbs @automaton: IR::Automaton
9
+ # @rbs @grammar: IR::Grammar
10
+
11
+ private
12
+
13
+ # @rbs (Array[String] lines, String indent) -> void
14
+ def append_table_metadata(lines, indent)
15
+ lines << "#{indent}PARSER_TABLE_FORMAT_VERSION = #{Runtime::PARSER_TABLE_FORMAT_VERSION}"
16
+ lines << "#{indent}GRAMMAR_DIGEST = #{@automaton.grammar_digest.inspect}.freeze"
17
+ lines << "#{indent}STATE_COUNT = #{@automaton.states.length}"
18
+ lines << "#{indent}PRODUCTION_COUNT = #{@grammar.productions.length}"
19
+ return unless @grammar.starts.length > 1
20
+
21
+ entries = @automaton.entry_states.map { |name, state| "#{name.to_sym.inspect} => #{state}" }
22
+ lines << "#{indent}ENTRY_STATES = { #{entries.join(', ')} }.freeze"
23
+ end
24
+
25
+ # @rbs (Array[String] lines) -> void
26
+ def append_entry_methods(lines)
27
+ return unless @grammar.starts.length > 1
28
+
29
+ @grammar.starts.each do |name|
30
+ lines << " def parse_#{name}"
31
+ lines << " drive_parser(-> { next_token }, initial_state: ENTRY_STATES.fetch(:#{name}))"
32
+ lines << " end"
33
+ lines << ""
34
+ end
35
+ end
36
+
37
+ # @rbs () -> String
38
+ def entry_table_fields
39
+ return "" unless @grammar.starts.length > 1
40
+
41
+ " initial_state: ENTRY_STATES.fetch(:#{@grammar.start}), entry_states: ENTRY_STATES,"
42
+ end
43
+
44
+ # @rbs () -> String
45
+ def recovery_table_fields
46
+ names = @grammar.recovery[:sync_tokens]
47
+ return "" if names.empty?
48
+
49
+ ids = names.map do |name|
50
+ symbol = @grammar.symbol(name) || raise(Ibex::Error, "missing recovery sync token #{name}")
51
+ symbol.id
52
+ end
53
+ " recovery_sync_tokens: #{ids.inspect}.freeze,"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Emits declarative value-printer tables and methods for Ruby parsers.
7
+ module RubyValuePrinters
8
+ # @rbs @grammar: IR::Grammar
9
+ # @rbs @line_convert: bool
10
+ # @rbs @value_printer_action_method_source: ActionMethodSource?
11
+
12
+ private
13
+
14
+ # @rbs (Array[String] lines, String indent) -> void
15
+ def append_value_printer_table(lines, indent)
16
+ return if @grammar.value_printers.empty?
17
+
18
+ entries = @grammar.value_printers.map do |printer|
19
+ symbol = @grammar.symbol(printer[:symbol]) ||
20
+ raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
21
+ "#{symbol.id} => :_ibex_value_printer_#{symbol.id}"
22
+ end
23
+ lines << "#{indent}VALUE_PRINTERS = { #{entries.join(', ')} }.freeze"
24
+ end
25
+
26
+ # @rbs (Array[String] lines) -> void
27
+ def append_value_printers(lines)
28
+ @grammar.value_printers.each do |printer|
29
+ append_value_printer(lines, printer)
30
+ lines << ""
31
+ end
32
+ end
33
+
34
+ # @rbs (Array[String] lines, IR::value_printer printer) -> void
35
+ def append_value_printer(lines, printer)
36
+ symbol = @grammar.symbol(printer[:symbol]) ||
37
+ raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
38
+ source_builder = value_printer_action_method_source
39
+ source = source_builder.value_printer_method_source(symbol.id, printer)
40
+ if @line_convert
41
+ location = printer[:loc]
42
+ lines << " class_eval(#{source.dump}, #{location[:file].inspect}, #{location[:line]})"
43
+ elsif source_builder.column_sensitive?(printer[:code])
44
+ lines << source
45
+ else
46
+ source.lines.each { |line| lines << " #{line.rstrip}" }
47
+ end
48
+ end
49
+
50
+ # @rbs () -> ActionMethodSource
51
+ def value_printer_action_method_source
52
+ @value_printer_action_method_source ||= ActionMethodSource.new(@grammar)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -6,7 +6,7 @@ module Ibex
6
6
  module SymbolLabels
7
7
  # @rbs (IR::Grammar grammar) -> Hash[Integer, String]
8
8
  def self.build(grammar)
9
- labels = grammar.symbols.to_h { |symbol| [symbol.id, symbol.name] }
9
+ labels = grammar.symbols.to_h { |symbol| [symbol.id, symbol.display_name || symbol.name] }
10
10
  grammar.productions.each do |production|
11
11
  expression = production.origin[:expression]
12
12
  labels[production.lhs] = expression if expression.is_a?(String)