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.
- checksums.yaml +4 -4
- data/README.md +247 -104
- data/docs/architecture.md +322 -28
- data/docs/cst-migration.md +107 -0
- data/docs/cst.md +213 -0
- data/docs/development.md +129 -0
- data/docs/editor-setup.md +25 -0
- data/docs/error-ux.md +60 -0
- data/docs/grammar-reference.md +458 -18
- data/docs/lexer-migration.md +51 -0
- data/docs/racc-migration.md +34 -6
- data/docs/release-readiness.md +163 -0
- data/docs/stability.md +124 -0
- data/examples/README.md +60 -0
- data/examples/calculator.y +44 -0
- data/examples/csv.y +32 -0
- data/examples/ini.y +70 -0
- data/examples/json.y +48 -0
- data/examples/tiny_language.y +75 -0
- data/lib/ibex/analysis/sets.rb +5 -4
- data/lib/ibex/artifact_set.rb +63 -0
- data/lib/ibex/cli/ambiguity.rb +66 -0
- data/lib/ibex/cli/counterexample_options.rb +6 -2
- data/lib/ibex/cli/coverage.rb +173 -0
- data/lib/ibex/cli/debug.rb +106 -0
- data/lib/ibex/cli/diagnostics.rb +116 -0
- data/lib/ibex/cli/documentation.rb +67 -0
- data/lib/ibex/cli/error_messages.rb +177 -0
- data/lib/ibex/cli/explain.rb +76 -0
- data/lib/ibex/cli/formatting.rb +386 -0
- data/lib/ibex/cli/generation_artifacts.rb +138 -0
- data/lib/ibex/cli/generation_error_messages.rb +39 -0
- data/lib/ibex/cli/grammar_tests.rb +122 -0
- data/lib/ibex/cli/ir_tools.rb +184 -0
- data/lib/ibex/cli/lsp.rb +33 -0
- data/lib/ibex/cli/outputs.rb +91 -8
- data/lib/ibex/cli/racc_migration.rb +87 -0
- data/lib/ibex/cli/samples.rb +92 -0
- data/lib/ibex/cli/watch.rb +103 -0
- data/lib/ibex/cli.rb +506 -37
- data/lib/ibex/codegen/action_locations.rb +103 -0
- data/lib/ibex/codegen/action_method_source.rb +210 -0
- data/lib/ibex/codegen/action_source.rb +118 -0
- data/lib/ibex/codegen/ambiguity.rb +173 -0
- data/lib/ibex/codegen/cst_metadata.rb +171 -0
- data/lib/ibex/codegen/documentation.rb +170 -0
- data/lib/ibex/codegen/explain.rb +312 -0
- data/lib/ibex/codegen/generated_action_abi.rb +288 -0
- data/lib/ibex/codegen/html.rb +94 -10
- data/lib/ibex/codegen/mermaid.rb +43 -0
- data/lib/ibex/codegen/railroad.rb +197 -0
- data/lib/ibex/codegen/railroad_documentation.rb +59 -0
- data/lib/ibex/codegen/rbs.rb +323 -2
- data/lib/ibex/codegen/report.rb +46 -6
- data/lib/ibex/codegen/ruby.rb +334 -59
- data/lib/ibex/codegen/ruby_actions.rb +143 -0
- data/lib/ibex/codegen/ruby_ast.rb +121 -0
- data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
- data/lib/ibex/codegen/ruby_lexer.rb +83 -0
- data/lib/ibex/codegen/ruby_syntax.rb +90 -0
- data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
- data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
- data/lib/ibex/codegen/symbol_labels.rb +1 -1
- data/lib/ibex/coverage/collector.rb +188 -0
- data/lib/ibex/coverage/event_stream.rb +97 -0
- data/lib/ibex/coverage/report.rb +259 -0
- data/lib/ibex/coverage/runtime_event_validator.rb +160 -0
- data/lib/ibex/coverage.rb +13 -0
- data/lib/ibex/error_messages/parser.rb +159 -0
- data/lib/ibex/error_messages/parser_v2.rb +198 -0
- data/lib/ibex/error_messages/renderer.rb +65 -0
- data/lib/ibex/error_messages/sentence_search.rb +196 -0
- data/lib/ibex/error_messages/update.rb +169 -0
- data/lib/ibex/error_messages.rb +165 -0
- data/lib/ibex/frontend/ast.rb +145 -6
- data/lib/ibex/frontend/bootstrap_parser.rb +47 -4
- data/lib/ibex/frontend/diagnostic.rb +81 -0
- data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
- data/lib/ibex/frontend/dsl.rb +66 -7
- data/lib/ibex/frontend/formatter.rb +407 -0
- data/lib/ibex/frontend/generated_parser.rb +614 -190
- data/lib/ibex/frontend/generated_parser_base.rb +164 -30
- data/lib/ibex/frontend/generated_parser_includes.rb +61 -0
- data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
- data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
- data/lib/ibex/frontend/generation.rb +33 -0
- data/lib/ibex/frontend/lexer.rb +162 -10
- data/lib/ibex/frontend/lexer_recovery.rb +84 -0
- data/lib/ibex/frontend/parser/declarations.rb +247 -11
- data/lib/ibex/frontend/parser/parameters.rb +82 -0
- data/lib/ibex/frontend/parser/rules.rb +43 -6
- data/lib/ibex/frontend/parser.rb +182 -4
- data/lib/ibex/frontend/regenerator.rb +26 -1
- data/lib/ibex/frontend/resolution.rb +69 -0
- data/lib/ibex/frontend/resolver.rb +217 -0
- data/lib/ibex/frontend/rule_documentation.rb +103 -0
- data/lib/ibex/frontend/source_cursor.rb +132 -8
- data/lib/ibex/frontend/source_document.rb +229 -0
- data/lib/ibex/frontend/source_loader.rb +150 -0
- data/lib/ibex/frontend/source_span.rb +81 -0
- data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
- data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
- data/lib/ibex/frontend/token_adapter/declaration_state.rb +216 -26
- data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
- data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
- data/lib/ibex/frontend/token_adapter.rb +8 -3
- data/lib/ibex/frontend.rb +13 -2
- data/lib/ibex/generation_input.rb +57 -0
- data/lib/ibex/generation_manifest.rb +200 -0
- data/lib/ibex/generation_transaction.rb +261 -0
- data/lib/ibex/generation_transaction_recovery.rb +109 -0
- data/lib/ibex/generation_transaction_validation.rb +196 -0
- data/lib/ibex/grammar_tests.rb +206 -0
- data/lib/ibex/ir/automaton_ir.rb +38 -5
- data/lib/ibex/ir/grammar_ir.rb +137 -24
- data/lib/ibex/ir/lexer_ir.rb +76 -0
- data/lib/ibex/ir/migration.rb +120 -0
- data/lib/ibex/ir/serialize.rb +110 -19
- data/lib/ibex/ir/validator/automaton.rb +345 -0
- data/lib/ibex/ir/validator/base.rb +129 -0
- data/lib/ibex/ir/validator/grammar.rb +604 -0
- data/lib/ibex/ir/validator/lexer.rb +113 -0
- data/lib/ibex/ir/validator.rb +62 -0
- data/lib/ibex/ir.rb +57 -4
- data/lib/ibex/lalr/build_metrics.rb +23 -0
- data/lib/ibex/lalr/builder.rb +379 -52
- data/lib/ibex/lalr/conflict.rb +1 -0
- data/lib/ibex/lalr/conflict_search.rb +11 -5
- data/lib/ibex/lalr/counterexample.rb +20 -5
- data/lib/ibex/lalr/direct_lookaheads.rb +236 -0
- data/lib/ibex/lalr/ielr_partition.rb +152 -0
- data/lib/ibex/lalr/on_error_reductions.rb +74 -0
- data/lib/ibex/lalr.rb +7 -0
- data/lib/ibex/location.rb +129 -0
- data/lib/ibex/lsp/document_handlers.rb +66 -0
- data/lib/ibex/lsp/document_store.rb +264 -0
- data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
- data/lib/ibex/lsp/document_store_validation.rb +61 -0
- data/lib/ibex/lsp/initialization_handlers.rb +78 -0
- data/lib/ibex/lsp/navigation_handlers.rb +56 -0
- data/lib/ibex/lsp/position_codec.rb +109 -0
- data/lib/ibex/lsp/protocol_error.rb +33 -0
- data/lib/ibex/lsp/request_handlers.rb +45 -0
- data/lib/ibex/lsp/request_support.rb +87 -0
- data/lib/ibex/lsp/server.rb +146 -0
- data/lib/ibex/lsp/symbol_index.rb +241 -0
- data/lib/ibex/lsp/symbol_index_builder.rb +267 -0
- data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
- data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
- data/lib/ibex/lsp/symbol_occurrence.rb +17 -0
- data/lib/ibex/lsp/transport.rb +118 -0
- data/lib/ibex/lsp/workspace.rb +127 -0
- data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
- data/lib/ibex/lsp.rb +32 -0
- data/lib/ibex/normalize/declarations.rb +140 -7
- data/lib/ibex/normalize/diagnostics.rb +50 -5
- data/lib/ibex/normalize/expander.rb +59 -55
- data/lib/ibex/normalize/expression.rb +60 -39
- data/lib/ibex/normalize/inline_expansion.rb +414 -0
- data/lib/ibex/normalize/inline_validation.rb +174 -0
- data/lib/ibex/normalize/lexer.rb +131 -0
- data/lib/ibex/normalize/named_references.rb +60 -0
- data/lib/ibex/normalize/nodes.rb +46 -0
- data/lib/ibex/normalize/parameter_ebnf_lowering.rb +69 -0
- data/lib/ibex/normalize/parameter_lowering.rb +126 -0
- data/lib/ibex/normalize/parameter_substitution.rb +125 -0
- data/lib/ibex/normalize/parameter_validation.rb +140 -0
- data/lib/ibex/normalize/parameters.rb +199 -0
- data/lib/ibex/normalize/recovery_declarations.rb +84 -0
- data/lib/ibex/normalize.rb +179 -14
- data/lib/ibex/racc_migration/checker.rb +122 -0
- data/lib/ibex/racc_migration/harness.rb +177 -0
- data/lib/ibex/racc_migration/report.rb +94 -0
- data/lib/ibex/racc_migration.rb +12 -0
- data/lib/ibex/rake_task.rb +116 -0
- data/lib/ibex/samples.rb +186 -0
- data/lib/ibex/table_simulation/result.rb +51 -0
- data/lib/ibex/table_simulation/simulator.rb +253 -0
- data/lib/ibex/table_simulation/step.rb +60 -0
- data/lib/ibex/table_simulation/text.rb +31 -0
- data/lib/ibex/table_simulation.rb +13 -0
- data/lib/ibex/tables.rb +9 -70
- data/lib/ibex/version.rb +1 -1
- data/lib/ibex/watch/runner.rb +172 -0
- data/lib/ibex/watch/source_snapshot.rb +93 -0
- data/lib/ibex/watch.rb +11 -0
- data/lib/ibex.rb +25 -1
- data/schema/automaton-ir-v1.schema.json +401 -0
- data/schema/automaton-ir-v2.schema.json +58 -0
- data/schema/benchmark-v1.schema.json +212 -0
- data/schema/benchmark-v2.schema.json +61 -0
- data/schema/cst-v1.json +170 -0
- data/schema/error-ux-v1.schema.json +258 -0
- data/schema/explain-v1.schema.json +433 -0
- data/schema/frontend-diagnostics-v1.schema.json +154 -0
- data/schema/generation-manifest-v1.schema.json +115 -0
- data/schema/grammar-ir-v1.schema.json +426 -0
- data/schema/grammar-ir-v2.schema.json +779 -0
- data/schema/lexer-ir-v1.schema.json +215 -0
- data/schema/migration-check-v1.schema.json +60 -0
- data/schema/performance-comparison-v1.schema.json +395 -0
- data/schema/public-performance-comparison-v1.schema.json +506 -0
- data/schema/public-performance-profile-v1.schema.json +360 -0
- data/schema/runtime-coverage-v1.schema.json +86 -0
- data/schema/runtime-event-v1.schema.json +308 -0
- data/schema/table-simulation-v1.schema.json +70 -0
- data/sig/ibex/artifact_set.rbs +37 -0
- data/sig/ibex/cli/ambiguity.rbs +22 -0
- data/sig/ibex/cli/counterexample_options.rbs +2 -0
- data/sig/ibex/cli/coverage.rbs +53 -0
- data/sig/ibex/cli/debug.rbs +28 -0
- data/sig/ibex/cli/diagnostics.rbs +38 -0
- data/sig/ibex/cli/documentation.rbs +25 -0
- data/sig/ibex/cli/error_messages.rbs +57 -0
- data/sig/ibex/cli/explain.rbs +25 -0
- data/sig/ibex/cli/formatting.rbs +103 -0
- data/sig/ibex/cli/generation_artifacts.rbs +50 -0
- data/sig/ibex/cli/generation_error_messages.rbs +19 -0
- data/sig/ibex/cli/grammar_tests.rbs +36 -0
- data/sig/ibex/cli/ir_tools.rbs +51 -0
- data/sig/ibex/cli/lsp.rbs +14 -0
- data/sig/ibex/cli/outputs.rbs +17 -0
- data/sig/ibex/cli/racc_migration.rbs +30 -0
- data/sig/ibex/cli/samples.rbs +30 -0
- data/sig/ibex/cli/watch.rbs +43 -0
- data/sig/ibex/cli.rbs +104 -5
- data/sig/ibex/codegen/action_locations.rbs +45 -0
- data/sig/ibex/codegen/action_method_source.rbs +65 -0
- data/sig/ibex/codegen/action_source.rbs +50 -0
- data/sig/ibex/codegen/ambiguity.rbs +60 -0
- data/sig/ibex/codegen/cst_metadata.rbs +59 -0
- data/sig/ibex/codegen/documentation.rbs +50 -0
- data/sig/ibex/codegen/explain.rbs +85 -0
- data/sig/ibex/codegen/generated_action_abi.rbs +101 -0
- data/sig/ibex/codegen/html.rbs +18 -2
- data/sig/ibex/codegen/mermaid.rbs +16 -0
- data/sig/ibex/codegen/railroad.rbs +82 -0
- data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
- data/sig/ibex/codegen/rbs.rbs +84 -4
- data/sig/ibex/codegen/report.rbs +8 -0
- data/sig/ibex/codegen/ruby.rbs +97 -23
- data/sig/ibex/codegen/ruby_actions.rbs +54 -0
- data/sig/ibex/codegen/ruby_ast.rbs +34 -0
- data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
- data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
- data/sig/ibex/codegen/ruby_syntax.rbs +25 -0
- data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
- data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
- data/sig/ibex/coverage/collector.rbs +76 -0
- data/sig/ibex/coverage/event_stream.rbs +42 -0
- data/sig/ibex/coverage/report.rbs +100 -0
- data/sig/ibex/coverage/runtime_event_validator.rbs +68 -0
- data/sig/ibex/coverage.rbs +7 -0
- data/sig/ibex/error_messages/parser.rbs +58 -0
- data/sig/ibex/error_messages/parser_v2.rbs +67 -0
- data/sig/ibex/error_messages/renderer.rbs +23 -0
- data/sig/ibex/error_messages/sentence_search.rbs +80 -0
- data/sig/ibex/error_messages/update.rbs +43 -0
- data/sig/ibex/error_messages.rbs +85 -0
- data/sig/ibex/frontend/ast.rbs +208 -19
- data/sig/ibex/frontend/bootstrap_parser.rbs +11 -0
- data/sig/ibex/frontend/diagnostic.rbs +53 -0
- data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
- data/sig/ibex/frontend/dsl.rbs +33 -4
- data/sig/ibex/frontend/formatter.rbs +135 -0
- data/sig/ibex/frontend/generated_parser.rbs +218 -68
- data/sig/ibex/frontend/generated_parser_base.rbs +61 -10
- data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
- data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
- data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
- data/sig/ibex/frontend/generation.rbs +6 -0
- data/sig/ibex/frontend/lexer.rbs +49 -2
- data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
- data/sig/ibex/frontend/parser/declarations.rbs +54 -0
- data/sig/ibex/frontend/parser/parameters.rbs +28 -0
- data/sig/ibex/frontend/parser/rules.rbs +3 -0
- data/sig/ibex/frontend/parser.rbs +66 -0
- data/sig/ibex/frontend/regenerator.rbs +11 -0
- data/sig/ibex/frontend/resolution.rbs +33 -0
- data/sig/ibex/frontend/resolver.rbs +91 -0
- data/sig/ibex/frontend/rule_documentation.rbs +42 -0
- data/sig/ibex/frontend/source_cursor.rbs +36 -3
- data/sig/ibex/frontend/source_document.rbs +119 -0
- data/sig/ibex/frontend/source_loader.rbs +66 -0
- data/sig/ibex/frontend/source_span.rbs +53 -0
- data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
- data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
- data/sig/ibex/frontend/token_adapter/declaration_state.rbs +73 -5
- data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
- data/sig/ibex/frontend/token_adapter.rbs +5 -2
- data/sig/ibex/frontend.rbs +1 -1
- data/sig/ibex/generation_input.rbs +37 -0
- data/sig/ibex/generation_manifest.rbs +67 -0
- data/sig/ibex/generation_transaction.rbs +82 -0
- data/sig/ibex/generation_transaction_recovery.rbs +36 -0
- data/sig/ibex/generation_transaction_validation.rbs +65 -0
- data/sig/ibex/grammar_tests.rbs +93 -0
- data/sig/ibex/ir/automaton_ir.rbs +8 -2
- data/sig/ibex/ir/grammar_ir.rbs +75 -15
- data/sig/ibex/ir/lexer_ir.rbs +57 -0
- data/sig/ibex/ir/migration.rbs +34 -0
- data/sig/ibex/ir/serialize.rbs +23 -6
- data/sig/ibex/ir/validator/automaton.rbs +109 -0
- data/sig/ibex/ir/validator/base.rbs +65 -0
- data/sig/ibex/ir/validator/grammar.rbs +184 -0
- data/sig/ibex/ir/validator/lexer.rbs +37 -0
- data/sig/ibex/ir/validator.rbs +16 -0
- data/sig/ibex/ir.rbs +38 -4
- data/sig/ibex/lalr/build_metrics.rbs +20 -0
- data/sig/ibex/lalr/builder.rbs +95 -15
- data/sig/ibex/lalr/conflict_search.rbs +7 -3
- data/sig/ibex/lalr/counterexample.rbs +5 -2
- data/sig/ibex/lalr/direct_lookaheads.rbs +86 -0
- data/sig/ibex/lalr/ielr_partition.rbs +59 -0
- data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
- data/sig/ibex/lalr.rbs +6 -0
- data/sig/ibex/location.rbs +67 -0
- data/sig/ibex/lsp/document_handlers.rbs +24 -0
- data/sig/ibex/lsp/document_store.rbs +94 -0
- data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
- data/sig/ibex/lsp/document_store_validation.rbs +26 -0
- data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
- data/sig/ibex/lsp/navigation_handlers.rbs +30 -0
- data/sig/ibex/lsp/position_codec.rbs +40 -0
- data/sig/ibex/lsp/protocol_error.rbs +32 -0
- data/sig/ibex/lsp/request_handlers.rbs +26 -0
- data/sig/ibex/lsp/request_support.rbs +40 -0
- data/sig/ibex/lsp/server.rbs +55 -0
- data/sig/ibex/lsp/symbol_index.rbs +78 -0
- data/sig/ibex/lsp/symbol_index_builder.rbs +87 -0
- data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
- data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
- data/sig/ibex/lsp/symbol_occurrence.rbs +25 -0
- data/sig/ibex/lsp/transport.rbs +35 -0
- data/sig/ibex/lsp/workspace.rbs +41 -0
- data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
- data/sig/ibex/lsp.rbs +7 -0
- data/sig/ibex/normalize/declarations.rbs +31 -0
- data/sig/ibex/normalize/diagnostics.rbs +9 -0
- data/sig/ibex/normalize/expander.rbs +20 -14
- data/sig/ibex/normalize/expression.rbs +10 -10
- data/sig/ibex/normalize/inline_expansion.rbs +120 -0
- data/sig/ibex/normalize/inline_validation.rbs +40 -0
- data/sig/ibex/normalize/lexer.rbs +37 -0
- data/sig/ibex/normalize/named_references.rbs +20 -0
- data/sig/ibex/normalize/nodes.rbs +14 -0
- data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +32 -0
- data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
- data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
- data/sig/ibex/normalize/parameter_validation.rbs +44 -0
- data/sig/ibex/normalize/parameters.rbs +46 -0
- data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
- data/sig/ibex/normalize.rbs +123 -18
- data/sig/ibex/racc_migration/checker.rbs +36 -0
- data/sig/ibex/racc_migration/harness.rbs +16 -0
- data/sig/ibex/racc_migration/report.rbs +53 -0
- data/sig/ibex/racc_migration.rbs +8 -0
- data/sig/ibex/rake_task.rbs +51 -0
- data/sig/ibex/samples.rbs +51 -0
- data/sig/ibex/table_simulation/result.rbs +32 -0
- data/sig/ibex/table_simulation/simulator.rbs +98 -0
- data/sig/ibex/table_simulation/step.rbs +40 -0
- data/sig/ibex/table_simulation/text.rbs +14 -0
- data/sig/ibex/table_simulation.rbs +7 -0
- data/sig/ibex/tables.rbs +0 -26
- data/sig/ibex/watch/runner.rbs +48 -0
- data/sig/ibex/watch/source_snapshot.rbs +42 -0
- data/sig/ibex/watch.rbs +7 -0
- data/sig/ibex.rbs +2 -0
- metadata +301 -16
- data/.rubocop.yml +0 -43
- data/CHANGELOG.md +0 -30
- data/Rakefile +0 -25
- data/Steepfile +0 -10
- data/docs/compat-notes.md +0 -37
- data/docs/lexer-coverage.md +0 -14
- data/docs/phase10-extensions.md +0 -27
- data/gemfiles/Gemfile +0 -7
- data/gemfiles/Gemfile.lock +0 -98
- data/lib/ibex/frontend/grammar.y +0 -156
- data/lib/ibex/runtime/parser.rb +0 -360
- data/lib/ibex/runtime.rb +0 -8
- data/sig/ibex/runtime/parser.rbs +0 -167
- 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
|