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,103 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ module Ibex
5
+ module Codegen
6
+ # Rewrites semantic-location expressions without touching Ruby literals,
7
+ # comments, heredoc bodies, or ordinary instance/class variables.
8
+ class ActionLocations
9
+ SEMANTIC_HELPERS = %w[loc result_loc].freeze #: Array[String]
10
+ private_constant :SEMANTIC_HELPERS
11
+
12
+ # @rbs @source: String
13
+ # @rbs @maximum: Integer
14
+ # @rbs @location: IR::location
15
+
16
+ # @rbs (String source, maximum: Integer, location: IR::location) -> void
17
+ def initialize(source, maximum:, location:)
18
+ @source = source
19
+ @maximum = maximum
20
+ @location = location
21
+ end
22
+
23
+ # @rbs () -> String
24
+ def rewrite
25
+ rewritten = mutable_binary_source_copy
26
+ return rewritten.force_encoding(@source.encoding) unless @source.match?(/@(?:\$|\d+)/)
27
+
28
+ replacements = semantic_references.map do |offset, spelling|
29
+ [offset, spelling.bytesize, replacement_for(spelling)]
30
+ end #: Array[[Integer, Integer, String]]
31
+ replacements.reverse_each { |offset, length, replacement| rewritten[offset, length] = replacement }
32
+ rewritten.force_encoding(@source.encoding)
33
+ end
34
+
35
+ # @rbs () -> bool
36
+ def references?
37
+ return true if @source.match?(/@(?:\$|\d+)/) && !semantic_references.empty?
38
+ return false unless @source.match?(/\b(?:loc|result_loc)\b/)
39
+
40
+ require "ripper"
41
+ tokens = Object.const_get(:Ripper).__send__(:lex, lexable_source)
42
+ tokens.any? do |_position, type, token, _state|
43
+ type == :on_ident && SEMANTIC_HELPERS.include?(token)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # @rbs () -> String
50
+ def mutable_binary_source_copy
51
+ String.new(encoding: Encoding::BINARY).replace(@source.b)
52
+ end
53
+
54
+ # @rbs () -> Array[[Integer, String]]
55
+ def semantic_references
56
+ require "ripper"
57
+
58
+ offsets = line_offsets
59
+ tokens = Object.const_get(:Ripper).__send__(:lex, lexable_source)
60
+ # @type var tokens: Array[[[Integer, Integer], Symbol, String, untyped]]
61
+ tokens.filter_map do |position, type, _token, _state|
62
+ next unless type == :on_ident
63
+
64
+ line, column = position
65
+ offset = offsets.fetch(line - 1) + column
66
+ spelling = @source.b.byteslice(offset..)&.match(/\A@(?:\$|\d+)/)&.[](0)
67
+ [offset, spelling] if spelling
68
+ end
69
+ end
70
+
71
+ # Give every Ripper implementation syntactically valid input while
72
+ # preserving byte offsets and lexical string/comment boundaries.
73
+ # @rbs () -> String
74
+ def lexable_source
75
+ @source.gsub(/@(?:\$|\d+)/) { |spelling| "_" * spelling.bytesize }
76
+ end
77
+
78
+ # @rbs () -> Array[Integer]
79
+ def line_offsets
80
+ offset = 0
81
+ @source.lines.map do |line|
82
+ current = offset
83
+ offset += line.bytesize
84
+ current
85
+ end
86
+ end
87
+
88
+ # @rbs (String spelling) -> String
89
+ def replacement_for(spelling)
90
+ return "_ibex_location" if spelling == "@$"
91
+
92
+ index = spelling.delete_prefix("@").to_i
93
+ if index.zero? || index > @maximum
94
+ raise Ibex::Error,
95
+ "#{@location[:file]}:#{@location[:line]}:#{@location[:column]}: " \
96
+ "semantic location #{spelling} is outside 1..#{@maximum}"
97
+ end
98
+
99
+ "_ibex_locations[#{index - 1}]"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "action_locations"
5
+ require_relative "generated_action_abi"
6
+
7
+ module Ibex
8
+ module Codegen
9
+ # Builds semantic method source shared by runtime and static shadow output.
10
+ class ActionMethodSource
11
+ # @rbs @grammar: IR::Grammar
12
+ # @rbs @generated_action_abi: GeneratedActionABI::Cache
13
+
14
+ # @rbs (IR::Grammar grammar, ?generated_action_abi: GeneratedActionABI::Cache?) -> void
15
+ def initialize(grammar, generated_action_abi: nil)
16
+ @grammar = grammar
17
+ @generated_action_abi = generated_action_abi || GeneratedActionABI::Cache.new
18
+ end
19
+
20
+ # @rbs (IR::Production production, Hash[Symbol, untyped] step, Integer index) -> String
21
+ def composed_fragment_method_source(production, step, index)
22
+ source = "private def #{composed_fragment_name(production, index)}" \
23
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location); "
24
+ append_parameter_values(source)
25
+ context_length = step.fetch(:context_length)
26
+ if context_length.positive?
27
+ source << "val = _values.last(#{context_length}); "
28
+ source << "_ibex_locations = _ibex_location_stack.last(#{context_length}); "
29
+ end
30
+ named_refs = step.fetch(:named_refs)
31
+ named_refs.each { |reference| source << "#{reference[:name]} = val[#{reference[:index]}]; " }
32
+ append_named_values(source, named_refs)
33
+ source << "result = val[0]; " if step.fetch(:result_var)
34
+ source << composed_semantic_code(step)
35
+ source << "\nresult" if step.fetch(:result_var)
36
+ source << "\nend"
37
+ end
38
+
39
+ # @rbs (IR::Production production, Integer index) -> String
40
+ def composed_fragment_name(production, index)
41
+ "_ibex_inline_fragment_#{production.id}_#{index}"
42
+ end
43
+
44
+ # @rbs (IR::Production production) -> String
45
+ def compiled_action_method_source(production)
46
+ action = production.action
47
+ source = "private def _ibex_action_#{production.id}#{action_parameters(production)}; "
48
+ append_parameter_values(source, production: production)
49
+ return "#{source}#{default_value_expression(production)}\nend" unless action
50
+
51
+ if action.context_length.positive?
52
+ source << "val = _values.last(#{action.context_length}); "
53
+ source << "_ibex_locations = _ibex_location_stack.last(#{action.context_length}); "
54
+ end
55
+ action.named_refs.each do |reference|
56
+ source << "#{reference[:name]} = #{value_expression(production, reference[:index])}; "
57
+ end
58
+ append_named_values(source, action.named_refs)
59
+ append_action_body(source, production, action)
60
+ source << "\nend"
61
+ end
62
+
63
+ # @rbs (IR::Production production) -> String
64
+ def direct_action_method_source(production)
65
+ action = production.action
66
+ lines = [
67
+ "private def _ibex_action_#{production.id}#{action_parameters(production)}"
68
+ ]
69
+ append_direct_parameter_values(lines, production: production)
70
+ if action&.context_length&.positive?
71
+ lines << " val = _values.last(#{action.context_length})"
72
+ lines << " _ibex_locations = _ibex_location_stack.last(#{action.context_length})"
73
+ end
74
+ if action&.named_refs&.any?
75
+ action.named_refs.each do |reference|
76
+ lines << " #{reference[:name]} = #{value_expression(production, reference[:index])}"
77
+ end
78
+ names = action.named_refs.map { |reference| reference[:name] }
79
+ lines << " _ibex_named_values = [#{names.join(', ')}]"
80
+ end
81
+ append_direct_action_body(lines, production, action)
82
+ lines << "end"
83
+ lines.join("\n")
84
+ end
85
+
86
+ # @rbs (Integer symbol_id, IR::value_printer printer) -> String
87
+ def value_printer_method_source(symbol_id, printer)
88
+ source = "private def _ibex_value_printer_#{symbol_id}(value); "
89
+ append_parameter_values(source)
90
+ source << printer[:code]
91
+ source << "\nend"
92
+ end
93
+
94
+ # @rbs (String source) -> bool
95
+ def column_sensitive?(source)
96
+ return false unless source.include?("<<")
97
+
98
+ require "ripper"
99
+ tokens = Object.const_get(:Ripper).__send__(:lex, source)
100
+ # @type var tokens: Array[[[Integer, Integer], Symbol, String, untyped]]
101
+ tokens.any? { |_position, event, _token, _state| event == :on_heredoc_beg }
102
+ end
103
+
104
+ private
105
+
106
+ # @rbs (IR::Production production) -> String
107
+ def action_parameters(production)
108
+ if @generated_action_abi.positional_values?(production)
109
+ parameters = Array.new(production.rhs.length) { |index| "v#{index}" }
110
+ return "(#{parameters.join(', ')})"
111
+ end
112
+ return "(val)" if @generated_action_abi.values_only?(production)
113
+
114
+ "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location)"
115
+ end
116
+
117
+ # @rbs (IR::Production production, Integer index) -> String
118
+ def value_expression(production, index)
119
+ return "v#{index}" if @generated_action_abi.positional_values?(production)
120
+
121
+ "val[#{index}]"
122
+ end
123
+
124
+ # @rbs (String source, ?production: IR::Production?) -> void
125
+ def append_parameter_values(source, production: nil)
126
+ excluded = if production && @generated_action_abi.positional_values?(production)
127
+ Array.new(production.rhs.length) { |index| "v#{index}" }
128
+ else
129
+ [] #: Array[String]
130
+ end
131
+ @grammar.parser_parameters.each do |parameter|
132
+ next if excluded.include?(parameter[:name])
133
+
134
+ source << "#{parameter[:name]} = @#{parameter[:name]}; "
135
+ end
136
+ end
137
+
138
+ # @rbs (Array[String] lines, production: IR::Production) -> void
139
+ def append_direct_parameter_values(lines, production:)
140
+ excluded = if @generated_action_abi.positional_values?(production)
141
+ Array.new(production.rhs.length) { |index| "v#{index}" }
142
+ else
143
+ [] #: Array[String]
144
+ end
145
+ @grammar.parser_parameters.each do |parameter|
146
+ next if excluded.include?(parameter[:name])
147
+
148
+ lines << " #{parameter[:name]} = @#{parameter[:name]}"
149
+ end
150
+ end
151
+
152
+ # @rbs (Hash[Symbol, untyped] step) -> String
153
+ def composed_semantic_code(step)
154
+ maximum = [step.fetch(:inputs).length, step.fetch(:context_length)].max
155
+ ActionLocations.new(
156
+ step.fetch(:code), maximum: maximum, location: step.fetch(:loc)
157
+ ).rewrite
158
+ end
159
+
160
+ # @rbs (String source, Array[IR::named_ref] named_refs) -> void
161
+ def append_named_values(source, named_refs)
162
+ return if named_refs.empty?
163
+
164
+ names = named_refs.map { |reference| reference[:name] }
165
+ source << "_ibex_named_values = [#{names.join(', ')}]; "
166
+ end
167
+
168
+ # @rbs (String source, IR::Production production, IR::Action action) -> void
169
+ def append_action_body(source, production, action)
170
+ source << "result = #{default_value_expression(production)}; " if @grammar.options[:result_var]
171
+ source << semantic_action_code(production, action)
172
+ source << "\nresult" if @grammar.options[:result_var]
173
+ end
174
+
175
+ # @rbs (Array[String] lines, IR::Production production, IR::Action? action) -> void
176
+ def append_direct_action_body(lines, production, action)
177
+ unless action
178
+ lines << " #{default_value_expression(production)}"
179
+ return
180
+ end
181
+
182
+ lines << " result = #{default_value_expression(production)}" if @grammar.options[:result_var]
183
+ semantic_code = semantic_action_code(production, action)
184
+ if column_sensitive?(semantic_code)
185
+ lines << semantic_code
186
+ else
187
+ semantic_code.lines.each { |line| lines << " #{line.rstrip}" }
188
+ end
189
+ lines << " result" if @grammar.options[:result_var]
190
+ end
191
+
192
+ # @rbs (IR::Production production, IR::Action action) -> String
193
+ def semantic_action_code(production, action)
194
+ positional = @generated_action_abi.positional_action_source(production)
195
+ return positional unless positional.nil?
196
+
197
+ maximum = action.context_length.positive? ? action.context_length : production.rhs.length
198
+ ActionLocations.new(action.code, maximum: maximum, location: action.location).rewrite
199
+ end
200
+
201
+ # @rbs (IR::Production production) -> String
202
+ def default_value_expression(production)
203
+ return "nil" if production.rhs.empty?
204
+ return "v0" if @generated_action_abi.positional_values?(production)
205
+
206
+ "val[0]"
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,118 @@
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
+ # Generates static-check-only Ruby containing semantic action methods.
10
+ class ActionSource
11
+ include RubyAST
12
+
13
+ # @rbs @automaton: IR::Automaton
14
+ # @rbs @grammar: IR::Grammar
15
+ # @rbs @omit_action_call: bool
16
+ # @rbs @method_source: ActionMethodSource
17
+
18
+ # @rbs (IR::Automaton automaton, ?omit_action_call: bool?) -> void
19
+ def initialize(automaton, omit_action_call: nil)
20
+ @automaton = automaton
21
+ @grammar = automaton.grammar
22
+ @omit_action_call = omit_action_call.nil? ? @grammar.options[:omit_action_call] : omit_action_call
23
+ @method_source = ActionMethodSource.new(@grammar)
24
+ end
25
+
26
+ # @rbs () -> String
27
+ def generate
28
+ lines = [
29
+ "# frozen_string_literal: true",
30
+ "# Generated by Ibex #{grammar_digest_comment}.",
31
+ "# Static-check-only semantic action shadow source.",
32
+ "# DO NOT LOAD OR EXECUTE: runtime wiring and user code are intentionally absent.",
33
+ ""
34
+ ]
35
+ modules, class_name = class_parts
36
+ modules.each { |name| lines << "module #{name}" }
37
+ lines << "class #{class_name}"
38
+ append_ast(lines)
39
+ append_value_printers(lines)
40
+ append_actions(lines)
41
+ lines << "end"
42
+ modules.reverse_each { lines << "end" }
43
+ "#{lines.join("\n")}\n"
44
+ end
45
+
46
+ private
47
+
48
+ # @rbs (Array[String] lines) -> void
49
+ def append_value_printers(lines)
50
+ @grammar.value_printers.each do |printer|
51
+ symbol = @grammar.symbol(printer[:symbol]) || raise(Ibex::Error, "missing printer symbol #{printer[:symbol]}")
52
+ append_method(lines, printer[:loc], @method_source.value_printer_method_source(symbol.id, printer))
53
+ end
54
+ end
55
+
56
+ # @rbs (Array[String] lines) -> void
57
+ def append_actions(lines)
58
+ @grammar.productions.each do |production|
59
+ if production.node
60
+ append_method(lines, production.node.fetch(:loc), ast_node_action_source(production))
61
+ elsif composed_action?(production)
62
+ append_composed_actions(lines, production)
63
+ elsif production.action || !@omit_action_call
64
+ append_action(lines, production)
65
+ end
66
+ end
67
+ end
68
+
69
+ # @rbs (Array[String] lines, IR::Production production) -> void
70
+ def append_composed_actions(lines, production)
71
+ plan = production.action&.composition&.dig(:plan)
72
+ raise Ibex::Error, "missing action composition plan" unless plan
73
+
74
+ plan.fetch(:steps).each_with_index do |step, index|
75
+ next unless step[:code]
76
+
77
+ append_method(
78
+ lines, step.fetch(:loc),
79
+ @method_source.composed_fragment_method_source(production, step, index)
80
+ )
81
+ end
82
+ end
83
+
84
+ # @rbs (Array[String] lines, IR::Production production) -> void
85
+ def append_action(lines, production)
86
+ location = production.action&.location || production.origin.fetch(:loc)
87
+ append_method(lines, location, @method_source.compiled_action_method_source(production))
88
+ end
89
+
90
+ # @rbs (Array[String] lines, IR::location location, String source) -> void
91
+ def append_method(lines, location, source)
92
+ lines << ""
93
+ lines << " # Grammar action: #{location.fetch(:file).inspect}:" \
94
+ "#{location.fetch(:line)}:#{location.fetch(:column)}"
95
+ # Keep action bytes at column zero. Ruby lexical nesting does not require
96
+ # indentation, while changing it can invalidate <<HEREDOC terminators or
97
+ # alter <<~HEREDOC dedentation.
98
+ lines << source
99
+ end
100
+
101
+ # @rbs (IR::Production production) -> bool
102
+ def composed_action?(production)
103
+ production.action&.composition&.dig(:plan, :version) == 1
104
+ end
105
+
106
+ # @rbs () -> [Array[String], String]
107
+ def class_parts
108
+ parts = @grammar.class_name.split("::")
109
+ [parts.take(parts.length - 1), parts.fetch(-1)]
110
+ end
111
+
112
+ # @rbs () -> String
113
+ def grammar_digest_comment
114
+ @automaton.grammar_digest.delete_prefix("sha256:").chars.first(12).join
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+ # rbs_inline: enabled
3
+
4
+ require_relative "../lalr"
5
+
6
+ module Ibex
7
+ module Codegen
8
+ # @rbs!
9
+ # type ambiguity_search = {
10
+ # max_tokens: Integer,
11
+ # max_configurations: Integer
12
+ # }
13
+ # type ambiguity_summary = {
14
+ # conflicts: Integer,
15
+ # ambiguous: Integer,
16
+ # not_found: Integer,
17
+ # configuration_budget_exhausted: Integer
18
+ # }
19
+ # type ambiguity_check = {
20
+ # state: Integer,
21
+ # type: String,
22
+ # token: String,
23
+ # result: String,
24
+ # sentence: Array[String],
25
+ # lookahead_index: Integer?,
26
+ # interpretations: Array[IR::interpretation],
27
+ # explored_configurations: Integer,
28
+ # configuration_budget_exhausted: bool
29
+ # }
30
+ # type ambiguity_document = {
31
+ # ibex_check: String,
32
+ # schema_version: Integer,
33
+ # algorithm: String,
34
+ # search: ambiguity_search,
35
+ # status: String,
36
+ # summary: ambiguity_summary,
37
+ # conflicts: Array[ambiguity_check]
38
+ # }
39
+
40
+ # Renders a bounded ambiguity search over every parser conflict.
41
+ class Ambiguity
42
+ SCHEMA_VERSION = 1 #: Integer
43
+
44
+ # @rbs @automaton: IR::Automaton
45
+ # @rbs @grammar: IR::Grammar
46
+ # @rbs @max_tokens: Integer
47
+ # @rbs @max_configurations: Integer
48
+ # @rbs @checks: Array[ambiguity_check]
49
+
50
+ # @rbs (IR::Automaton automaton, ?max_tokens: Integer, ?max_configurations: Integer) -> void
51
+ def initialize(
52
+ automaton,
53
+ max_tokens: LALR::Counterexample::DEFAULT_MAX_TOKENS,
54
+ max_configurations: LALR::Counterexample::DEFAULT_MAX_CONFIGURATIONS
55
+ )
56
+ LALR::ConflictSearchLimits.validate!(
57
+ max_tokens: max_tokens, max_configurations: max_configurations
58
+ )
59
+ @automaton = automaton
60
+ @grammar = automaton.grammar
61
+ @max_tokens = max_tokens
62
+ @max_configurations = max_configurations
63
+ @checks = check_conflicts
64
+ end
65
+
66
+ # @rbs () -> Integer
67
+ def exit_status
68
+ return 1 if status == "ambiguous"
69
+ return 2 if status == "inconclusive"
70
+
71
+ 0
72
+ end
73
+
74
+ # @rbs () -> ambiguity_document
75
+ def to_h
76
+ {
77
+ ibex_check: "ambiguity",
78
+ schema_version: SCHEMA_VERSION,
79
+ algorithm: @automaton.algorithm,
80
+ search: { max_tokens: @max_tokens, max_configurations: @max_configurations },
81
+ status: status,
82
+ summary: summary,
83
+ conflicts: @checks
84
+ }
85
+ end
86
+
87
+ # @rbs () -> String
88
+ def render_text
89
+ counts = summary
90
+ lines = [
91
+ "Ibex ambiguity check v#{SCHEMA_VERSION}",
92
+ "Algorithm: #{@automaton.algorithm}",
93
+ "Search budget: #{@max_tokens} tokens, #{@max_configurations} configurations per conflict",
94
+ "Result: #{status}",
95
+ "Conflicts: #{counts.fetch(:conflicts)}, ambiguous: #{counts.fetch(:ambiguous)}, " \
96
+ "exhausted: #{counts.fetch(:configuration_budget_exhausted)}"
97
+ ]
98
+ @checks.each_with_index { |check, index| append_check(lines, check, index + 1) }
99
+ "#{lines.join("\n")}\n"
100
+ end
101
+
102
+ private
103
+
104
+ # @rbs () -> String
105
+ def status
106
+ return "ambiguous" if @checks.any? { |check| check.fetch(:result) == "ambiguous" }
107
+ return "inconclusive" if @checks.any? { |check| check.fetch(:configuration_budget_exhausted) }
108
+
109
+ "no_ambiguity_found_within_bounds"
110
+ end
111
+
112
+ # @rbs () -> ambiguity_summary
113
+ def summary
114
+ {
115
+ conflicts: @checks.length,
116
+ ambiguous: @checks.count { |check| check.fetch(:result) == "ambiguous" },
117
+ not_found: @checks.count { |check| check.fetch(:result) == "not_found" },
118
+ configuration_budget_exhausted: @checks.count do |check|
119
+ check.fetch(:configuration_budget_exhausted)
120
+ end
121
+ }
122
+ end
123
+
124
+ # @rbs () -> Array[ambiguity_check]
125
+ def check_conflicts
126
+ @automaton.states.flat_map do |state|
127
+ state.conflicts.map { |conflict| check_conflict(state, conflict) }
128
+ end
129
+ end
130
+
131
+ # @rbs (IR::AutomatonState state, IR::conflict conflict) -> ambiguity_check
132
+ def check_conflict(state, conflict)
133
+ search = LALR::ConflictSearch.new(
134
+ @automaton, state, conflict,
135
+ max_tokens: @max_tokens, max_configurations: @max_configurations
136
+ )
137
+ result = search.call
138
+ {
139
+ state: state.id,
140
+ type: conflict.fetch(:type).to_s,
141
+ token: conflict.fetch(:symbol),
142
+ result: result ? "ambiguous" : "not_found",
143
+ sentence: result ? symbol_names(result.fetch(:sentence_ids)) : [],
144
+ lookahead_index: result&.fetch(:lookahead_index),
145
+ interpretations: result ? result.fetch(:interpretations) : [],
146
+ explored_configurations: search.explored,
147
+ configuration_budget_exhausted: search.exhausted?
148
+ }
149
+ end
150
+
151
+ # @rbs (Array[Integer] ids) -> Array[String]
152
+ def symbol_names(ids)
153
+ ids.map do |id|
154
+ symbol = @grammar.symbol_by_id(id) || raise(Ibex::Error, "missing grammar symbol id #{id}")
155
+ symbol.display_name || symbol.name
156
+ end
157
+ end
158
+
159
+ # @rbs (Array[String] lines, ambiguity_check check, Integer number) -> void
160
+ def append_check(lines, check, number)
161
+ lines << ""
162
+ lines << "#{number}. State #{check.fetch(:state)}, #{check.fetch(:type)}, token #{check.fetch(:token)}"
163
+ lines << " Result: #{check.fetch(:result)}"
164
+ sentence = check.fetch(:sentence)
165
+ lines << " Sentence: #{sentence.join(' ')}" unless sentence.empty?
166
+ lines << " Explored configurations: #{check.fetch(:explored_configurations)}"
167
+ return unless check.fetch(:configuration_budget_exhausted)
168
+
169
+ lines << " Configuration budget exhausted before a counterexample was found."
170
+ end
171
+ end
172
+ end
173
+ end