ibex 0.1.0 → 0.3.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 +89 -123
- data/docs/architecture.md +477 -31
- data/docs/bison-import.md +103 -0
- data/docs/comparison-policy.md +127 -0
- data/docs/configuration-model.md +59 -0
- data/docs/configuration-report.md +28 -0
- data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
- data/docs/conflict-explanation-study.md +62 -0
- data/docs/construction-profiling.md +157 -0
- data/docs/cst-migration.md +106 -0
- data/docs/cst.md +237 -0
- data/docs/decisions/0000-template.md +24 -0
- data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
- data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
- data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
- data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
- data/docs/decisions/0005-contained-grammar-composition.md +34 -0
- data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
- data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
- data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
- data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
- data/docs/decisions/0010-committed-runtime-observation.md +34 -0
- data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
- data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
- data/docs/decisions/0013-transactional-generation-publication.md +37 -0
- data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
- data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
- data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
- data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
- data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
- data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
- data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
- data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
- data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
- data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
- data/docs/decisions/0024-direct-ielr-construction.md +42 -0
- data/docs/decisions/README.md +74 -0
- data/docs/declarative-configuration.md +262 -0
- data/docs/development.md +306 -0
- data/docs/direct-ielr-decision.md +120 -0
- data/docs/direct-multi-entry-decision.md +82 -0
- data/docs/editor-setup.md +26 -0
- data/docs/error-ux-review-rubric-v1.md +117 -0
- data/docs/error-ux-reviews/v1/records/README.md +22 -0
- data/docs/error-ux-round2-review-status-v1.json +27 -0
- data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
- data/docs/error-ux-round2-v1.json +1581 -0
- data/docs/error-ux-round2.md +111 -0
- data/docs/error-ux.md +114 -0
- data/docs/getting-started.md +80 -0
- data/docs/grammar-reference.md +629 -18
- data/docs/ielr-design.md +43 -0
- data/docs/ielr.md +92 -0
- data/docs/ja/bison-import.md +51 -0
- data/docs/ja/stable-api.md +53 -0
- data/docs/lexer-construction-profile.md +109 -0
- data/docs/lexer-migration.md +56 -0
- data/docs/maturity.md +128 -0
- data/docs/project-site-strategy.md +54 -0
- data/docs/racc-migration-evidence.md +45 -0
- data/docs/racc-migration.md +45 -6
- data/docs/release-readiness.md +221 -0
- data/docs/repair-semantics.md +123 -0
- data/docs/runtime-abi-evolution.md +307 -0
- data/docs/stability.md +234 -0
- data/docs/status.md +43 -0
- data/docs/syntax-sessions.md +183 -0
- data/docs/table-artifact.md +125 -0
- data/docs/test-interactions.md +219 -0
- data/docs/verification-report.md +137 -0
- data/docs/verifier-trust-boundary.md +199 -0
- data/docs/workloads.md +132 -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/digraph.rb +128 -0
- data/lib/ibex/analysis/sets.rb +5 -4
- data/lib/ibex/analysis.rb +1 -0
- data/lib/ibex/artifact_set.rb +63 -0
- data/lib/ibex/bison_import/importer.rb +516 -0
- data/lib/ibex/bison_import/tokenizer.rb +260 -0
- data/lib/ibex/bison_import.rb +200 -0
- data/lib/ibex/bounded_subprocess.rb +171 -0
- data/lib/ibex/cli/ambiguity.rb +75 -0
- data/lib/ibex/cli/analysis.rb +134 -0
- data/lib/ibex/cli/bison_import.rb +121 -0
- data/lib/ibex/cli/config.rb +128 -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 +136 -0
- data/lib/ibex/cli/documentation.rb +70 -0
- data/lib/ibex/cli/equiv.rb +169 -0
- data/lib/ibex/cli/error_messages.rb +184 -0
- data/lib/ibex/cli/explain.rb +85 -0
- data/lib/ibex/cli/fix.rb +203 -0
- data/lib/ibex/cli/formatting.rb +387 -0
- data/lib/ibex/cli/fuzz.rb +200 -0
- data/lib/ibex/cli/fuzz_regressions.rb +145 -0
- data/lib/ibex/cli/generation_artifacts.rb +189 -0
- data/lib/ibex/cli/generation_error_messages.rb +39 -0
- data/lib/ibex/cli/grammar_tests.rb +140 -0
- data/lib/ibex/cli/ir_tools.rb +128 -0
- data/lib/ibex/cli/lsp.rb +33 -0
- data/lib/ibex/cli/outputs.rb +133 -23
- data/lib/ibex/cli/racc_migration.rb +87 -0
- data/lib/ibex/cli/reduce.rb +202 -0
- data/lib/ibex/cli/reduce_reporting.rb +71 -0
- data/lib/ibex/cli/samples.rb +118 -0
- data/lib/ibex/cli/verify.rb +116 -0
- data/lib/ibex/cli/watch.rb +104 -0
- data/lib/ibex/cli.rb +825 -55
- data/lib/ibex/codegen/action_locations.rb +103 -0
- data/lib/ibex/codegen/action_method_source.rb +209 -0
- data/lib/ibex/codegen/action_source.rb +119 -0
- data/lib/ibex/codegen/ambiguity.rb +174 -0
- data/lib/ibex/codegen/cst_metadata.rb +171 -0
- data/lib/ibex/codegen/documentation.rb +170 -0
- data/lib/ibex/codegen/explain.rb +380 -0
- data/lib/ibex/codegen/generated_action_abi.rb +293 -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 +331 -2
- data/lib/ibex/codegen/report.rb +67 -15
- data/lib/ibex/codegen/ruby.rb +305 -66
- data/lib/ibex/codegen/ruby_actions.rb +146 -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 +96 -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/configuration/analysis_grammar.rb +35 -0
- data/lib/ibex/configuration/explanation.rb +421 -0
- data/lib/ibex/configuration/inspector.rb +232 -0
- data/lib/ibex/configuration.rb +580 -0
- data/lib/ibex/coverage/collector.rb +198 -0
- data/lib/ibex/coverage/event_stream.rb +103 -0
- data/lib/ibex/coverage/report.rb +267 -0
- data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
- data/lib/ibex/coverage.rb +13 -0
- data/lib/ibex/delta_reducer.rb +99 -0
- data/lib/ibex/diff.rb +140 -0
- data/lib/ibex/equiv/machine.rb +135 -0
- data/lib/ibex/equiv.rb +373 -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/fix.rb +557 -0
- data/lib/ibex/frontend/ast.rb +166 -7
- data/lib/ibex/frontend/bootstrap_parser.rb +40 -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 +453 -0
- data/lib/ibex/frontend/generated_parser.rb +644 -190
- data/lib/ibex/frontend/generated_parser_base.rb +170 -32
- data/lib/ibex/frontend/generated_parser_includes.rb +51 -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 +262 -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/parser_configuration_support.rb +56 -0
- data/lib/ibex/frontend/regenerator.rb +27 -1
- data/lib/ibex/frontend/resolution.rb +70 -0
- data/lib/ibex/frontend/resolver.rb +217 -0
- data/lib/ibex/frontend/rule_documentation.rb +104 -0
- data/lib/ibex/frontend/source_cursor.rb +133 -9
- 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 +89 -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 +244 -22
- 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 +18 -3
- data/lib/ibex/frontend.rb +14 -2
- data/lib/ibex/fuzz.rb +219 -0
- data/lib/ibex/generation_input.rb +57 -0
- data/lib/ibex/generation_manifest.rb +211 -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 +86 -11
- data/lib/ibex/ir/grammar_ir.rb +170 -26
- data/lib/ibex/ir/lexer_ir.rb +76 -0
- data/lib/ibex/ir/parser_contract.rb +135 -0
- data/lib/ibex/ir/serialize.rb +268 -50
- data/lib/ibex/ir/validator/automaton.rb +375 -0
- data/lib/ibex/ir/validator/base.rb +147 -0
- data/lib/ibex/ir/validator/grammar.rb +634 -0
- data/lib/ibex/ir/validator/lexer.rb +113 -0
- data/lib/ibex/ir/validator.rb +63 -0
- data/lib/ibex/ir.rb +71 -5
- data/lib/ibex/lalr/build_metrics.rb +71 -0
- data/lib/ibex/lalr/builder.rb +514 -52
- data/lib/ibex/lalr/conflict.rb +1 -0
- data/lib/ibex/lalr/conflict_search.rb +26 -9
- data/lib/ibex/lalr/counterexample.rb +38 -18
- data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
- data/lib/ibex/lalr/goto_follows.rb +229 -0
- data/lib/ibex/lalr/ielr/annotator.rb +214 -0
- data/lib/ibex/lalr/ielr/bits.rb +28 -0
- data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
- data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
- data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
- data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
- data/lib/ibex/lalr/ielr/split_state.rb +20 -0
- data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
- data/lib/ibex/lalr/ielr_partition.rb +166 -0
- data/lib/ibex/lalr/inadequacy_report.rb +50 -0
- data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
- data/lib/ibex/lalr/lr0_collection.rb +121 -0
- data/lib/ibex/lalr/on_error_reductions.rb +74 -0
- data/lib/ibex/lalr/unreachable_states.rb +80 -0
- data/lib/ibex/lalr.rb +59 -1
- data/lib/ibex/location.rb +129 -0
- data/lib/ibex/lsp/document_handlers.rb +68 -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 +80 -0
- data/lib/ibex/lsp/navigation_handlers.rb +70 -0
- data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
- data/lib/ibex/lsp/position_codec.rb +113 -0
- data/lib/ibex/lsp/protocol_error.rb +33 -0
- data/lib/ibex/lsp/request_handlers.rb +46 -0
- data/lib/ibex/lsp/request_support.rb +94 -0
- data/lib/ibex/lsp/server.rb +148 -0
- data/lib/ibex/lsp/symbol_index.rb +241 -0
- data/lib/ibex/lsp/symbol_index_builder.rb +277 -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 +23 -0
- data/lib/ibex/lsp/transport.rb +128 -0
- data/lib/ibex/lsp/workspace.rb +128 -0
- data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
- data/lib/ibex/lsp.rb +33 -0
- data/lib/ibex/messages/en.yml +28 -0
- data/lib/ibex/messages/ja.yml +28 -0
- data/lib/ibex/messages.rb +68 -0
- data/lib/ibex/metrics.rb +175 -0
- data/lib/ibex/normalize/declarations.rb +142 -7
- data/lib/ibex/normalize/diagnostics.rb +94 -24
- data/lib/ibex/normalize/expander.rb +64 -59
- data/lib/ibex/normalize/expression.rb +63 -40
- data/lib/ibex/normalize/grammar_builder.rb +26 -0
- data/lib/ibex/normalize/inline_expansion.rb +465 -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 +70 -0
- data/lib/ibex/normalize/parameter_lowering.rb +143 -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 +226 -0
- data/lib/ibex/normalize/parser_configuration.rb +70 -0
- data/lib/ibex/normalize/recovery_declarations.rb +84 -0
- data/lib/ibex/normalize.rb +172 -17
- 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 +97 -0
- data/lib/ibex/racc_migration.rb +12 -0
- data/lib/ibex/rake_task.rb +116 -0
- data/lib/ibex/samples.rb +216 -0
- data/lib/ibex/table_artifact/builder.rb +266 -0
- data/lib/ibex/table_artifact/cst_projection.rb +70 -0
- data/lib/ibex/table_artifact/document.rb +39 -0
- data/lib/ibex/table_artifact/executor.rb +187 -0
- data/lib/ibex/table_artifact/serializer.rb +57 -0
- data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
- data/lib/ibex/table_artifact/validator/support.rb +86 -0
- data/lib/ibex/table_artifact/validator/tables.rb +238 -0
- data/lib/ibex/table_artifact/validator.rb +253 -0
- data/lib/ibex/table_artifact.rb +88 -0
- data/lib/ibex/table_simulation/result.rb +55 -0
- data/lib/ibex/table_simulation/simulator.rb +253 -0
- data/lib/ibex/table_simulation/step.rb +62 -0
- data/lib/ibex/table_simulation/text.rb +31 -0
- data/lib/ibex/table_simulation.rb +13 -0
- data/lib/ibex/tables.rb +22 -69
- data/lib/ibex/verifiable_generation_bundle.rb +86 -0
- data/lib/ibex/verification_report/builder.rb +159 -0
- data/lib/ibex/verification_report/canonical_ir.rb +123 -0
- data/lib/ibex/verification_report/logical_path.rb +68 -0
- data/lib/ibex/verification_report/validator.rb +329 -0
- data/lib/ibex/verification_report.rb +69 -0
- data/lib/ibex/verify/action_correspondence.rb +138 -0
- data/lib/ibex/verify/language_witness.rb +295 -0
- data/lib/ibex/verify/reference_collection.rb +190 -0
- data/lib/ibex/verify/result.rb +73 -0
- data/lib/ibex/verify/verifier.rb +598 -0
- data/lib/ibex/verify.rb +15 -0
- data/lib/ibex/version.rb +1 -1
- data/lib/ibex/watch/runner.rb +181 -0
- data/lib/ibex/watch/source_snapshot.rb +98 -0
- data/lib/ibex/watch.rb +11 -0
- data/lib/ibex.rb +35 -1
- data/schema/automaton-ir-definitions.schema.json +401 -0
- data/schema/automaton-ir.schema.json +65 -0
- data/schema/benchmark-v1.schema.json +212 -0
- data/schema/benchmark-v2.schema.json +61 -0
- data/schema/bison-import-v1.schema.json +106 -0
- data/schema/conflict-explanation-review-v1.schema.json +196 -0
- data/schema/conflict-explanation-study-v1.schema.json +528 -0
- data/schema/construction-profile-v1.schema.json +779 -0
- data/schema/cst-v1.json +170 -0
- data/schema/diff-v1.schema.json +41 -0
- data/schema/direct-ielr-decision-v1.schema.json +200 -0
- data/schema/equiv-v1.schema.json +64 -0
- data/schema/error-ux-review-v1.schema.json +609 -0
- data/schema/error-ux-round2-review-v1.schema.json +191 -0
- data/schema/error-ux-round2-v1.schema.json +519 -0
- data/schema/error-ux-v1.schema.json +258 -0
- data/schema/explain-v1.schema.json +495 -0
- data/schema/fix-v1.schema.json +64 -0
- data/schema/fix-v2.schema.json +66 -0
- data/schema/fix-v3.schema.json +101 -0
- data/schema/frontend-diagnostics-v1.schema.json +154 -0
- data/schema/fuzz-regression-v1.schema.json +79 -0
- data/schema/fuzz-v1.schema.json +114 -0
- data/schema/generation-manifest-v1.schema.json +115 -0
- data/schema/grammar-ir-extensions.schema.json +734 -0
- data/schema/grammar-ir-foundation.schema.json +426 -0
- data/schema/grammar-ir.schema.json +271 -0
- data/schema/ielr-benchmark-v1.schema.json +85 -0
- data/schema/lexer-ir-v1.schema.json +215 -0
- data/schema/lexer-profile-v1.schema.json +491 -0
- data/schema/metrics-v1.schema.json +60 -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/reduce-v1.schema.json +22 -0
- data/schema/reduce-v2.schema.json +63 -0
- data/schema/runtime-coverage-v1.schema.json +86 -0
- data/schema/runtime-event-v1.schema.json +308 -0
- data/schema/table-artifact-v1.schema.json +377 -0
- data/schema/table-simulation-v1.schema.json +70 -0
- data/schema/verification-report-v1.schema.json +222 -0
- data/schema/verify-v1.schema.json +42 -0
- data/sig/ibex/analysis/digraph.rbs +19 -0
- data/sig/ibex/artifact_set.rbs +37 -0
- data/sig/ibex/bison_import/importer.rbs +140 -0
- data/sig/ibex/bison_import/tokenizer.rbs +91 -0
- data/sig/ibex/bison_import.rbs +95 -0
- data/sig/ibex/bounded_subprocess.rbs +76 -0
- data/sig/ibex/cli/ambiguity.rbs +28 -0
- data/sig/ibex/cli/analysis.rbs +43 -0
- data/sig/ibex/cli/bison_import.rbs +32 -0
- data/sig/ibex/cli/config.rbs +35 -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 +51 -0
- data/sig/ibex/cli/documentation.rbs +29 -0
- data/sig/ibex/cli/equiv.rbs +49 -0
- data/sig/ibex/cli/error_messages.rbs +63 -0
- data/sig/ibex/cli/explain.rbs +31 -0
- data/sig/ibex/cli/fix.rbs +53 -0
- data/sig/ibex/cli/formatting.rbs +107 -0
- data/sig/ibex/cli/fuzz.rbs +47 -0
- data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
- data/sig/ibex/cli/generation_artifacts.rbs +69 -0
- data/sig/ibex/cli/generation_error_messages.rbs +19 -0
- data/sig/ibex/cli/grammar_tests.rbs +48 -0
- data/sig/ibex/cli/ir_tools.rbs +39 -0
- data/sig/ibex/cli/lsp.rbs +14 -0
- data/sig/ibex/cli/outputs.rbs +26 -3
- data/sig/ibex/cli/racc_migration.rbs +30 -0
- data/sig/ibex/cli/reduce.rbs +60 -0
- data/sig/ibex/cli/reduce_reporting.rbs +27 -0
- data/sig/ibex/cli/samples.rbs +38 -0
- data/sig/ibex/cli/verify.rbs +28 -0
- data/sig/ibex/cli/watch.rbs +43 -0
- data/sig/ibex/cli.rbs +182 -9
- 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 +105 -0
- data/sig/ibex/codegen/generated_action_abi.rbs +105 -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 +86 -4
- data/sig/ibex/codegen/report.rbs +16 -8
- data/sig/ibex/codegen/ruby.rbs +105 -28
- 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 +27 -0
- data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
- data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
- data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
- data/sig/ibex/configuration/explanation.rbs +195 -0
- data/sig/ibex/configuration/inspector.rbs +53 -0
- data/sig/ibex/configuration.rbs +242 -0
- data/sig/ibex/coverage/collector.rbs +78 -0
- data/sig/ibex/coverage/event_stream.rbs +44 -0
- data/sig/ibex/coverage/report.rbs +102 -0
- data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
- data/sig/ibex/coverage.rbs +7 -0
- data/sig/ibex/delta_reducer.rbs +38 -0
- data/sig/ibex/diff.rbs +47 -0
- data/sig/ibex/equiv/machine.rbs +54 -0
- data/sig/ibex/equiv.rbs +129 -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/fix.rbs +138 -0
- data/sig/ibex/frontend/ast.rbs +237 -22
- data/sig/ibex/frontend/bootstrap_parser.rbs +13 -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 +143 -0
- data/sig/ibex/frontend/generated_parser.rbs +228 -68
- data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
- 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 +57 -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/parser_configuration_support.rbs +27 -0
- data/sig/ibex/frontend/regenerator.rbs +11 -0
- data/sig/ibex/frontend/resolution.rbs +34 -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 +38 -5
- 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 +56 -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 +83 -3
- data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
- data/sig/ibex/frontend/token_adapter.rbs +11 -2
- data/sig/ibex/frontend.rbs +1 -1
- data/sig/ibex/fuzz.rbs +71 -0
- data/sig/ibex/generation_input.rbs +37 -0
- data/sig/ibex/generation_manifest.rbs +70 -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 +35 -10
- data/sig/ibex/ir/grammar_ir.rbs +96 -22
- data/sig/ibex/ir/lexer_ir.rbs +57 -0
- data/sig/ibex/ir/parser_contract.rbs +69 -0
- data/sig/ibex/ir/serialize.rbs +75 -23
- data/sig/ibex/ir/validator/automaton.rbs +112 -0
- data/sig/ibex/ir/validator/base.rbs +69 -0
- data/sig/ibex/ir/validator/grammar.rbs +195 -0
- data/sig/ibex/ir/validator/lexer.rbs +37 -0
- data/sig/ibex/ir/validator.rbs +16 -0
- data/sig/ibex/ir.rbs +45 -5
- data/sig/ibex/lalr/build_metrics.rbs +60 -0
- data/sig/ibex/lalr/builder.rbs +150 -19
- data/sig/ibex/lalr/conflict_search.rbs +12 -5
- data/sig/ibex/lalr/counterexample.rbs +20 -14
- data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
- data/sig/ibex/lalr/goto_follows.rbs +89 -0
- data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
- data/sig/ibex/lalr/ielr/bits.rbs +14 -0
- data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
- data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
- data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
- data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
- data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
- data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
- data/sig/ibex/lalr/ielr_partition.rbs +71 -0
- data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
- data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
- data/sig/ibex/lalr/lr0_collection.rbs +50 -0
- data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
- data/sig/ibex/lalr/unreachable_states.rbs +25 -0
- data/sig/ibex/lalr.rbs +17 -1
- 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 +33 -0
- data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
- data/sig/ibex/lsp/position_codec.rbs +44 -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 +77 -0
- data/sig/ibex/lsp/symbol_index_builder.rbs +88 -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 +31 -0
- data/sig/ibex/lsp/transport.rbs +47 -0
- data/sig/ibex/lsp/workspace.rbs +42 -0
- data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
- data/sig/ibex/lsp.rbs +7 -0
- data/sig/ibex/messages.rbs +26 -0
- data/sig/ibex/metrics.rbs +50 -0
- data/sig/ibex/normalize/declarations.rbs +31 -0
- data/sig/ibex/normalize/diagnostics.rbs +13 -4
- data/sig/ibex/normalize/expander.rbs +22 -16
- data/sig/ibex/normalize/expression.rbs +11 -9
- data/sig/ibex/normalize/grammar_builder.rbs +11 -0
- data/sig/ibex/normalize/inline_expansion.rbs +129 -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 +33 -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 +51 -0
- data/sig/ibex/normalize/parser_configuration.rbs +23 -0
- data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
- data/sig/ibex/normalize.rbs +129 -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 +55 -0
- data/sig/ibex/racc_migration.rbs +8 -0
- data/sig/ibex/rake_task.rbs +51 -0
- data/sig/ibex/samples.rbs +60 -0
- data/sig/ibex/table_artifact/builder.rbs +93 -0
- data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
- data/sig/ibex/table_artifact/document.rbs +27 -0
- data/sig/ibex/table_artifact/executor.rbs +66 -0
- data/sig/ibex/table_artifact/serializer.rbs +25 -0
- data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
- data/sig/ibex/table_artifact/validator/support.rbs +46 -0
- data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
- data/sig/ibex/table_artifact/validator.rbs +66 -0
- data/sig/ibex/table_artifact.rbs +32 -0
- data/sig/ibex/table_simulation/result.rbs +36 -0
- data/sig/ibex/table_simulation/simulator.rbs +98 -0
- data/sig/ibex/table_simulation/step.rbs +42 -0
- data/sig/ibex/table_simulation/text.rbs +14 -0
- data/sig/ibex/table_simulation.rbs +7 -0
- data/sig/ibex/tables.rbs +10 -35
- data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
- data/sig/ibex/verification_report/builder.rbs +53 -0
- data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
- data/sig/ibex/verification_report/logical_path.rbs +34 -0
- data/sig/ibex/verification_report/validator.rbs +114 -0
- data/sig/ibex/verification_report.rbs +44 -0
- data/sig/ibex/verify/action_correspondence.rbs +50 -0
- data/sig/ibex/verify/language_witness.rbs +112 -0
- data/sig/ibex/verify/reference_collection.rbs +63 -0
- data/sig/ibex/verify/result.rbs +52 -0
- data/sig/ibex/verify/verifier.rbs +170 -0
- data/sig/ibex/verify.rbs +6 -0
- data/sig/ibex/watch/runner.rbs +58 -0
- data/sig/ibex/watch/source_snapshot.rbs +46 -0
- data/sig/ibex/watch.rbs +7 -0
- data/sig/ibex.rbs +2 -0
- metadata +524 -19
- 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,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# @rbs!
|
|
6
|
+
# type lsp_value = String | Integer | Float | bool | nil | Array[lsp_value] | Hash[String, lsp_value]
|
|
7
|
+
# type lsp_object = Hash[String, lsp_value]
|
|
8
|
+
|
|
9
|
+
# Converts between frontend byte offsets and zero-based LSP UTF-16 positions.
|
|
10
|
+
class PositionCodec
|
|
11
|
+
# @rbs (String source) -> void
|
|
12
|
+
def initialize(source)
|
|
13
|
+
@source = Frontend::SourceEncoding.validated_utf8(source, "(lsp)")
|
|
14
|
+
@line_starts = build_line_starts.freeze #: Array[Integer]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @rbs (Integer byte_offset) -> Hash[String, Integer]
|
|
18
|
+
def position(byte_offset)
|
|
19
|
+
validate_byte_offset(byte_offset)
|
|
20
|
+
prefix = @source.byteslice(0, byte_offset) || ""
|
|
21
|
+
raise ArgumentError, "byte offset is not on a UTF-8 character boundary" unless prefix.valid_encoding?
|
|
22
|
+
|
|
23
|
+
line = (@line_starts.bsearch_index { |start| start > byte_offset } || @line_starts.length) - 1
|
|
24
|
+
line_start = @line_starts.fetch(line)
|
|
25
|
+
line_end = content_end(line)
|
|
26
|
+
raise ArgumentError, "byte offset points inside a line ending" if byte_offset > line_end
|
|
27
|
+
|
|
28
|
+
text = @source.byteslice(line_start, byte_offset - line_start) || ""
|
|
29
|
+
{ "line" => line, "character" => utf16_length(text) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @rbs (lsp_object position) -> Integer
|
|
33
|
+
def byte_offset(position)
|
|
34
|
+
line = integer_member(position, "line")
|
|
35
|
+
character = integer_member(position, "character")
|
|
36
|
+
raise ArgumentError, "line and character must be non-negative" if line.negative? || character.negative?
|
|
37
|
+
|
|
38
|
+
line_start = @line_starts[line]
|
|
39
|
+
raise ArgumentError, "line is outside the document" unless line_start
|
|
40
|
+
|
|
41
|
+
text = @source.byteslice(line_start, content_end(line) - line_start) || ""
|
|
42
|
+
line_start + byte_length_at_utf16(text, character)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @rbs (Frontend::SourceSpan span) -> Hash[String, Hash[String, Integer]]
|
|
46
|
+
def range(span)
|
|
47
|
+
{ "start" => position(span.start_byte), "end" => position(span.end_byte) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# @rbs () -> Array[Integer]
|
|
53
|
+
def build_line_starts
|
|
54
|
+
starts = [0]
|
|
55
|
+
offset = 0
|
|
56
|
+
@source.each_char do |character|
|
|
57
|
+
offset += character.bytesize
|
|
58
|
+
starts << offset if character == "\n"
|
|
59
|
+
end
|
|
60
|
+
starts
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @rbs (Integer line) -> Integer
|
|
64
|
+
def content_end(line)
|
|
65
|
+
boundary = @line_starts[line + 1] || @source.bytesize
|
|
66
|
+
return boundary unless @line_starts[line + 1]
|
|
67
|
+
|
|
68
|
+
before_newline = boundary - 1
|
|
69
|
+
@source.getbyte(before_newline - 1) == 13 ? before_newline - 1 : before_newline
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @rbs (String text) -> Integer
|
|
73
|
+
def utf16_length(text)
|
|
74
|
+
text.each_codepoint.sum { |codepoint| codepoint > 0xFFFF ? 2 : 1 }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @rbs (String text, Integer units) -> Integer
|
|
78
|
+
def byte_length_at_utf16(text, units)
|
|
79
|
+
consumed_units = 0
|
|
80
|
+
consumed_bytes = 0
|
|
81
|
+
text.each_char do |character|
|
|
82
|
+
return consumed_bytes if consumed_units == units
|
|
83
|
+
|
|
84
|
+
width = character.ord > 0xFFFF ? 2 : 1
|
|
85
|
+
if consumed_units + width > units
|
|
86
|
+
raise ArgumentError, "character points into the middle of a UTF-16 surrogate pair"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
consumed_units += width
|
|
90
|
+
consumed_bytes += character.bytesize
|
|
91
|
+
end
|
|
92
|
+
return consumed_bytes if consumed_units == units
|
|
93
|
+
|
|
94
|
+
raise ArgumentError, "character is outside the document line"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @rbs (lsp_object position, String name) -> Integer
|
|
98
|
+
def integer_member(position, name)
|
|
99
|
+
value = position[name]
|
|
100
|
+
raise ArgumentError, "#{name} must be an integer" unless value.is_a?(Integer)
|
|
101
|
+
|
|
102
|
+
value
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @rbs (Integer byte_offset) -> void
|
|
106
|
+
def validate_byte_offset(byte_offset)
|
|
107
|
+
return if byte_offset.is_a?(Integer) && byte_offset.between?(0, @source.bytesize)
|
|
108
|
+
|
|
109
|
+
raise ArgumentError, "byte offset is outside the document"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# Resource bounds shared by transport and open-document validation.
|
|
6
|
+
module Limits
|
|
7
|
+
MAX_HEADER_BYTES = 16 * 1024
|
|
8
|
+
MAX_MESSAGE_BYTES = 1024 * 1024
|
|
9
|
+
MAX_DOCUMENT_BYTES = 2 * 1024 * 1024
|
|
10
|
+
MAX_OUTPUT_BYTES = 1024 * 1024
|
|
11
|
+
MAX_ERROR_MESSAGE_CHARACTERS = 1024
|
|
12
|
+
MAX_REQUEST_ID_BYTES = 256
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Bounded protocol and workspace failures with their JSON-RPC error code.
|
|
16
|
+
class ProtocolError < Ibex::Error
|
|
17
|
+
attr_reader :code #: Integer
|
|
18
|
+
attr_reader :request_id #: String | Integer | nil
|
|
19
|
+
attr_reader :fatal #: bool
|
|
20
|
+
|
|
21
|
+
# @rbs (String message, ?code: Integer, ?request_id: String | Integer | nil, ?fatal: bool) -> void
|
|
22
|
+
def initialize(message, code: -32_600, request_id: nil, fatal: false)
|
|
23
|
+
normalized = message.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
|
24
|
+
bounded = normalized[0, Limits::MAX_ERROR_MESSAGE_CHARACTERS] || ""
|
|
25
|
+
bounded += "…" if bounded.length < normalized.length
|
|
26
|
+
super("(lsp):1:1: #{bounded}")
|
|
27
|
+
@code = code
|
|
28
|
+
@request_id = request_id
|
|
29
|
+
@fatal = fatal
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibex
|
|
4
|
+
module LSP
|
|
5
|
+
# Dispatches the finite LSP surface to focused lifecycle, document, and navigation handlers.
|
|
6
|
+
module RequestHandlers
|
|
7
|
+
include InitializationHandlers
|
|
8
|
+
include DocumentHandlers
|
|
9
|
+
include NavigationHandlers
|
|
10
|
+
include RequestSupport
|
|
11
|
+
|
|
12
|
+
HANDLERS = {
|
|
13
|
+
"initialize" => :initialize_workspace,
|
|
14
|
+
"initialized" => :initialized_notification,
|
|
15
|
+
"shutdown" => :shutdown_request,
|
|
16
|
+
"exit" => :exit_notification,
|
|
17
|
+
"textDocument/didOpen" => :did_open,
|
|
18
|
+
"textDocument/didChange" => :did_change,
|
|
19
|
+
"textDocument/didSave" => :did_save,
|
|
20
|
+
"textDocument/didClose" => :did_close,
|
|
21
|
+
"textDocument/definition" => :definition,
|
|
22
|
+
"textDocument/references" => :references,
|
|
23
|
+
"textDocument/prepareRename" => :prepare_rename,
|
|
24
|
+
"textDocument/rename" => :rename,
|
|
25
|
+
"textDocument/hover" => :hover,
|
|
26
|
+
"textDocument/completion" => :completion,
|
|
27
|
+
"$/cancelRequest" => :cancel_request
|
|
28
|
+
}.freeze #: Hash[String, Symbol]
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @rbs (String method, lsp_value? params) -> lsp_value?
|
|
33
|
+
def dispatch(method, params)
|
|
34
|
+
handler = HANDLERS[method]
|
|
35
|
+
raise ProtocolError.new("method not found: #{method}", code: -32_601) unless handler
|
|
36
|
+
|
|
37
|
+
send(handler, params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @rbs (lsp_value? params) -> nil
|
|
41
|
+
def cancel_request(_params)
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
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
|
+
} #: lsp_object
|
|
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 (lsp_value? value) -> lsp_object
|
|
33
|
+
def params_hash(value)
|
|
34
|
+
return {} if value.nil?
|
|
35
|
+
|
|
36
|
+
if value.is_a?(Hash)
|
|
37
|
+
result = value #: lsp_object
|
|
38
|
+
return result
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
raise ProtocolError.new("params must be an object", code: -32_602)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @rbs (lsp_object value, String name) -> lsp_object
|
|
45
|
+
def hash_member(value, name)
|
|
46
|
+
member = value[name]
|
|
47
|
+
if member.is_a?(Hash)
|
|
48
|
+
result = member #: lsp_object
|
|
49
|
+
return result
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
raise ProtocolError.new("#{name} must be an object", code: -32_602)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @rbs (lsp_object value, String name) -> String
|
|
56
|
+
def string_member(value, name)
|
|
57
|
+
member = value[name]
|
|
58
|
+
return member if member.is_a?(String)
|
|
59
|
+
|
|
60
|
+
raise ProtocolError.new("#{name} must be a string", code: -32_602)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @rbs (lsp_object value, String name) -> Integer
|
|
64
|
+
def integer_member(value, name)
|
|
65
|
+
member = value[name]
|
|
66
|
+
return member if member.is_a?(Integer)
|
|
67
|
+
|
|
68
|
+
raise ProtocolError.new("#{name} must be an integer", code: -32_602)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @rbs (Symbol state) -> void
|
|
72
|
+
def require_state!(state)
|
|
73
|
+
return if @state == state
|
|
74
|
+
|
|
75
|
+
raise ProtocolError.new("request requires #{state} server state", code: -32_600)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @rbs () -> void
|
|
79
|
+
def require_running!
|
|
80
|
+
require_state!(:running)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @rbs () -> DocumentStore
|
|
84
|
+
def store
|
|
85
|
+
@store || raise(ProtocolError.new("server is not initialized", code: -32_002))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @rbs () -> Workspace
|
|
89
|
+
def workspace
|
|
90
|
+
@workspace || raise(ProtocolError.new("server is not initialized", code: -32_002))
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
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 textDocument/completion
|
|
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: Transport::_Input, stdout: Transport::_Output, stderr: Object?) -> 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 () -> lsp_object?
|
|
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 (lsp_object 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") #: String
|
|
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 (lsp_object message) -> (String | Integer)?
|
|
70
|
+
def safe_request_id(message)
|
|
71
|
+
value = message["id"]
|
|
72
|
+
return unless value.is_a?(String) || value.is_a?(Integer)
|
|
73
|
+
|
|
74
|
+
value if valid_request_id?(value)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @rbs (lsp_object message) -> bool
|
|
78
|
+
def notification_envelope?(message)
|
|
79
|
+
!message.key?("id") && message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @rbs (String method, bool request) -> void
|
|
83
|
+
def validate_message_kind!(method, request)
|
|
84
|
+
if REQUEST_METHODS.include?(method) && !request
|
|
85
|
+
raise ProtocolError.new("#{method} must be a request", code: -32_600)
|
|
86
|
+
end
|
|
87
|
+
return unless NOTIFICATION_METHODS.include?(method) && request
|
|
88
|
+
|
|
89
|
+
raise ProtocolError.new("#{method} must be a notification", code: -32_600)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @rbs (lsp_object message) -> (String | Integer)?
|
|
93
|
+
def validate_envelope(message)
|
|
94
|
+
unless message["jsonrpc"] == "2.0" && message["method"].is_a?(String)
|
|
95
|
+
raise ProtocolError.new("invalid JSON-RPC request", code: -32_600)
|
|
96
|
+
end
|
|
97
|
+
return nil unless message.key?("id")
|
|
98
|
+
|
|
99
|
+
request_id = message["id"]
|
|
100
|
+
unless (request_id.is_a?(String) || request_id.is_a?(Integer)) && valid_request_id?(request_id)
|
|
101
|
+
raise ProtocolError.new("request id must be a bounded string or integer", code: -32_600)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
request_id
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @rbs (Object? value) -> bool
|
|
108
|
+
def valid_request_id?(value)
|
|
109
|
+
return false unless value.is_a?(String) || value.is_a?(Integer)
|
|
110
|
+
|
|
111
|
+
value.to_s.bytesize <= Limits::MAX_REQUEST_ID_BYTES
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @rbs (String method) -> void
|
|
115
|
+
def validate_lifecycle!(method)
|
|
116
|
+
return if method == "exit"
|
|
117
|
+
return if @state == :uninitialized && method == "initialize"
|
|
118
|
+
return if @state == :initialized && %w[initialized shutdown].include?(method)
|
|
119
|
+
return if @state == :running
|
|
120
|
+
|
|
121
|
+
code = @state == :uninitialized ? -32_002 : -32_600
|
|
122
|
+
raise ProtocolError.new("request is invalid in #{@state} server state", code: code)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @rbs (String | Integer request_id, lsp_value result) -> void
|
|
126
|
+
def send_result(request_id, result)
|
|
127
|
+
@transport.write_message("jsonrpc" => "2.0", "id" => request_id, "result" => result)
|
|
128
|
+
rescue ProtocolError => e
|
|
129
|
+
send_error(request_id, e)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @rbs (String | Integer | nil request_id, ProtocolError error) -> void
|
|
133
|
+
def send_error(request_id, error)
|
|
134
|
+
@transport.write_message(
|
|
135
|
+
"jsonrpc" => "2.0", "id" => request_id,
|
|
136
|
+
"error" => { "code" => error.code, "message" => error.message }
|
|
137
|
+
)
|
|
138
|
+
rescue ProtocolError => e
|
|
139
|
+
log(e.message)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @rbs (String message) -> void
|
|
143
|
+
def log(message)
|
|
144
|
+
@stderr.puts(message)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
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, [Integer?, String]?]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @rbs (String path, lsp_object position) -> Array[lsp_object]
|
|
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, lsp_object position, ?include_declaration: bool) -> Array[lsp_object]
|
|
36
|
+
def references(path, position, include_declaration: false)
|
|
37
|
+
occurrence = occurrence_at(path, position)
|
|
38
|
+
return [] unless occurrence
|
|
39
|
+
|
|
40
|
+
entries = matching(occurrence.key)
|
|
41
|
+
entries = entries.reject { |entry| entry.role == :definition } unless include_declaration
|
|
42
|
+
entries.map { |entry| location(entry) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @rbs (String path, lsp_object position) -> lsp_object?
|
|
46
|
+
def prepare_rename(path, position)
|
|
47
|
+
occurrence = renameable_occurrence(path, position)
|
|
48
|
+
{ "range" => range(occurrence), "placeholder" => occurrence.name }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @rbs (String path, lsp_object position, String new_name) -> lsp_object
|
|
52
|
+
def rename(path, position, new_name)
|
|
53
|
+
ensure_fresh!
|
|
54
|
+
occurrence = renameable_occurrence(path, position)
|
|
55
|
+
validate_new_name(occurrence, new_name)
|
|
56
|
+
entries = matching(occurrence.key)
|
|
57
|
+
validate_unshared(entries)
|
|
58
|
+
validate_nonoverlapping(entries)
|
|
59
|
+
changes = entries.group_by(&:path).transform_values do |path_entries|
|
|
60
|
+
path_entries.sort_by { |entry| entry.span.start_byte }.map do |entry|
|
|
61
|
+
{ "range" => range(entry), "newText" => new_name }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
replacements = changed_sources(entries, new_name)
|
|
65
|
+
unless @store.valid_replacements?(replacements)
|
|
66
|
+
raise ProtocolError.new("rename would make the affected grammar closure invalid", code: -32_602)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
document_changes = changes.sort.map do |changed_path, edits|
|
|
70
|
+
snapshot = @store.snapshot_for(changed_path)
|
|
71
|
+
version = snapshot&.fetch(:open) ? snapshot.fetch(:version) : nil
|
|
72
|
+
{
|
|
73
|
+
"textDocument" => { "uri" => @store.uri_for(changed_path), "version" => version },
|
|
74
|
+
"edits" => edits
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
{ "documentChanges" => document_changes }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @rbs (String path, lsp_object position) -> lsp_object?
|
|
81
|
+
def hover(path, position)
|
|
82
|
+
occurrence = occurrence_at(path, position)
|
|
83
|
+
return unless occurrence
|
|
84
|
+
|
|
85
|
+
value = hover_value(occurrence)
|
|
86
|
+
return unless value
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
"contents" => { "kind" => "markdown", "value" => value },
|
|
90
|
+
"range" => range(occurrence)
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# @rbs (String path, lsp_object position) -> SymbolOccurrence?
|
|
97
|
+
def occurrence_at(path, position)
|
|
98
|
+
document = @documents[path]
|
|
99
|
+
return unless document
|
|
100
|
+
|
|
101
|
+
offset = PositionCodec.new(document.source).byte_offset(position)
|
|
102
|
+
candidates = @occurrences.select do |entry|
|
|
103
|
+
entry.path == path && entry.span.start_byte <= offset && offset < entry.span.end_byte
|
|
104
|
+
end
|
|
105
|
+
candidates.min_by { |entry| entry.span.length }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @rbs (symbol_key key, ?role: Symbol?) -> Array[SymbolOccurrence]
|
|
109
|
+
def matching(key, role: nil)
|
|
110
|
+
@occurrences.select { |entry| entry.key == key && (!role || entry.role == role) }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @rbs (SymbolOccurrence occurrence) -> lsp_object
|
|
114
|
+
def location(occurrence)
|
|
115
|
+
{ "uri" => @store.uri_for(occurrence.path), "range" => range(occurrence) }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @rbs (SymbolOccurrence occurrence) -> lsp_object
|
|
119
|
+
def include_target_location(occurrence)
|
|
120
|
+
target = occurrence.data.fetch(:target)
|
|
121
|
+
point = { "line" => 0, "character" => 0 }
|
|
122
|
+
{ "uri" => @store.uri_for(target), "range" => { "start" => point, "end" => point.dup } }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @rbs (SymbolOccurrence occurrence) -> Hash[String, Hash[String, Integer]]
|
|
126
|
+
def range(occurrence)
|
|
127
|
+
document = @documents.fetch(occurrence.path)
|
|
128
|
+
PositionCodec.new(document.source).range(occurrence.span)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @rbs (String path, lsp_object position) -> SymbolOccurrence
|
|
132
|
+
def renameable_occurrence(path, position)
|
|
133
|
+
occurrence = occurrence_at(path, position)
|
|
134
|
+
unless occurrence && %i[rule terminal parameter].include?(occurrence.kind) &&
|
|
135
|
+
occurrence.name.match?(IDENTIFIER) && !RESERVED.include?(occurrence.name)
|
|
136
|
+
raise ProtocolError.new("symbol at position cannot be renamed", code: -32_602)
|
|
137
|
+
end
|
|
138
|
+
unless matching(occurrence.key, role: :definition).any?
|
|
139
|
+
raise ProtocolError.new("unresolved symbol cannot be renamed", code: -32_602)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
occurrence
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @rbs (SymbolOccurrence occurrence, String new_name) -> void
|
|
146
|
+
def validate_new_name(occurrence, new_name)
|
|
147
|
+
unless new_name.is_a?(String) && new_name.match?(IDENTIFIER) && !RESERVED.include?(new_name)
|
|
148
|
+
raise ProtocolError.new("new name must be a non-reserved grammar identifier", code: -32_602)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
collision = @occurrences.any? do |entry|
|
|
152
|
+
entry.role == :definition && entry.name == new_name && entry.key != occurrence.key &&
|
|
153
|
+
collision_scope?(entry, occurrence)
|
|
154
|
+
end
|
|
155
|
+
raise ProtocolError.new("rename collides with existing symbol #{new_name}", code: -32_602) if collision
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @rbs (SymbolOccurrence candidate, SymbolOccurrence occurrence) -> bool
|
|
159
|
+
def collision_scope?(candidate, occurrence)
|
|
160
|
+
return candidate.key.take(3) == occurrence.key.take(3) if occurrence.kind == :parameter
|
|
161
|
+
|
|
162
|
+
candidate.kind != :parameter
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @rbs (Array[SymbolOccurrence] entries) -> void
|
|
166
|
+
def validate_nonoverlapping(entries)
|
|
167
|
+
entries.group_by(&:path).each_value do |path_entries|
|
|
168
|
+
ordered = path_entries.sort_by { |entry| [entry.span.start_byte, entry.span.end_byte] }
|
|
169
|
+
overlap = (1...ordered.length).any? do |index|
|
|
170
|
+
ordered.fetch(index - 1).span.end_byte > ordered.fetch(index).span.start_byte
|
|
171
|
+
end
|
|
172
|
+
raise ProtocolError.new("rename contains overlapping source edits", code: -32_603) if overlap
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @rbs (Array[SymbolOccurrence] entries) -> void
|
|
177
|
+
def validate_unshared(entries)
|
|
178
|
+
return unless entries.any? { |entry| @store.roots_for(entry.path).length > 1 }
|
|
179
|
+
|
|
180
|
+
raise ProtocolError.new("rename affecting a fragment shared by multiple roots is ambiguous", code: -32_602)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @rbs () -> void
|
|
184
|
+
def ensure_fresh!
|
|
185
|
+
stale = @snapshot_state.any? do |path, expected|
|
|
186
|
+
snapshot = @store.snapshot_for(path)
|
|
187
|
+
actual = snapshot && [snapshot.fetch(:version), snapshot.fetch(:source)]
|
|
188
|
+
actual != expected
|
|
189
|
+
end
|
|
190
|
+
raise ProtocolError.new("symbol snapshot is stale; retry the request", code: -32_602) if stale
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# @rbs (Array[SymbolOccurrence] entries, String new_name) -> Hash[String, String]
|
|
194
|
+
def changed_sources(entries, new_name)
|
|
195
|
+
entries.group_by(&:path).to_h do |path, path_entries|
|
|
196
|
+
document = @documents.fetch(path)
|
|
197
|
+
source = document.source.dup
|
|
198
|
+
path_entries.sort_by { |entry| -entry.span.start_byte }.each do |entry|
|
|
199
|
+
prefix = source.byteslice(0, entry.span.start_byte) || ""
|
|
200
|
+
suffix = source.byteslice(entry.span.end_byte, source.bytesize - entry.span.end_byte) || ""
|
|
201
|
+
source = prefix + new_name + suffix
|
|
202
|
+
end
|
|
203
|
+
[path, source]
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# @rbs (SymbolOccurrence occurrence) -> String?
|
|
208
|
+
def hover_value(occurrence)
|
|
209
|
+
case occurrence.kind
|
|
210
|
+
when :rule then rule_hover(occurrence)
|
|
211
|
+
when :terminal then terminal_hover(occurrence)
|
|
212
|
+
when :parameter then "`#{occurrence.name}` — formal parameter of `#{occurrence.data[:rule]}`"
|
|
213
|
+
when :include then "Includes `#{occurrence.data[:target]}`"
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# @rbs (SymbolOccurrence occurrence) -> String
|
|
218
|
+
def rule_hover(occurrence)
|
|
219
|
+
definition = matching(occurrence.key, role: :definition).first
|
|
220
|
+
data = definition&.data || occurrence.data
|
|
221
|
+
lines = ["```ibex", data[:signature] || occurrence.name, "```"]
|
|
222
|
+
lines << data[:documentation] if data[:documentation]
|
|
223
|
+
lines.join("\n")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# @rbs (SymbolOccurrence occurrence) -> String
|
|
227
|
+
def terminal_hover(occurrence)
|
|
228
|
+
definition = matching(occurrence.key, role: :definition).first
|
|
229
|
+
data = definition&.data || occurrence.data
|
|
230
|
+
lines = ["`#{occurrence.name}` — terminal"]
|
|
231
|
+
lines << "Display: #{data[:display]}" if data[:display]
|
|
232
|
+
lines << "Type: `#{data[:type]}`" if data[:type]
|
|
233
|
+
if (precedence = data[:precedence])
|
|
234
|
+
precedence_data = precedence #: Hash[Symbol, symbol_data_value]
|
|
235
|
+
lines << "Precedence: #{precedence_data[:associativity]} level #{precedence_data[:level]}"
|
|
236
|
+
end
|
|
237
|
+
lines.join("\n\n")
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|