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
data/lib/ibex/frontend/dsl.rb
CHANGED
|
@@ -48,9 +48,29 @@ module Ibex
|
|
|
48
48
|
@declarations << AST::Expect.new(conflicts: conflicts, loc: next_location)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
# @rbs (Object
|
|
52
|
-
def start(
|
|
53
|
-
@declarations << AST::Start.new(
|
|
51
|
+
# @rbs (*Object names) -> void
|
|
52
|
+
def start(*names)
|
|
53
|
+
@declarations << AST::Start.new(names: names.map(&:to_s), loc: next_location)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @rbs (*Object names) -> void
|
|
57
|
+
def recover_sync(*names)
|
|
58
|
+
@declarations << AST::Recovery.new(sync_tokens: names.map(&:to_s), loc: next_location)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @rbs (*Object names) -> void
|
|
62
|
+
def on_error_reduce(*names)
|
|
63
|
+
@declarations << AST::OnErrorReduce.new(names: names.map(&:to_s), loc: next_location)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @rbs (Object source) -> void
|
|
67
|
+
def test_accept(source)
|
|
68
|
+
@declarations << AST::GrammarTest.new(expectation: :accept, source: source.to_s, loc: next_location)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @rbs (Object source) -> void
|
|
72
|
+
def test_reject(source)
|
|
73
|
+
@declarations << AST::GrammarTest.new(expectation: :reject, source: source.to_s, loc: next_location)
|
|
54
74
|
end
|
|
55
75
|
|
|
56
76
|
# @rbs (Object name, Object expression) -> void
|
|
@@ -60,6 +80,29 @@ module Ibex
|
|
|
60
80
|
@declarations << AST::Convert.new(pairs: [pair], loc: location)
|
|
61
81
|
end
|
|
62
82
|
|
|
83
|
+
# @rbs (Object name, Object value) -> void
|
|
84
|
+
def display(name, value)
|
|
85
|
+
@declarations << AST::DisplayName.new(name: name.to_s, value: metadata_value(value, "display"),
|
|
86
|
+
loc: next_location)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @rbs (Object name, Object value) -> void
|
|
90
|
+
def type(name, value)
|
|
91
|
+
@declarations << AST::SemanticType.new(name: name.to_s, value: metadata_value(value, "type"),
|
|
92
|
+
loc: next_location)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @rbs (Object name, ?Object? semantic_type) -> void
|
|
96
|
+
def param(name, semantic_type = nil)
|
|
97
|
+
type = semantic_type && metadata_value(semantic_type, "%param")
|
|
98
|
+
@declarations << AST::Parameter.new(name: name.to_s, semantic_type: type, loc: next_location)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @rbs (Object name, Object code) -> void
|
|
102
|
+
def printer(name, code)
|
|
103
|
+
@declarations << AST::Printer.new(name: name.to_s, code: code.to_s, loc: next_location)
|
|
104
|
+
end
|
|
105
|
+
|
|
63
106
|
# @rbs (?direction: Symbol) { (PrecedenceBuilder) -> void } -> void
|
|
64
107
|
def precedence(direction: :low_to_high)
|
|
65
108
|
location = next_location
|
|
@@ -73,7 +116,9 @@ module Ibex
|
|
|
73
116
|
location = next_location
|
|
74
117
|
builder = RuleBuilder.new(self, location)
|
|
75
118
|
yield builder
|
|
76
|
-
@rules << AST::Rule.new(
|
|
119
|
+
@rules << AST::Rule.new(
|
|
120
|
+
lhs: lhs.to_s, parameters: [], alternatives: builder.alternatives, loc: location, inline: false
|
|
121
|
+
)
|
|
77
122
|
end
|
|
78
123
|
|
|
79
124
|
# @rbs (Object name, Object code) -> void
|
|
@@ -134,6 +179,19 @@ module Ibex
|
|
|
134
179
|
@line += 1
|
|
135
180
|
location
|
|
136
181
|
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
# @rbs (Object value, String feature) -> String
|
|
186
|
+
def metadata_value(value, feature)
|
|
187
|
+
string = value.to_s
|
|
188
|
+
raise ArgumentError, "#{feature} value must not be empty" if string.strip.empty?
|
|
189
|
+
raise ArgumentError, "#{feature} value must be a single line" if string.match?(/[\r\n]/)
|
|
190
|
+
raise ArgumentError, "#{feature} value must not contain control characters" if
|
|
191
|
+
string.match?(/[[:cntrl:]]/)
|
|
192
|
+
|
|
193
|
+
string
|
|
194
|
+
end
|
|
137
195
|
end
|
|
138
196
|
|
|
139
197
|
# Collects ordered associativity levels.
|
|
@@ -180,13 +238,14 @@ module Ibex
|
|
|
180
238
|
@alternatives = [] #: Array[AST::Alternative]
|
|
181
239
|
end
|
|
182
240
|
|
|
183
|
-
# @rbs (*Object items, ?action: Object?, ?precedence: Object?) -> void
|
|
184
|
-
def alt(*items, action: nil, precedence: nil)
|
|
241
|
+
# @rbs (*Object items, ?action: Object?, ?precedence: Object?, ?node: AST::NodeAnnotation?) -> void
|
|
242
|
+
def alt(*items, action: nil, precedence: nil, node: nil)
|
|
185
243
|
location = @grammar.next_location || @default_location
|
|
186
244
|
normalized = items.map { |item| @grammar.normalize_item(item) }
|
|
187
245
|
action_node = action && AST::InlineAction.new(code: action.to_s, loc: location)
|
|
188
246
|
alternative = AST::Alternative.new(
|
|
189
|
-
items: normalized, action: action_node, precedence: precedence&.to_s,
|
|
247
|
+
items: normalized, action: action_node, precedence: precedence&.to_s,
|
|
248
|
+
node_annotation: node, loc: location
|
|
190
249
|
)
|
|
191
250
|
@alternatives << alternative
|
|
192
251
|
end
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module Frontend
|
|
5
|
+
# Deterministically formats grammar trivia and rejects any semantic change.
|
|
6
|
+
# rubocop:disable Metrics/ClassLength -- token layout policy stays together so adjacency rules remain auditable.
|
|
7
|
+
class Formatter
|
|
8
|
+
DECLARATION_STARTS = %i[
|
|
9
|
+
PRAGMA INCLUDE IMPORT TOKEN PRECHIGH PRECLOW OPTIONS EXPECT EXPECT_RR START RECOVER ON_ERROR_REDUCE TEST LEXER
|
|
10
|
+
CONVERT DISPLAY TYPE PARAM PRINTER RULE
|
|
11
|
+
].freeze #: Array[Symbol]
|
|
12
|
+
ASSOCIATIONS = %i[LEFT RIGHT NONASSOC].freeze #: Array[Symbol]
|
|
13
|
+
CALLABLES = %i[LHS PARAMETERIZED_REFERENCE SEPARATED_LIST SEPARATED_NONEMPTY_LIST].freeze #: Array[Symbol]
|
|
14
|
+
SUFFIXES = %w[? * +].freeze #: Array[String]
|
|
15
|
+
CLOSERS = %w[) , ;].freeze #: Array[String]
|
|
16
|
+
ADJACENT_AFTER = ["::", "("].freeze #: Array[String]
|
|
17
|
+
|
|
18
|
+
# @rbs!
|
|
19
|
+
# type formatter_element = {
|
|
20
|
+
# segment: Segment,
|
|
21
|
+
# external: external_token?,
|
|
22
|
+
# role: Symbol?,
|
|
23
|
+
# gap: Array[Segment]
|
|
24
|
+
# }
|
|
25
|
+
|
|
26
|
+
# @rbs (String source, ?file: String, ?mode: Symbol) -> String
|
|
27
|
+
def self.format(source, file: "(grammar)", mode: :default)
|
|
28
|
+
new(mode: mode).format(source, file: file)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @rbs (?mode: Symbol) -> void
|
|
32
|
+
def initialize(mode: :default)
|
|
33
|
+
raise ArgumentError, "mode must be :default or :extended" unless %i[default extended].include?(mode)
|
|
34
|
+
|
|
35
|
+
@mode = mode
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @rbs (String source, ?file: String) -> String
|
|
39
|
+
def format(source, file: "(grammar)")
|
|
40
|
+
document = Parser.new(source, file: file, mode: @mode).parse_source_document
|
|
41
|
+
formatted = render(document)
|
|
42
|
+
reparsed = Parser.new(formatted, file: file, mode: @mode).parse_source_document
|
|
43
|
+
unless same_semantic_projection?(document.ast, reparsed.ast)
|
|
44
|
+
raise Ibex::Error, "#{file}: formatting would change grammar semantics"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
formatted
|
|
48
|
+
rescue Ibex::Error
|
|
49
|
+
raise
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
raise Ibex::Error, "#{file}: formatting failed: #{e.message}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# @rbs (SourceDocument document) -> String
|
|
57
|
+
def render(document)
|
|
58
|
+
@default_newline = document.source.match(/\r\n|\n/)&.[](0) || "\n"
|
|
59
|
+
elements = build_elements(document)
|
|
60
|
+
output = +""
|
|
61
|
+
previous = nil #: formatter_element?
|
|
62
|
+
elements.each do |current|
|
|
63
|
+
output << separator(previous, current)
|
|
64
|
+
output << current.fetch(:segment).text
|
|
65
|
+
previous = current
|
|
66
|
+
end
|
|
67
|
+
output
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @rbs (SourceDocument document) -> Array[formatter_element]
|
|
71
|
+
def build_elements(document)
|
|
72
|
+
external_types = external_types(document.tokens)
|
|
73
|
+
pending = [] #: Array[Segment]
|
|
74
|
+
elements = document.cst.each_with_object([]) do |segment, result|
|
|
75
|
+
if %i[whitespace newline].include?(segment.kind)
|
|
76
|
+
pending << segment
|
|
77
|
+
next
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
result << {
|
|
81
|
+
segment: segment,
|
|
82
|
+
external: segment.token_index && external_types[segment.token_index],
|
|
83
|
+
role: nil,
|
|
84
|
+
gap: pending
|
|
85
|
+
}
|
|
86
|
+
pending = []
|
|
87
|
+
end
|
|
88
|
+
annotate_roles(elements)
|
|
89
|
+
elements
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (Array[Token] tokens) -> Hash[Integer, external_token]
|
|
93
|
+
def external_types(tokens)
|
|
94
|
+
adapter = TokenAdapter.new(tokens, extended: @mode == :extended)
|
|
95
|
+
types = {} #: Hash[Integer, external_token]
|
|
96
|
+
index = 0
|
|
97
|
+
while (classified = adapter.next_token)
|
|
98
|
+
types[index] = classified.fetch(0)
|
|
99
|
+
index += 1
|
|
100
|
+
end
|
|
101
|
+
types
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @rbs (Array[formatter_element] elements) -> void
|
|
105
|
+
def annotate_roles(elements)
|
|
106
|
+
state = {
|
|
107
|
+
section: :declarations, precedence_closer: nil, conversion: false,
|
|
108
|
+
conversion_name: true, depth: 0, rule_colon: false
|
|
109
|
+
} #: Hash[Symbol, untyped]
|
|
110
|
+
elements.each do |element|
|
|
111
|
+
external = element.fetch(:external)
|
|
112
|
+
next unless external
|
|
113
|
+
|
|
114
|
+
element[:role] = token_role(external, state)
|
|
115
|
+
advance_role_state(external, element.fetch(:role), state)
|
|
116
|
+
end
|
|
117
|
+
annotate_comment_indentation(elements)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @rbs (Array[formatter_element] elements) -> void
|
|
121
|
+
def annotate_comment_indentation(elements)
|
|
122
|
+
following_role = nil #: Symbol?
|
|
123
|
+
elements.reverse_each do |element|
|
|
124
|
+
segment = element.fetch(:segment)
|
|
125
|
+
if comment?(segment)
|
|
126
|
+
element[:role] = :rule_comment if following_role == :rule_start
|
|
127
|
+
element[:role] = :alternative_comment if following_role == :alternative
|
|
128
|
+
elsif element.fetch(:external)
|
|
129
|
+
following_role = element.fetch(:role)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @rbs (external_token external, Hash[Symbol, untyped] state) -> Symbol?
|
|
135
|
+
def token_role(external, state)
|
|
136
|
+
document_role = document_token_role(external, state)
|
|
137
|
+
return document_role if document_role
|
|
138
|
+
|
|
139
|
+
rule_token_role(external, state)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @rbs (external_token external, Hash[Symbol, untyped] state) -> Symbol?
|
|
143
|
+
def document_token_role(external, state)
|
|
144
|
+
return :user_code if external == :USER_CODE
|
|
145
|
+
return precedence_role(external, state) if %i[PRECHIGH PRECLOW].include?(external)
|
|
146
|
+
return :precedence_level if ASSOCIATIONS.include?(external) && state[:precedence_closer]
|
|
147
|
+
return section_end_role(state) if external == :END
|
|
148
|
+
return :conversion_entry if state.fetch(:conversion) && state.fetch(:conversion_name)
|
|
149
|
+
return :rule_keyword if external == :RULE
|
|
150
|
+
return :declaration if DECLARATION_STARTS.include?(external)
|
|
151
|
+
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @rbs (Hash[Symbol, untyped] state) -> Symbol?
|
|
156
|
+
def section_end_role(state)
|
|
157
|
+
return :conversion_end if state.fetch(:conversion)
|
|
158
|
+
return :grammar_end if state.fetch(:section) == :rules
|
|
159
|
+
|
|
160
|
+
nil
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @rbs (external_token external, Hash[Symbol, untyped] state) -> Symbol?
|
|
164
|
+
def rule_token_role(external, state)
|
|
165
|
+
return :rule_start if external == :INLINE && state.fetch(:section) == :rules
|
|
166
|
+
return :rule_start if external == :LHS
|
|
167
|
+
return :alternative if external == "|" && state.fetch(:section) == :rules && state.fetch(:depth).zero?
|
|
168
|
+
|
|
169
|
+
if external == ":"
|
|
170
|
+
return :rule_colon if state.fetch(:rule_colon) && state.fetch(:depth).zero?
|
|
171
|
+
|
|
172
|
+
return :named_reference
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# @rbs (external_token external, Hash[Symbol, untyped] state) -> Symbol
|
|
179
|
+
def precedence_role(external, state)
|
|
180
|
+
return :precedence_end if state[:precedence_closer] == external
|
|
181
|
+
|
|
182
|
+
:declaration
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# @rbs (external_token external, Symbol? role, Hash[Symbol, untyped] state) -> void
|
|
186
|
+
def advance_role_state(external, role, state)
|
|
187
|
+
advance_precedence_state(external, role, state)
|
|
188
|
+
advance_conversion_state(external, role, state)
|
|
189
|
+
advance_rule_state(external, role, state)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# @rbs (external_token external, Symbol? role, Hash[Symbol, untyped] state) -> void
|
|
193
|
+
def advance_precedence_state(external, role, state)
|
|
194
|
+
if role == :declaration && %i[PRECHIGH PRECLOW].include?(external)
|
|
195
|
+
state[:precedence_closer] = external == :PRECHIGH ? :PRECLOW : :PRECHIGH
|
|
196
|
+
elsif role == :precedence_end
|
|
197
|
+
state[:precedence_closer] = nil
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# @rbs (external_token external, Symbol? role, Hash[Symbol, untyped] state) -> void
|
|
202
|
+
def advance_conversion_state(external, role, state)
|
|
203
|
+
if external == :CONVERT
|
|
204
|
+
state[:conversion] = true
|
|
205
|
+
state[:conversion_name] = true
|
|
206
|
+
elsif role == :conversion_end
|
|
207
|
+
state[:conversion] = false
|
|
208
|
+
elsif state.fetch(:conversion) && role == :conversion_entry
|
|
209
|
+
state[:conversion_name] = false
|
|
210
|
+
elsif state.fetch(:conversion) && !state.fetch(:conversion_name)
|
|
211
|
+
state[:conversion_name] = true
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# @rbs (external_token external, Symbol? role, Hash[Symbol, untyped] state) -> void
|
|
216
|
+
def advance_rule_state(external, role, state)
|
|
217
|
+
state[:section] = :rules if external == :RULE
|
|
218
|
+
state[:rule_colon] = true if external == :LHS
|
|
219
|
+
state[:rule_colon] = false if role == :rule_colon
|
|
220
|
+
state[:depth] += 1 if external == "("
|
|
221
|
+
state[:depth] -= 1 if external == ")"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @rbs (formatter_element? previous, formatter_element current) -> String
|
|
225
|
+
def separator(previous, current)
|
|
226
|
+
gap = current.fetch(:gap)
|
|
227
|
+
return leading_separator(current, gap) unless previous
|
|
228
|
+
|
|
229
|
+
previous_segment = previous.fetch(:segment)
|
|
230
|
+
current_segment = current.fetch(:segment)
|
|
231
|
+
return "" if direct_opaque_pair?(previous_segment, current_segment)
|
|
232
|
+
return trailing_separator(previous, gap) if current_segment.kind == :eof
|
|
233
|
+
return comment_separator(previous, current, gap) if comment?(previous_segment) || comment?(current_segment)
|
|
234
|
+
|
|
235
|
+
kind = separator_kind(previous, current)
|
|
236
|
+
render_separator(kind, gap, indentation(current))
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# @rbs (formatter_element current, Array[Segment] gap) -> String
|
|
240
|
+
def leading_separator(current, gap)
|
|
241
|
+
return "" unless newline_in?(gap)
|
|
242
|
+
|
|
243
|
+
render_separator(:line, gap, indentation(current))
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# @rbs (formatter_element previous, Array[Segment] gap) -> String
|
|
247
|
+
def trailing_separator(previous, gap)
|
|
248
|
+
segment = previous.fetch(:segment)
|
|
249
|
+
return "" if segment.kind == :user_code_body
|
|
250
|
+
return render_separator(:line, gap, 0) if previous.fetch(:role) == :grammar_end
|
|
251
|
+
|
|
252
|
+
render_separator(gap.any? { |item| item.kind == :newline } ? :line : :none, gap, 0)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# @rbs (Segment previous, Segment current) -> bool
|
|
256
|
+
def direct_opaque_pair?(previous, current)
|
|
257
|
+
(previous.kind == :user_code_marker && current.kind == :user_code_body) ||
|
|
258
|
+
(previous.kind == :user_code_body && current.kind == :user_code_marker)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# @rbs (Segment segment) -> bool
|
|
262
|
+
def comment?(segment)
|
|
263
|
+
%i[line_comment block_comment].include?(segment.kind)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# @rbs (formatter_element previous, formatter_element current, Array[Segment] gap) -> String
|
|
267
|
+
def comment_separator(previous, current, gap)
|
|
268
|
+
previous_segment = previous.fetch(:segment)
|
|
269
|
+
current_segment = current.fetch(:segment)
|
|
270
|
+
if text_ends_with_newline?(previous_segment.text)
|
|
271
|
+
newlines = gap.select { |segment| segment.kind == :newline }.map(&:text)
|
|
272
|
+
return newlines.join + (" " * indentation(current))
|
|
273
|
+
end
|
|
274
|
+
if previous_segment.kind == :line_comment || newline_in?(gap)
|
|
275
|
+
return render_separator(:line, gap, indentation(current))
|
|
276
|
+
end
|
|
277
|
+
return " " if current_segment.kind == :line_comment || previous_segment.kind == :block_comment ||
|
|
278
|
+
current_segment.kind == :block_comment
|
|
279
|
+
|
|
280
|
+
render_separator(:space, gap, indentation(current))
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# @rbs (formatter_element previous, formatter_element current) -> Symbol
|
|
284
|
+
def separator_kind(previous, current)
|
|
285
|
+
previous_external = previous.fetch(:external)
|
|
286
|
+
current_external = current.fetch(:external)
|
|
287
|
+
previous_role = previous.fetch(:role)
|
|
288
|
+
current_role = current.fetch(:role)
|
|
289
|
+
|
|
290
|
+
return :line if line_boundary?(previous_role, current_role, previous, current)
|
|
291
|
+
return :none if adjacent_tokens?(previous_external, current_external, previous_role, current_role)
|
|
292
|
+
|
|
293
|
+
:space
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# @rbs (external_token? previous_external, external_token? current_external,
|
|
297
|
+
# Symbol? previous_role, Symbol? current_role) -> bool
|
|
298
|
+
def adjacent_tokens?(previous_external, current_external, previous_role, current_role)
|
|
299
|
+
return true if current_role == :named_reference || previous_role == :named_reference
|
|
300
|
+
return true if current_external == "::"
|
|
301
|
+
return true if CLOSERS.include?(current_external) || SUFFIXES.include?(current_external)
|
|
302
|
+
return true if ADJACENT_AFTER.include?(previous_external)
|
|
303
|
+
|
|
304
|
+
current_external == "(" && CALLABLES.include?(previous_external)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @rbs (Symbol? previous_role, Symbol? current_role, formatter_element previous,
|
|
308
|
+
# formatter_element current) -> bool
|
|
309
|
+
def line_boundary?(previous_role, current_role, previous, current)
|
|
310
|
+
return false if current_role == :rule_start && previous.fetch(:external) == :INLINE
|
|
311
|
+
|
|
312
|
+
return true if %i[declaration rule_keyword precedence_level precedence_end conversion_entry
|
|
313
|
+
conversion_end rule_start alternative grammar_end user_code].include?(current_role)
|
|
314
|
+
return true if previous_role == :rule_keyword
|
|
315
|
+
return false unless current.fetch(:segment).kind == :user_code_marker
|
|
316
|
+
|
|
317
|
+
previous.fetch(:segment).kind != :user_code_body
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# @rbs (formatter_element element) -> Integer
|
|
321
|
+
def indentation(element)
|
|
322
|
+
case element.fetch(:role)
|
|
323
|
+
when :rule_start, :precedence_level, :conversion_entry, :rule_comment then 2
|
|
324
|
+
when :alternative, :alternative_comment then 4
|
|
325
|
+
else 0
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# @rbs (Symbol kind, Array[Segment] gap, Integer indentation) -> String
|
|
330
|
+
def render_separator(kind, gap, indentation)
|
|
331
|
+
return "" if kind == :none
|
|
332
|
+
return " " if kind == :space
|
|
333
|
+
|
|
334
|
+
newlines = gap.select { |segment| segment.kind == :newline }.map(&:text)
|
|
335
|
+
newlines = [@default_newline] if newlines.empty?
|
|
336
|
+
newlines.join + (" " * indentation)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# @rbs (Array[Segment] gap) -> bool
|
|
340
|
+
def newline_in?(gap)
|
|
341
|
+
gap.any? { |segment| segment.kind == :newline }
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# @rbs (String text) -> bool
|
|
345
|
+
def text_ends_with_newline?(text)
|
|
346
|
+
text.end_with?("\n")
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# @rbs (untyped left, untyped right) -> bool
|
|
350
|
+
def same_semantic_projection?(left, right)
|
|
351
|
+
pending = [[left, right]] #: Array[[untyped, untyped]]
|
|
352
|
+
until pending.empty?
|
|
353
|
+
pair = pending.pop
|
|
354
|
+
next unless pair
|
|
355
|
+
|
|
356
|
+
left_value, right_value = pair
|
|
357
|
+
next if left_value.equal?(right_value)
|
|
358
|
+
return false unless comparable_semantic_values?(left_value, right_value)
|
|
359
|
+
|
|
360
|
+
append_semantic_children(pending, left_value, right_value)
|
|
361
|
+
end
|
|
362
|
+
true
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# @rbs (untyped left, untyped right) -> bool
|
|
366
|
+
def comparable_semantic_values?(left, right)
|
|
367
|
+
return left.instance_of?(right.class) && left.members == right.members if left.is_a?(Struct)
|
|
368
|
+
return right.is_a?(Array) && left.length == right.length if left.is_a?(Array)
|
|
369
|
+
return comparable_semantic_hashes?(left, right) if left.is_a?(Hash)
|
|
370
|
+
|
|
371
|
+
left == right
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# @rbs (Hash[untyped, untyped] left, untyped right) -> bool
|
|
375
|
+
def comparable_semantic_hashes?(left, right)
|
|
376
|
+
return false unless right.is_a?(Hash)
|
|
377
|
+
|
|
378
|
+
left_keys = semantic_keys(left)
|
|
379
|
+
right_keys = semantic_keys(right)
|
|
380
|
+
left_keys.length == right_keys.length && left_keys.all? { |key| right_keys.include?(key) }
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# @rbs (Array[[untyped, untyped]] pending, untyped left, untyped right) -> void
|
|
384
|
+
def append_semantic_children(pending, left, right)
|
|
385
|
+
case left
|
|
386
|
+
when Struct
|
|
387
|
+
semantic_members(left).reverse_each { |member| pending << [left[member], right[member]] }
|
|
388
|
+
when Array
|
|
389
|
+
left.each_index.reverse_each { |index| pending << [left[index], right[index]] }
|
|
390
|
+
when Hash
|
|
391
|
+
semantic_keys(left).reverse_each { |key| pending << [left[key], right[key]] }
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# @rbs (Struct[untyped] value) -> Array[Symbol]
|
|
396
|
+
def semantic_members(value)
|
|
397
|
+
value.members.reject { |member| %i[loc span].include?(member) }
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# @rbs (Hash[untyped, untyped] value) -> Array[untyped]
|
|
401
|
+
def semantic_keys(value)
|
|
402
|
+
value.keys.reject { |key| %i[loc span].include?(key) }
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
# rubocop:enable Metrics/ClassLength
|
|
406
|
+
end
|
|
407
|
+
end
|