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,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# Shared publication, state, and parameter validation for request handlers.
|
|
6
|
+
module RequestSupport
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
# @rbs (Array[DocumentStore::publication] publications) -> void
|
|
10
|
+
def publish(publications)
|
|
11
|
+
publications.each do |publication|
|
|
12
|
+
version = publication[:version]
|
|
13
|
+
next if version && stale_publication?(publication.fetch(:uri), version)
|
|
14
|
+
|
|
15
|
+
params = {
|
|
16
|
+
"uri" => publication.fetch(:uri),
|
|
17
|
+
"diagnostics" => publication.fetch(:diagnostics)
|
|
18
|
+
} #: Hash[String, untyped]
|
|
19
|
+
params["version"] = version if version
|
|
20
|
+
@transport.write_message(
|
|
21
|
+
"jsonrpc" => "2.0", "method" => "textDocument/publishDiagnostics", "params" => params
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs (String uri, Integer version) -> bool
|
|
27
|
+
def stale_publication?(uri, version)
|
|
28
|
+
path = workspace.path(uri)
|
|
29
|
+
store.snapshot_for(path)&.fetch(:version) != version
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @rbs (untyped value) -> Hash[String, untyped]
|
|
33
|
+
def params_hash(value)
|
|
34
|
+
return {} if value.nil?
|
|
35
|
+
return value if value.is_a?(Hash)
|
|
36
|
+
|
|
37
|
+
raise ProtocolError.new("params must be an object", code: -32_602)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @rbs (Hash[String, untyped] value, String name) -> Hash[String, untyped]
|
|
41
|
+
def hash_member(value, name)
|
|
42
|
+
member = value[name]
|
|
43
|
+
return member if member.is_a?(Hash)
|
|
44
|
+
|
|
45
|
+
raise ProtocolError.new("#{name} must be an object", code: -32_602)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @rbs (Hash[String, untyped] value, String name) -> String
|
|
49
|
+
def string_member(value, name)
|
|
50
|
+
member = value[name]
|
|
51
|
+
return member if member.is_a?(String)
|
|
52
|
+
|
|
53
|
+
raise ProtocolError.new("#{name} must be a string", code: -32_602)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @rbs (Hash[String, untyped] value, String name) -> Integer
|
|
57
|
+
def integer_member(value, name)
|
|
58
|
+
member = value[name]
|
|
59
|
+
return member if member.is_a?(Integer)
|
|
60
|
+
|
|
61
|
+
raise ProtocolError.new("#{name} must be an integer", code: -32_602)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @rbs (Symbol state) -> void
|
|
65
|
+
def require_state!(state)
|
|
66
|
+
return if @state == state
|
|
67
|
+
|
|
68
|
+
raise ProtocolError.new("request requires #{state} server state", code: -32_600)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @rbs () -> void
|
|
72
|
+
def require_running!
|
|
73
|
+
require_state!(:running)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @rbs () -> DocumentStore
|
|
77
|
+
def store
|
|
78
|
+
@store || raise(ProtocolError.new("server is not initialized", code: -32_002))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @rbs () -> Workspace
|
|
82
|
+
def workspace
|
|
83
|
+
@workspace || raise(ProtocolError.new("server is not initialized", code: -32_002))
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# Coordinates JSON-RPC lifecycle, request responses, and protocol-safe logging.
|
|
6
|
+
class Server
|
|
7
|
+
include RequestHandlers
|
|
8
|
+
|
|
9
|
+
REQUEST_METHODS = %w[
|
|
10
|
+
initialize shutdown textDocument/definition textDocument/references textDocument/prepareRename
|
|
11
|
+
textDocument/rename textDocument/hover
|
|
12
|
+
].freeze #: Array[String]
|
|
13
|
+
NOTIFICATION_METHODS = %w[
|
|
14
|
+
initialized exit textDocument/didOpen textDocument/didChange textDocument/didSave textDocument/didClose
|
|
15
|
+
$/cancelRequest
|
|
16
|
+
].freeze #: Array[String]
|
|
17
|
+
|
|
18
|
+
# @rbs (stdin: untyped, stdout: untyped, stderr: untyped) -> void
|
|
19
|
+
def initialize(stdin:, stdout:, stderr:)
|
|
20
|
+
@transport = Transport.new(stdin, stdout)
|
|
21
|
+
@stderr = stderr
|
|
22
|
+
@state = :uninitialized
|
|
23
|
+
@exit_requested = false
|
|
24
|
+
@exit_status = nil #: Integer?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @rbs () -> Integer
|
|
28
|
+
def run
|
|
29
|
+
until @exit_requested
|
|
30
|
+
message = read_message
|
|
31
|
+
break unless message
|
|
32
|
+
|
|
33
|
+
process_message(message)
|
|
34
|
+
end
|
|
35
|
+
@exit_status || 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# @rbs () -> Hash[String, untyped]?
|
|
41
|
+
def read_message
|
|
42
|
+
@transport.read_message
|
|
43
|
+
rescue ProtocolError => e
|
|
44
|
+
send_error(nil, e)
|
|
45
|
+
@exit_requested = true if e.fatal
|
|
46
|
+
retry unless e.fatal
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @rbs (Hash[String, untyped] message) -> void
|
|
51
|
+
def process_message(message)
|
|
52
|
+
request_id = safe_request_id(message)
|
|
53
|
+
notification = notification_envelope?(message)
|
|
54
|
+
request_id = validate_envelope(message)
|
|
55
|
+
method = message.fetch("method")
|
|
56
|
+
validate_message_kind!(method, message.key?("id"))
|
|
57
|
+
return if request_id.nil? && method.start_with?("$/")
|
|
58
|
+
|
|
59
|
+
validate_lifecycle!(method)
|
|
60
|
+
result = dispatch(method, message["params"])
|
|
61
|
+
send_result(request_id, result) if request_id
|
|
62
|
+
rescue ProtocolError => e
|
|
63
|
+
notification ? log(e.message) : send_error(request_id, e)
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
error = ProtocolError.new("internal error: #{e.message}", code: -32_603)
|
|
66
|
+
notification ? log(error.message) : send_error(request_id, error)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @rbs (Hash[String, untyped] message) -> (String | Integer)?
|
|
70
|
+
def safe_request_id(message)
|
|
71
|
+
value = message["id"]
|
|
72
|
+
value if valid_request_id?(value)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @rbs (Hash[String, untyped] message) -> bool
|
|
76
|
+
def notification_envelope?(message)
|
|
77
|
+
!message.key?("id") && message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @rbs (String method, bool request) -> void
|
|
81
|
+
def validate_message_kind!(method, request)
|
|
82
|
+
if REQUEST_METHODS.include?(method) && !request
|
|
83
|
+
raise ProtocolError.new("#{method} must be a request", code: -32_600)
|
|
84
|
+
end
|
|
85
|
+
return unless NOTIFICATION_METHODS.include?(method) && request
|
|
86
|
+
|
|
87
|
+
raise ProtocolError.new("#{method} must be a notification", code: -32_600)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @rbs (Hash[String, untyped] message) -> (String | Integer)?
|
|
91
|
+
def validate_envelope(message)
|
|
92
|
+
unless message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
|
|
93
|
+
raise ProtocolError.new("invalid JSON-RPC request", code: -32_600)
|
|
94
|
+
end
|
|
95
|
+
return nil unless message.key?("id")
|
|
96
|
+
|
|
97
|
+
request_id = message["id"]
|
|
98
|
+
unless valid_request_id?(request_id)
|
|
99
|
+
raise ProtocolError.new("request id must be a bounded string or integer", code: -32_600)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
request_id
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @rbs (untyped value) -> bool
|
|
106
|
+
def valid_request_id?(value)
|
|
107
|
+
return false unless value.is_a?(String) || value.is_a?(Integer)
|
|
108
|
+
|
|
109
|
+
value.to_s.bytesize <= Limits::MAX_REQUEST_ID_BYTES
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @rbs (String method) -> void
|
|
113
|
+
def validate_lifecycle!(method)
|
|
114
|
+
return if method == "exit"
|
|
115
|
+
return if @state == :uninitialized && method == "initialize"
|
|
116
|
+
return if @state == :initialized && %w[initialized shutdown].include?(method)
|
|
117
|
+
return if @state == :running
|
|
118
|
+
|
|
119
|
+
code = @state == :uninitialized ? -32_002 : -32_600
|
|
120
|
+
raise ProtocolError.new("request is invalid in #{@state} server state", code: code)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @rbs (String | Integer request_id, untyped result) -> void
|
|
124
|
+
def send_result(request_id, result)
|
|
125
|
+
@transport.write_message("jsonrpc" => "2.0", "id" => request_id, "result" => result)
|
|
126
|
+
rescue ProtocolError => e
|
|
127
|
+
send_error(request_id, e)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @rbs (String | Integer | nil request_id, ProtocolError error) -> void
|
|
131
|
+
def send_error(request_id, error)
|
|
132
|
+
@transport.write_message(
|
|
133
|
+
"jsonrpc" => "2.0", "id" => request_id,
|
|
134
|
+
"error" => { "code" => error.code, "message" => error.message }
|
|
135
|
+
)
|
|
136
|
+
rescue ProtocolError => e
|
|
137
|
+
log(e.message)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @rbs (String message) -> void
|
|
141
|
+
def log(message)
|
|
142
|
+
@stderr.puts(message)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# Answers source navigation and guarded workspace rename operations.
|
|
6
|
+
class SymbolIndex
|
|
7
|
+
IDENTIFIER = /\A[A-Za-z_][A-Za-z0-9_]*\z/ #: Regexp
|
|
8
|
+
RESERVED = %w[
|
|
9
|
+
class fragment include token prechigh preclow left right nonassoc options expect start
|
|
10
|
+
recover sync on_error_reduce convert display type pragma extended rule end
|
|
11
|
+
separated_list separated_nonempty_list
|
|
12
|
+
].freeze #: Array[String]
|
|
13
|
+
|
|
14
|
+
# @rbs (DocumentStore store, String path) -> void
|
|
15
|
+
def initialize(store, path)
|
|
16
|
+
@store = store
|
|
17
|
+
@path = path
|
|
18
|
+
files = store.files_for(path)
|
|
19
|
+
@occurrences, @documents = SymbolIndexBuilder.new(store, files).build
|
|
20
|
+
@snapshot_state = files.to_h do |file|
|
|
21
|
+
snapshot = store.snapshot_for(file)
|
|
22
|
+
[file, snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]]
|
|
23
|
+
end #: Hash[String, Array[untyped]?]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs (String path, Hash[String, untyped] position) -> Array[Hash[String, untyped]]
|
|
27
|
+
def definition(path, position)
|
|
28
|
+
occurrence = occurrence_at(path, position)
|
|
29
|
+
return [] unless occurrence
|
|
30
|
+
return [include_target_location(occurrence)] if occurrence.kind == :include
|
|
31
|
+
|
|
32
|
+
matching(occurrence.key, role: :definition).map { |entry| location(entry) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @rbs (String path, Hash[String, untyped] position, ?include_declaration: bool) ->
|
|
36
|
+
# Array[Hash[String, untyped]]
|
|
37
|
+
def references(path, position, include_declaration: false)
|
|
38
|
+
occurrence = occurrence_at(path, position)
|
|
39
|
+
return [] unless occurrence
|
|
40
|
+
|
|
41
|
+
entries = matching(occurrence.key)
|
|
42
|
+
entries = entries.reject { |entry| entry.role == :definition } unless include_declaration
|
|
43
|
+
entries.map { |entry| location(entry) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
|
|
47
|
+
def prepare_rename(path, position)
|
|
48
|
+
occurrence = renameable_occurrence(path, position)
|
|
49
|
+
{ "range" => range(occurrence), "placeholder" => occurrence.name }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @rbs (String path, Hash[String, untyped] position, String new_name) -> Hash[String, untyped]
|
|
53
|
+
def rename(path, position, new_name)
|
|
54
|
+
ensure_fresh!
|
|
55
|
+
occurrence = renameable_occurrence(path, position)
|
|
56
|
+
validate_new_name(occurrence, new_name)
|
|
57
|
+
entries = matching(occurrence.key)
|
|
58
|
+
validate_unshared(entries)
|
|
59
|
+
validate_nonoverlapping(entries)
|
|
60
|
+
changes = entries.group_by(&:path).transform_values do |path_entries|
|
|
61
|
+
path_entries.sort_by { |entry| entry.span.start_byte }.map do |entry|
|
|
62
|
+
{ "range" => range(entry), "newText" => new_name }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
replacements = changed_sources(entries, new_name)
|
|
66
|
+
unless @store.valid_replacements?(replacements)
|
|
67
|
+
raise ProtocolError.new("rename would make the affected grammar closure invalid", code: -32_602)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
document_changes = changes.sort.map do |changed_path, edits|
|
|
71
|
+
snapshot = @store.snapshot_for(changed_path)
|
|
72
|
+
version = snapshot&.fetch(:open) ? snapshot.fetch(:version) : nil
|
|
73
|
+
{
|
|
74
|
+
"textDocument" => { "uri" => @store.uri_for(changed_path), "version" => version },
|
|
75
|
+
"edits" => edits
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
{ "documentChanges" => document_changes }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @rbs (String path, Hash[String, untyped] position) -> Hash[String, untyped]?
|
|
82
|
+
def hover(path, position)
|
|
83
|
+
occurrence = occurrence_at(path, position)
|
|
84
|
+
return unless occurrence
|
|
85
|
+
|
|
86
|
+
value = hover_value(occurrence)
|
|
87
|
+
return unless value
|
|
88
|
+
|
|
89
|
+
{
|
|
90
|
+
"contents" => { "kind" => "markdown", "value" => value },
|
|
91
|
+
"range" => range(occurrence)
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence?
|
|
98
|
+
def occurrence_at(path, position)
|
|
99
|
+
document = @documents[path]
|
|
100
|
+
return unless document
|
|
101
|
+
|
|
102
|
+
offset = PositionCodec.new(document.source).byte_offset(position)
|
|
103
|
+
candidates = @occurrences.select do |entry|
|
|
104
|
+
entry.path == path && entry.span.start_byte <= offset && offset < entry.span.end_byte
|
|
105
|
+
end
|
|
106
|
+
candidates.min_by { |entry| entry.span.length }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @rbs (Array[untyped] key, ?role: Symbol?) -> Array[SymbolOccurrence]
|
|
110
|
+
def matching(key, role: nil)
|
|
111
|
+
@occurrences.select { |entry| entry.key == key && (!role || entry.role == role) }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
|
|
115
|
+
def location(occurrence)
|
|
116
|
+
{ "uri" => @store.uri_for(occurrence.path), "range" => range(occurrence) }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# @rbs (SymbolOccurrence occurrence) -> Hash[String, untyped]
|
|
120
|
+
def include_target_location(occurrence)
|
|
121
|
+
target = occurrence.data.fetch(:target)
|
|
122
|
+
point = { "line" => 0, "character" => 0 }
|
|
123
|
+
{ "uri" => @store.uri_for(target), "range" => { "start" => point, "end" => point.dup } }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @rbs (SymbolOccurrence occurrence) -> Hash[String, Hash[String, Integer]]
|
|
127
|
+
def range(occurrence)
|
|
128
|
+
document = @documents.fetch(occurrence.path)
|
|
129
|
+
PositionCodec.new(document.source).range(occurrence.span)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @rbs (String path, Hash[String, untyped] position) -> SymbolOccurrence
|
|
133
|
+
def renameable_occurrence(path, position)
|
|
134
|
+
occurrence = occurrence_at(path, position)
|
|
135
|
+
unless occurrence && %i[rule terminal parameter].include?(occurrence.kind) &&
|
|
136
|
+
occurrence.name.match?(IDENTIFIER) && !RESERVED.include?(occurrence.name)
|
|
137
|
+
raise ProtocolError.new("symbol at position cannot be renamed", code: -32_602)
|
|
138
|
+
end
|
|
139
|
+
unless matching(occurrence.key, role: :definition).any?
|
|
140
|
+
raise ProtocolError.new("unresolved symbol cannot be renamed", code: -32_602)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
occurrence
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @rbs (SymbolOccurrence occurrence, String new_name) -> void
|
|
147
|
+
def validate_new_name(occurrence, new_name)
|
|
148
|
+
unless new_name.is_a?(String) && new_name.match?(IDENTIFIER) && !RESERVED.include?(new_name)
|
|
149
|
+
raise ProtocolError.new("new name must be a non-reserved grammar identifier", code: -32_602)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
collision = @occurrences.any? do |entry|
|
|
153
|
+
entry.role == :definition && entry.name == new_name && entry.key != occurrence.key &&
|
|
154
|
+
collision_scope?(entry, occurrence)
|
|
155
|
+
end
|
|
156
|
+
raise ProtocolError.new("rename collides with existing symbol #{new_name}", code: -32_602) if collision
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @rbs (SymbolOccurrence candidate, SymbolOccurrence occurrence) -> bool
|
|
160
|
+
def collision_scope?(candidate, occurrence)
|
|
161
|
+
return candidate.key.take(3) == occurrence.key.take(3) if occurrence.kind == :parameter
|
|
162
|
+
|
|
163
|
+
candidate.kind != :parameter
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# @rbs (Array[SymbolOccurrence] entries) -> void
|
|
167
|
+
def validate_nonoverlapping(entries)
|
|
168
|
+
entries.group_by(&:path).each_value do |path_entries|
|
|
169
|
+
ordered = path_entries.sort_by { |entry| [entry.span.start_byte, entry.span.end_byte] }
|
|
170
|
+
overlap = (1...ordered.length).any? do |index|
|
|
171
|
+
ordered.fetch(index - 1).span.end_byte > ordered.fetch(index).span.start_byte
|
|
172
|
+
end
|
|
173
|
+
raise ProtocolError.new("rename contains overlapping source edits", code: -32_603) if overlap
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @rbs (Array[SymbolOccurrence] entries) -> void
|
|
178
|
+
def validate_unshared(entries)
|
|
179
|
+
return unless entries.any? { |entry| @store.roots_for(entry.path).length > 1 }
|
|
180
|
+
|
|
181
|
+
raise ProtocolError.new("rename affecting a fragment shared by multiple roots is ambiguous", code: -32_602)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @rbs () -> void
|
|
185
|
+
def ensure_fresh!
|
|
186
|
+
stale = @snapshot_state.any? do |path, expected|
|
|
187
|
+
snapshot = @store.snapshot_for(path)
|
|
188
|
+
actual = snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]
|
|
189
|
+
actual != expected
|
|
190
|
+
end
|
|
191
|
+
raise ProtocolError.new("symbol snapshot is stale; retry the request", code: -32_602) if stale
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @rbs (Array[SymbolOccurrence] entries, String new_name) -> Hash[String, String]
|
|
195
|
+
def changed_sources(entries, new_name)
|
|
196
|
+
entries.group_by(&:path).to_h do |path, path_entries|
|
|
197
|
+
document = @documents.fetch(path)
|
|
198
|
+
source = document.source.dup
|
|
199
|
+
path_entries.sort_by { |entry| -entry.span.start_byte }.each do |entry|
|
|
200
|
+
prefix = source.byteslice(0, entry.span.start_byte) || ""
|
|
201
|
+
suffix = source.byteslice(entry.span.end_byte, source.bytesize - entry.span.end_byte) || ""
|
|
202
|
+
source = prefix + new_name + suffix
|
|
203
|
+
end
|
|
204
|
+
[path, source]
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# @rbs (SymbolOccurrence occurrence) -> String?
|
|
209
|
+
def hover_value(occurrence)
|
|
210
|
+
case occurrence.kind
|
|
211
|
+
when :rule then rule_hover(occurrence)
|
|
212
|
+
when :terminal then terminal_hover(occurrence)
|
|
213
|
+
when :parameter then "`#{occurrence.name}` — formal parameter of `#{occurrence.data[:rule]}`"
|
|
214
|
+
when :include then "Includes `#{occurrence.data[:target]}`"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# @rbs (SymbolOccurrence occurrence) -> String
|
|
219
|
+
def rule_hover(occurrence)
|
|
220
|
+
definition = matching(occurrence.key, role: :definition).first
|
|
221
|
+
data = definition&.data || occurrence.data
|
|
222
|
+
lines = ["```ibex", data[:signature] || occurrence.name, "```"]
|
|
223
|
+
lines << data[:documentation] if data[:documentation]
|
|
224
|
+
lines.join("\n")
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# @rbs (SymbolOccurrence occurrence) -> String
|
|
228
|
+
def terminal_hover(occurrence)
|
|
229
|
+
definition = matching(occurrence.key, role: :definition).first
|
|
230
|
+
data = definition&.data || occurrence.data
|
|
231
|
+
lines = ["`#{occurrence.name}` — terminal"]
|
|
232
|
+
lines << "Display: #{data[:display]}" if data[:display]
|
|
233
|
+
lines << "Type: `#{data[:type]}`" if data[:type]
|
|
234
|
+
if (precedence = data[:precedence])
|
|
235
|
+
lines << "Precedence: #{precedence[:associativity]} level #{precedence[:level]}"
|
|
236
|
+
end
|
|
237
|
+
lines.join("\n\n")
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|