mt-lang 0.3.8 → 0.3.10
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/lib/milk_tea/base.rb +1 -2
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
- data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
- data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
- data/lib/milk_tea/bindings/steamworks.rb +12 -16
- data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
- data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
- data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
- data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
- data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
- data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
- data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
- data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
- data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
- data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
- data/lib/milk_tea/core/ast.rb +103 -45
- data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
- data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
- data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
- data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
- data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
- data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
- data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
- data/lib/milk_tea/core/c_backend/statements.rb +528 -530
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
- data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
- data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
- data/lib/milk_tea/core/c_backend.rb +17 -9
- data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
- data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
- data/lib/milk_tea/core/compile_time.rb +32 -38
- data/lib/milk_tea/core/control_flow/builder.rb +3 -5
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
- data/lib/milk_tea/core/ir.rb +10 -10
- data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
- data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
- data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
- data/lib/milk_tea/core/lexer/indentation.rb +0 -2
- data/lib/milk_tea/core/lexer/numbers.rb +0 -2
- data/lib/milk_tea/core/lexer/recovery.rb +0 -2
- data/lib/milk_tea/core/lexer/strings.rb +0 -2
- data/lib/milk_tea/core/lexer/symbols.rb +0 -2
- data/lib/milk_tea/core/lexer/trivia.rb +0 -2
- data/lib/milk_tea/core/lexer.rb +0 -2
- data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
- data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
- data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
- data/lib/milk_tea/core/lowering/async.rb +627 -630
- data/lib/milk_tea/core/lowering/block.rb +413 -416
- data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
- data/lib/milk_tea/core/lowering/declarations.rb +180 -183
- data/lib/milk_tea/core/lowering/dyn.rb +48 -50
- data/lib/milk_tea/core/lowering/events.rb +983 -985
- data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
- data/lib/milk_tea/core/lowering/functions.rb +185 -188
- data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
- data/lib/milk_tea/core/lowering/proc.rb +363 -366
- data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
- data/lib/milk_tea/core/lowering/scans.rb +179 -181
- data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
- data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
- data/lib/milk_tea/core/lowering.rb +5 -7
- data/lib/milk_tea/core/module_binder.rb +0 -2
- data/lib/milk_tea/core/module_loader/errors.rb +4 -2
- data/lib/milk_tea/core/module_loader.rb +113 -20
- data/lib/milk_tea/core/module_path_resolver.rb +0 -2
- data/lib/milk_tea/core/module_roots.rb +6 -8
- data/lib/milk_tea/core/parser/attributes.rb +0 -2
- data/lib/milk_tea/core/parser/blocks.rb +0 -2
- data/lib/milk_tea/core/parser/declarations.rb +0 -2
- data/lib/milk_tea/core/parser/expressions.rb +31 -14
- data/lib/milk_tea/core/parser/recovery.rb +0 -2
- data/lib/milk_tea/core/parser/statements.rb +0 -2
- data/lib/milk_tea/core/parser/types.rb +8 -10
- data/lib/milk_tea/core/parser.rb +1 -3
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
- data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
- data/lib/milk_tea/core/types/layout.rb +21 -22
- data/lib/milk_tea/core/types/predicates.rb +0 -2
- data/lib/milk_tea/core/types/registry.rb +16 -18
- data/lib/milk_tea/core/types/visitor.rb +0 -4
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
- data/lib/milk_tea/dap/protocol.rb +1 -1
- data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
- data/lib/milk_tea/dap/server/debug_map.rb +0 -2
- data/lib/milk_tea/dap/server/handlers.rb +0 -2
- data/lib/milk_tea/dap/server/launch.rb +0 -2
- data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
- data/lib/milk_tea/dap/server/utilities.rb +0 -2
- data/lib/milk_tea/dap/server/wire.rb +0 -2
- data/lib/milk_tea/dap/server.rb +0 -2
- data/lib/milk_tea/lsp/diagnostics.rb +16 -16
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
- data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
- data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
- data/lib/milk_tea/lsp/server/completion.rb +873 -875
- data/lib/milk_tea/lsp/server/configuration.rb +129 -131
- data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
- data/lib/milk_tea/lsp/server/definition.rb +564 -565
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
- data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
- data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
- data/lib/milk_tea/lsp/server/formatting.rb +478 -480
- data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
- data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
- data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
- data/lib/milk_tea/lsp/server/progress.rb +0 -2
- data/lib/milk_tea/lsp/server/references.rb +316 -318
- data/lib/milk_tea/lsp/server/rename.rb +445 -447
- data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
- data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
- data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
- data/lib/milk_tea/lsp/server/utilities.rb +397 -399
- data/lib/milk_tea/lsp/server.rb +0 -3
- data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
- data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
- data/lib/milk_tea/packages/atomic_write.rb +4 -5
- data/lib/milk_tea/packages/dependency_solver.rb +15 -15
- data/lib/milk_tea/packages/lock.rb +4 -4
- data/lib/milk_tea/packages/manager_cli.rb +1 -1
- data/lib/milk_tea/packages/manifest.rb +3 -3
- data/lib/milk_tea/packages/registry_store.rb +4 -6
- data/lib/milk_tea/packages/services.rb +16 -16
- data/lib/milk_tea/packages/source_cache.rb +4 -6
- data/lib/milk_tea/packages/source_resolver.rb +44 -44
- data/lib/milk_tea/packages/version.rb +8 -8
- data/lib/milk_tea/tooling/build.rb +3 -7
- data/lib/milk_tea/tooling/build_cache.rb +0 -2
- data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
- data/lib/milk_tea/tooling/debug_map.rb +8 -10
- data/lib/milk_tea/tooling/docs_app.rb +0 -2
- data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
- data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
- data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
- data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
- data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
- data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
- data/lib/milk_tea/tooling/linter/rules.rb +87 -89
- data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
- data/lib/milk_tea/tooling/linter/visitors.rb +162 -50
- data/lib/milk_tea/tooling/linter.rb +0 -2
- data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
- data/lib/milk_tea/tooling/run.rb +0 -2
- data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
- data/std/cli.mt +13 -32
- data/std/color.mt +28 -28
- data/std/encoding.mt +4 -4
- data/std/graph.mt +1 -2
- data/std/hash.mt +14 -14
- data/std/http/server.mt +3 -3
- data/std/input.mt +1 -1
- data/std/json.mt +1 -1
- data/std/linear_algebra.mt +6 -6
- data/std/net/mux.mt +1 -1
- data/std/noise.mt +23 -23
- data/std/parse.mt +2 -2
- data/std/process.mt +3 -4
- data/std/sparse_set.mt +1 -1
- data/std/steering.mt +5 -5
- data/std/str.mt +1 -1
- data/std/tween.mt +4 -4
- data/std/utility.mt +3 -3
- metadata +2 -2
|
@@ -4,741 +4,740 @@ module MilkTea
|
|
|
4
4
|
module LSP
|
|
5
5
|
class Server
|
|
6
6
|
module ServerDefinition
|
|
7
|
-
|
|
7
|
+
def is_builtin_name?(name, tokens, token_index)
|
|
8
|
+
return false unless token_index
|
|
9
|
+
builtin_hover_info(name, tokens, token_index)
|
|
10
|
+
end
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
end
|
|
12
|
+
def handle_definition(params)
|
|
13
|
+
handle_definition_request('textDocument/definition', params, error_label: 'definition')
|
|
14
|
+
end
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
def handle_declaration(params)
|
|
17
|
+
handle_definition_request('textDocument/declaration', params, error_label: 'declaration')
|
|
18
|
+
end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def handle_type_definition(params)
|
|
21
|
+
stages = new_perf_stages
|
|
22
|
+
total_start = stages ? monotonic_time : nil
|
|
23
|
+
uri = params.dig('textDocument', 'uri')
|
|
24
|
+
result_state = 'miss'
|
|
25
|
+
|
|
26
|
+
location = resolve_type_definition_location(params, stages: stages)
|
|
27
|
+
result_state = location ? 'hit' : 'miss'
|
|
28
|
+
location
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
result_state = 'error'
|
|
31
|
+
warn "Error in typeDefinition handler: #{e.message}"
|
|
32
|
+
nil
|
|
33
|
+
ensure
|
|
34
|
+
log_request_stage_breakdown('textDocument/typeDefinition', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
|
|
35
|
+
end
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
def handle_implementation(params)
|
|
38
|
+
stages = new_perf_stages
|
|
39
|
+
total_start = stages ? monotonic_time : nil
|
|
40
|
+
uri = params.dig('textDocument', 'uri')
|
|
41
|
+
result_state = 'miss'
|
|
42
|
+
|
|
43
|
+
locations = resolve_implementation_locations(params, stages: stages)
|
|
44
|
+
result_state = locations.empty? ? 'miss' : 'hit'
|
|
45
|
+
locations
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
result_state = 'error'
|
|
48
|
+
warn "Error in implementation handler: #{e.message}"
|
|
49
|
+
[]
|
|
50
|
+
ensure
|
|
51
|
+
log_request_stage_breakdown('textDocument/implementation', total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
|
|
52
|
+
end
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
def handle_definition_request(method_name, params, error_label:)
|
|
55
|
+
stages = new_perf_stages
|
|
56
|
+
total_start = stages ? monotonic_time : nil
|
|
57
|
+
uri = params.dig('textDocument', 'uri')
|
|
58
|
+
result_state = 'miss'
|
|
59
|
+
|
|
60
|
+
location = resolve_definition_location(params, stages: stages)
|
|
61
|
+
result_state = location ? 'hit' : 'miss'
|
|
62
|
+
location
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
result_state = 'error'
|
|
65
|
+
warn "Error in #{error_label} handler: #{e.message}"
|
|
66
|
+
nil
|
|
67
|
+
ensure
|
|
68
|
+
log_request_stage_breakdown(method_name, total_start, uri: uri, stages: stages, summary: "result=#{result_state}")
|
|
69
|
+
end
|
|
55
70
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
def resolve_definition_location(params, stages: nil)
|
|
72
|
+
uri = params['textDocument']['uri']
|
|
73
|
+
lsp_line = params['position']['line']
|
|
74
|
+
lsp_char = params['position']['character']
|
|
75
|
+
|
|
76
|
+
context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
|
|
77
|
+
token = context&.fetch(:token, nil)
|
|
78
|
+
return nil unless token&.type == :identifier
|
|
79
|
+
|
|
80
|
+
tokens = context[:tokens]
|
|
81
|
+
token_index = context[:token_index]
|
|
82
|
+
return nil if token_index && module_declaration_info_at(tokens, token_index)
|
|
83
|
+
|
|
84
|
+
if token_index && named_argument_label_token?(tokens, token_index)
|
|
85
|
+
location = named_argument_definition_location(uri, token.lexeme, tokens, token_index, stages:)
|
|
86
|
+
return location if location
|
|
87
|
+
end
|
|
72
88
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
121
|
-
elsif facts.interfaces[token.lexeme]
|
|
122
|
-
location = module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
123
|
-
elsif facts.types.key?(token.lexeme)
|
|
124
|
-
location = module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
125
|
-
elsif (binding = facts.values[token.lexeme])
|
|
126
|
-
location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
|
|
127
|
-
location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
128
|
-
else
|
|
129
|
-
if imported_module_name
|
|
130
|
-
location = module_member_definition_location(uri, imported_module_name, token.lexeme) || module_definition_location(uri, imported_module_name)
|
|
131
|
-
elsif facts.imports.key?(token.lexeme)
|
|
132
|
-
module_name = facts.imports.fetch(token.lexeme).name
|
|
133
|
-
location = module_member_definition_location(uri, module_name, token.lexeme)
|
|
134
|
-
location ||= module_definition_location(uri, module_name)
|
|
135
|
-
elsif (module_name = imported_module_name_from_ast(uri, token.lexeme))
|
|
136
|
-
location = module_definition_location(uri, module_name)
|
|
89
|
+
import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
|
|
90
|
+
if import_info
|
|
91
|
+
return module_definition_location(uri, import_info[:module_name])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
|
|
95
|
+
if facts
|
|
96
|
+
facts_location = measure_perf_stage(stages, 'facts_lookup') do
|
|
97
|
+
location = nil
|
|
98
|
+
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
99
|
+
dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
|
|
100
|
+
imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
|
|
101
|
+
|
|
102
|
+
if token_index && (field_location = resolve_field_member_definition_location(uri, facts, tokens, token_index))
|
|
103
|
+
location = field_location
|
|
104
|
+
elsif token_index && (enum_member_location = resolve_enum_member_definition_location(uri, facts, tokens, token_index))
|
|
105
|
+
location = enum_member_location
|
|
106
|
+
elsif token_index && imported_module_name && module_member_access_info(tokens, token_index)
|
|
107
|
+
location = module_member_definition_location(uri, imported_module_name, token.lexeme)
|
|
108
|
+
location ||= module_definition_location(uri, imported_module_name)
|
|
109
|
+
elsif (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, token.lexeme))
|
|
110
|
+
location = module_member_binding_location(uri, type_method[:module_name], token.lexeme, type_method[:binding]) ||
|
|
111
|
+
module_member_definition_location(uri, type_method[:module_name], token.lexeme) ||
|
|
112
|
+
module_definition_location(uri, type_method[:module_name])
|
|
113
|
+
elsif (binding = method_binding_at_token(facts, token))
|
|
114
|
+
location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
|
|
115
|
+
location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
116
|
+
elsif (binding = facts.functions[token.lexeme])
|
|
117
|
+
location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
|
|
118
|
+
location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
119
|
+
elsif facts.interfaces[token.lexeme]
|
|
120
|
+
location = module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
121
|
+
elsif facts.types.key?(token.lexeme)
|
|
122
|
+
location = module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
123
|
+
elsif (binding = facts.values[token.lexeme])
|
|
124
|
+
location = module_member_binding_location(uri, facts.module_name, token.lexeme, binding)
|
|
125
|
+
location ||= module_member_definition_location(uri, facts.module_name, token.lexeme)
|
|
126
|
+
else
|
|
127
|
+
if imported_module_name
|
|
128
|
+
location = module_member_definition_location(uri, imported_module_name, token.lexeme) || module_definition_location(uri, imported_module_name)
|
|
129
|
+
elsif facts.imports.key?(token.lexeme)
|
|
130
|
+
module_name = facts.imports.fetch(token.lexeme).name
|
|
131
|
+
location = module_member_definition_location(uri, module_name, token.lexeme)
|
|
132
|
+
location ||= module_definition_location(uri, module_name)
|
|
133
|
+
elsif (module_name = imported_module_name_from_ast(uri, token.lexeme))
|
|
134
|
+
location = module_definition_location(uri, module_name)
|
|
135
|
+
end
|
|
137
136
|
end
|
|
137
|
+
|
|
138
|
+
location
|
|
138
139
|
end
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
return facts_location if facts_location
|
|
141
142
|
end
|
|
142
143
|
|
|
143
|
-
return
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
return nil if token_index && is_builtin_name?(token.lexeme, tokens, token_index)
|
|
144
|
+
return nil if token_index && is_builtin_name?(token.lexeme, tokens, token_index)
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
if facts && token_index && !facts_location
|
|
147
|
+
local_location = measure_perf_stage(stages, 'local_binding') do
|
|
148
|
+
name = token.lexeme
|
|
149
|
+
line = lsp_line + 1
|
|
150
|
+
char = lsp_char + 1
|
|
151
|
+
local_binding = resolve_local_hover_binding(facts, name, line, char)
|
|
152
|
+
next nil unless local_binding
|
|
155
153
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
{
|
|
159
|
-
uri: uri,
|
|
160
|
-
range: {
|
|
161
|
-
start: { line: ast_node.line - 1, character: ast_node.column - 1 },
|
|
162
|
-
end: { line: ast_node.line - 1, character: ast_node.column - 1 + name.length }
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
else
|
|
166
|
-
declaration_node = find_local_declaration_ast_node(uri, name, line)
|
|
167
|
-
if declaration_node
|
|
154
|
+
ast_node = local_binding.respond_to?(:ast) ? local_binding.ast : nil
|
|
155
|
+
if ast_node&.line && ast_node.column
|
|
168
156
|
{
|
|
169
157
|
uri: uri,
|
|
170
158
|
range: {
|
|
171
|
-
start: { line:
|
|
172
|
-
end: { line:
|
|
159
|
+
start: { line: ast_node.line - 1, character: ast_node.column - 1 },
|
|
160
|
+
end: { line: ast_node.line - 1, character: ast_node.column - 1 + name.length }
|
|
173
161
|
}
|
|
174
162
|
}
|
|
163
|
+
else
|
|
164
|
+
declaration_node = find_local_declaration_ast_node(uri, name, line)
|
|
165
|
+
if declaration_node
|
|
166
|
+
{
|
|
167
|
+
uri: uri,
|
|
168
|
+
range: {
|
|
169
|
+
start: { line: declaration_node.line - 1, character: declaration_node.column - 1 },
|
|
170
|
+
end: { line: declaration_node.line - 1, character: declaration_node.column - 1 + name.length }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
end
|
|
175
174
|
end
|
|
176
175
|
end
|
|
176
|
+
return local_location if local_location
|
|
177
177
|
end
|
|
178
|
-
return local_location if local_location
|
|
179
|
-
end
|
|
180
178
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
179
|
+
found = measure_perf_stage(stages, 'global_lookup') do
|
|
180
|
+
@workspace.find_definition_token_global(
|
|
181
|
+
token.lexeme,
|
|
182
|
+
preferred_uri: uri,
|
|
183
|
+
before_line: lsp_line + 1,
|
|
184
|
+
before_char: lsp_char + 1,
|
|
185
|
+
)
|
|
186
|
+
end
|
|
187
|
+
return nil unless found
|
|
190
188
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
189
|
+
{
|
|
190
|
+
uri: found[:uri],
|
|
191
|
+
range: token_to_range(found[:token])
|
|
192
|
+
}
|
|
193
|
+
end
|
|
196
194
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
def find_local_declaration_ast_node(uri, name, before_line)
|
|
196
|
+
ast = @workspace.get_ast(uri)
|
|
197
|
+
return nil unless ast
|
|
200
198
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
result = nil
|
|
200
|
+
find_local_decl_node(ast, name, before_line) { |node| result = node; true }
|
|
201
|
+
result
|
|
202
|
+
end
|
|
205
203
|
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
def find_local_decl_node(node, name, before_line, &block)
|
|
205
|
+
return false if node.nil?
|
|
208
206
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
if (node.is_a?(AST::LocalDecl) || node.is_a?(AST::ForBinding)) && node.name == name && node.line && node.line < before_line
|
|
208
|
+
return true if yield node
|
|
209
|
+
end
|
|
212
210
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
211
|
+
if node.is_a?(Array)
|
|
212
|
+
node.each { |item| return true if find_local_decl_node(item, name, before_line, &block) }
|
|
213
|
+
return false
|
|
214
|
+
end
|
|
217
215
|
|
|
218
|
-
|
|
216
|
+
return false unless node.class.name&.start_with?("MilkTea::AST::")
|
|
219
217
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
218
|
+
if node.respond_to?(:members)
|
|
219
|
+
node.members.each do |member|
|
|
220
|
+
next unless member.is_a?(Symbol)
|
|
221
|
+
return true if find_local_decl_node(node.public_send(member), name, before_line, &block)
|
|
222
|
+
end
|
|
224
223
|
end
|
|
225
|
-
end
|
|
226
224
|
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
false
|
|
226
|
+
end
|
|
229
227
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
228
|
+
def resolve_field_member_definition_location(current_uri, facts, tokens, token_index)
|
|
229
|
+
chain = member_access_chain_at(tokens, token_index)
|
|
230
|
+
return nil unless chain
|
|
233
231
|
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
|
|
233
|
+
return nil unless hovered_segment && hovered_segment[:position].positive?
|
|
236
234
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
235
|
+
current_type = resolve_dot_receiver_value_type(
|
|
236
|
+
facts,
|
|
237
|
+
chain[:segments].first[:name],
|
|
238
|
+
chain[:line],
|
|
239
|
+
chain[:char],
|
|
240
|
+
)
|
|
241
|
+
unless current_type
|
|
242
|
+
first_name = chain[:segments].first[:name]
|
|
243
|
+
current_type = facts.types[first_name]
|
|
244
|
+
end
|
|
245
|
+
return nil unless current_type
|
|
248
246
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
247
|
+
chain[:segments][1..hovered_segment[:position]].each do |segment|
|
|
248
|
+
field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
|
|
249
|
+
if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
|
|
250
|
+
return field_definition_location(current_uri, field_receiver_type, segment[:name]) if segment[:token_index] == token_index
|
|
253
251
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
252
|
+
current_type = field_type
|
|
253
|
+
next
|
|
254
|
+
end
|
|
257
255
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
256
|
+
if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
|
|
257
|
+
if segment[:token_index] == token_index
|
|
258
|
+
decl = nested.respond_to?(:ast_declaration) ? nested.ast_declaration : nil
|
|
259
|
+
if decl&.line && decl.column
|
|
260
|
+
return {
|
|
261
|
+
uri: current_uri,
|
|
262
|
+
range: {
|
|
263
|
+
start: { line: decl.line - 1, character: decl.column - 1 },
|
|
264
|
+
end: { line: decl.line - 1, character: decl.column - 1 + segment[:name].length },
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
end
|
|
268
|
+
return nil
|
|
269
269
|
end
|
|
270
|
-
|
|
270
|
+
current_type = nested
|
|
271
|
+
next
|
|
271
272
|
end
|
|
272
|
-
current_type = nested
|
|
273
|
-
next
|
|
274
|
-
end
|
|
275
273
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
274
|
+
if segment[:token_index] == token_index
|
|
275
|
+
method_receiver_type = project_method_receiver_type_for_completion(current_type)
|
|
276
|
+
method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
|
|
277
|
+
return nil unless method_info
|
|
280
278
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
279
|
+
return module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding]) ||
|
|
280
|
+
module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
|
|
281
|
+
end
|
|
284
282
|
|
|
285
|
-
|
|
283
|
+
break
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
nil
|
|
286
287
|
end
|
|
287
288
|
|
|
288
|
-
nil
|
|
289
|
-
|
|
289
|
+
def resolve_type_definition_location(params, stages: nil)
|
|
290
|
+
uri = params['textDocument']['uri']
|
|
291
|
+
lsp_line = params['position']['line']
|
|
292
|
+
lsp_char = params['position']['character']
|
|
290
293
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
lsp_char = params['position']['character']
|
|
294
|
+
context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
|
|
295
|
+
token = context&.fetch(:token, nil)
|
|
296
|
+
return nil unless token&.type == :identifier
|
|
295
297
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
name = token.lexeme
|
|
299
|
+
tokens = context[:tokens]
|
|
300
|
+
token_index = context[:token_index]
|
|
299
301
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
302
|
+
import_info = token_index ? measure_perf_stage(stages, 'import_path') { import_path_info_at(tokens, token_index) } : nil
|
|
303
|
+
if import_info
|
|
304
|
+
return module_definition_location(uri, import_info[:module_name])
|
|
305
|
+
end
|
|
303
306
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return module_definition_location(uri, import_info[:module_name])
|
|
307
|
-
end
|
|
307
|
+
facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
|
|
308
|
+
return nil unless facts
|
|
308
309
|
|
|
309
|
-
|
|
310
|
-
|
|
310
|
+
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
311
|
+
imported_module_name = dot_receiver ? (facts.imports[dot_receiver]&.name || imported_module_name_from_ast(uri, dot_receiver)) : nil
|
|
311
312
|
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
if facts.types.key?(name) || facts.interfaces.key?(name)
|
|
314
|
+
return module_member_definition_location(uri, facts.module_name, name)
|
|
315
|
+
end
|
|
314
316
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
317
|
+
if token_index && imported_module_name && module_member_access_info(tokens, token_index)
|
|
318
|
+
return module_member_definition_location(uri, imported_module_name, name) ||
|
|
319
|
+
module_definition_location(uri, imported_module_name)
|
|
320
|
+
end
|
|
318
321
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
322
|
+
if imported_module_name && (facts.types.key?(imported_module_name) || facts.interfaces.key?(imported_module_name))
|
|
323
|
+
return module_member_definition_location(uri, imported_module_name, name) ||
|
|
324
|
+
module_definition_location(uri, imported_module_name)
|
|
325
|
+
end
|
|
323
326
|
|
|
324
|
-
|
|
325
|
-
return module_member_definition_location(uri, imported_module_name, name) ||
|
|
326
|
-
module_definition_location(uri, imported_module_name)
|
|
327
|
+
handle_definition_request('textDocument/typeDefinition', params, error_label: 'typeDefinition')
|
|
327
328
|
end
|
|
328
329
|
|
|
329
|
-
|
|
330
|
-
|
|
330
|
+
def resolve_implementation_locations(params, stages: nil)
|
|
331
|
+
uri = params['textDocument']['uri']
|
|
332
|
+
lsp_line = params['position']['line']
|
|
333
|
+
lsp_char = params['position']['character']
|
|
331
334
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
lsp_line = params['position']['line']
|
|
335
|
-
lsp_char = params['position']['character']
|
|
335
|
+
token = measure_perf_stage(stages, 'token') { @workspace.find_token_at(uri, lsp_line, lsp_char) }
|
|
336
|
+
return [] unless token&.type == :identifier
|
|
336
337
|
|
|
337
|
-
|
|
338
|
-
|
|
338
|
+
facts = measure_perf_stage(stages, 'facts') { @workspace.get_facts(uri) }
|
|
339
|
+
return [] unless facts
|
|
339
340
|
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
target = measure_perf_stage(stages, 'target_lookup') { resolve_interface_method_target_at_token(facts, token) }
|
|
342
|
+
if target
|
|
343
|
+
return measure_perf_stage(stages, 'implementation_lookup') do
|
|
344
|
+
interface_method_implementation_locations(target[:interface], target[:method])
|
|
345
|
+
end
|
|
346
|
+
end
|
|
342
347
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return measure_perf_stage(stages, 'implementation_lookup') do
|
|
346
|
-
interface_method_implementation_locations(target[:interface], target[:method])
|
|
348
|
+
interface_binding = measure_perf_stage(stages, 'binding_lookup') do
|
|
349
|
+
resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
|
|
347
350
|
end
|
|
348
|
-
|
|
351
|
+
return [] unless interface_binding
|
|
349
352
|
|
|
350
|
-
|
|
351
|
-
resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
|
|
353
|
+
measure_perf_stage(stages, 'implementation_lookup') { interface_implementation_locations(interface_binding) }
|
|
352
354
|
end
|
|
353
|
-
return [] unless interface_binding
|
|
354
355
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def module_definition_location(current_uri, module_name)
|
|
359
|
-
path = module_path_for_name(current_uri, module_name)
|
|
360
|
-
return nil unless path
|
|
356
|
+
def module_definition_location(current_uri, module_name)
|
|
357
|
+
path = module_path_for_name(current_uri, module_name)
|
|
358
|
+
return nil unless path
|
|
361
359
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
360
|
+
{
|
|
361
|
+
uri: path_to_uri(File.expand_path(path)),
|
|
362
|
+
range: {
|
|
363
|
+
start: { line: 0, character: 0 },
|
|
364
|
+
end: { line: 0, character: 0 }
|
|
365
|
+
}
|
|
367
366
|
}
|
|
368
|
-
|
|
369
|
-
end
|
|
367
|
+
end
|
|
370
368
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
369
|
+
def module_member_definition_location(current_uri, module_name, member_name)
|
|
370
|
+
path = module_path_for_name(current_uri, module_name)
|
|
371
|
+
return nil unless path
|
|
374
372
|
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
token = find_definition_token_in_file(path, member_name)
|
|
374
|
+
return nil unless token
|
|
377
375
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
376
|
+
{
|
|
377
|
+
uri: path_to_uri(File.expand_path(path)),
|
|
378
|
+
range: token_to_range(token)
|
|
379
|
+
}
|
|
380
|
+
end
|
|
383
381
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
382
|
+
def field_definition_location(current_uri, receiver_type, field_name)
|
|
383
|
+
owner_type = field_owner_type(receiver_type)
|
|
384
|
+
return nil unless owner_type&.respond_to?(:name)
|
|
387
385
|
|
|
388
|
-
|
|
389
|
-
|
|
386
|
+
path = module_path_for_name(current_uri, owner_type.module_name)
|
|
387
|
+
return nil unless path
|
|
390
388
|
|
|
391
|
-
|
|
392
|
-
|
|
389
|
+
token = find_field_token_in_type(path, owner_type.name, field_name, current_uri: current_uri)
|
|
390
|
+
return nil unless token
|
|
393
391
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
392
|
+
{
|
|
393
|
+
uri: path_to_uri(File.expand_path(path)),
|
|
394
|
+
range: token_to_range(token)
|
|
395
|
+
}
|
|
396
|
+
end
|
|
399
397
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
398
|
+
def enum_member_definition_location(current_uri, module_name, type_name, member_name)
|
|
399
|
+
path = module_path_for_name(current_uri, module_name)
|
|
400
|
+
return nil unless path
|
|
403
401
|
|
|
404
|
-
|
|
405
|
-
|
|
402
|
+
token = find_enum_member_token_in_file(path, type_name, member_name)
|
|
403
|
+
return nil unless token
|
|
406
404
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
405
|
+
{
|
|
406
|
+
uri: path_to_uri(File.expand_path(path)),
|
|
407
|
+
range: token_to_range(token)
|
|
408
|
+
}
|
|
409
|
+
end
|
|
412
410
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
411
|
+
def module_member_binding_location(current_uri, module_name, member_name, binding)
|
|
412
|
+
path = module_path_for_name(current_uri, module_name)
|
|
413
|
+
return nil unless path
|
|
416
414
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
415
|
+
ast = binding.respond_to?(:ast) ? binding.ast : nil
|
|
416
|
+
if ast&.line && ast.column
|
|
417
|
+
start_line = ast.line - 1
|
|
418
|
+
start_char = ast.column - 1
|
|
421
419
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
420
|
+
return {
|
|
421
|
+
uri: path_to_uri(File.expand_path(path)),
|
|
422
|
+
range: {
|
|
423
|
+
start: { line: start_line, character: start_char },
|
|
424
|
+
end: { line: start_line, character: start_char + member_name.length }
|
|
425
|
+
}
|
|
427
426
|
}
|
|
428
|
-
|
|
429
|
-
end
|
|
427
|
+
end
|
|
430
428
|
|
|
431
|
-
|
|
432
|
-
|
|
429
|
+
module_member_definition_location(current_uri, module_name, member_name)
|
|
430
|
+
end
|
|
433
431
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
432
|
+
def module_path_for_name(current_uri, module_name)
|
|
433
|
+
current_path = uri_to_path(current_uri)
|
|
434
|
+
return nil unless current_path
|
|
435
|
+
return current_path if module_name.nil? || module_name.empty?
|
|
438
436
|
|
|
439
|
-
|
|
440
|
-
|
|
437
|
+
current_facts = @workspace.get_facts(current_uri)
|
|
438
|
+
return current_path if current_facts&.module_name == module_name
|
|
441
439
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
440
|
+
resolution = DependencyResolution.resolve(current_path, mode: @workspace.dependency_resolution_mode)
|
|
441
|
+
module_roots = if resolution.ok?
|
|
442
|
+
MilkTea::ModuleRoots.roots_for_path(current_path, locked: resolution.locked)
|
|
443
|
+
else
|
|
444
|
+
MilkTea::ModuleRoots.roots_for_path(current_path)
|
|
445
|
+
end
|
|
446
|
+
relative_path = File.join(*module_name.split('.')) + '.mt'
|
|
447
|
+
resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
|
|
448
|
+
return resolved_path if resolved_path
|
|
451
449
|
|
|
452
|
-
|
|
453
|
-
|
|
450
|
+
workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
|
|
451
|
+
return nil unless workspace_root && File.directory?(workspace_root)
|
|
454
452
|
|
|
455
|
-
|
|
456
|
-
|
|
453
|
+
workspace_candidate = File.join(workspace_root, relative_path)
|
|
454
|
+
return workspace_candidate if File.file?(workspace_candidate)
|
|
457
455
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
456
|
+
nil
|
|
457
|
+
rescue PackageLockError
|
|
458
|
+
module_roots = MilkTea::ModuleRoots.roots_for_path(current_path)
|
|
459
|
+
relative_path = File.join(*module_name.split('.')) + '.mt'
|
|
460
|
+
resolved_path = module_roots.lazy.map { |root| File.join(root, relative_path) }.find { |candidate| File.file?(candidate) }
|
|
461
|
+
return resolved_path if resolved_path
|
|
464
462
|
|
|
465
|
-
|
|
466
|
-
|
|
463
|
+
workspace_root = @root_uri ? uri_to_path(@root_uri) : nil
|
|
464
|
+
return nil unless workspace_root && File.directory?(workspace_root)
|
|
467
465
|
|
|
468
|
-
|
|
469
|
-
|
|
466
|
+
workspace_candidate = File.join(workspace_root, relative_path)
|
|
467
|
+
return workspace_candidate if File.file?(workspace_candidate)
|
|
470
468
|
|
|
471
|
-
|
|
472
|
-
|
|
469
|
+
nil
|
|
470
|
+
end
|
|
473
471
|
|
|
474
|
-
|
|
475
|
-
|
|
472
|
+
def imported_module_name_from_ast(uri, alias_name)
|
|
473
|
+
return nil if alias_name.nil? || alias_name.empty?
|
|
476
474
|
|
|
477
|
-
|
|
478
|
-
|
|
475
|
+
ast = @workspace.get_ast(uri)
|
|
476
|
+
return nil unless ast
|
|
479
477
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
478
|
+
import = ast.imports.find do |entry|
|
|
479
|
+
resolved_alias = entry.alias_name || entry.path.parts.last
|
|
480
|
+
resolved_alias == alias_name
|
|
481
|
+
end
|
|
482
|
+
import&.path&.to_s
|
|
483
|
+
rescue StandardError
|
|
484
|
+
nil
|
|
483
485
|
end
|
|
484
|
-
import&.path&.to_s
|
|
485
|
-
rescue StandardError
|
|
486
|
-
nil
|
|
487
|
-
end
|
|
488
486
|
|
|
489
|
-
|
|
490
|
-
|
|
487
|
+
def find_definition_token_in_file(path, name)
|
|
488
|
+
tokens = definition_file_tokens(path)
|
|
491
489
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
490
|
+
tokens.each_cons(2) do |kw_tok, id_tok|
|
|
491
|
+
next unless MilkTea::LSP::Workspace::DEFINITION_KEYWORDS.include?(kw_tok.type)
|
|
492
|
+
next unless id_tok.type == :identifier && id_tok.lexeme == name
|
|
495
493
|
|
|
496
|
-
|
|
494
|
+
return id_tok
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
nil
|
|
498
|
+
rescue StandardError
|
|
499
|
+
nil
|
|
497
500
|
end
|
|
498
501
|
|
|
499
|
-
nil
|
|
500
|
-
|
|
501
|
-
nil
|
|
502
|
-
end
|
|
502
|
+
def find_field_token_in_type(path, type_name, field_name, current_uri: nil)
|
|
503
|
+
tokens = definition_lookup_tokens(path, current_uri: current_uri)
|
|
503
504
|
|
|
504
|
-
|
|
505
|
-
|
|
505
|
+
tokens.each_with_index do |token, index|
|
|
506
|
+
next unless [:struct, :union].include?(token.type)
|
|
506
507
|
|
|
507
|
-
|
|
508
|
-
|
|
508
|
+
name_index = next_non_trivia_token_index(tokens, index + 1)
|
|
509
|
+
next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
|
|
509
510
|
|
|
510
|
-
|
|
511
|
-
|
|
511
|
+
field_token = find_field_token_in_body(tokens, index, field_name)
|
|
512
|
+
return field_token if field_token
|
|
513
|
+
end
|
|
512
514
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
+
nil
|
|
516
|
+
rescue StandardError
|
|
517
|
+
nil
|
|
515
518
|
end
|
|
516
519
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
end
|
|
520
|
+
def find_field_token_in_body(tokens, header_index, field_name)
|
|
521
|
+
header = tokens[header_index]
|
|
522
|
+
i = header_index + 1
|
|
521
523
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
i = header_index + 1
|
|
524
|
+
while i < tokens.length
|
|
525
|
+
token = tokens[i]
|
|
525
526
|
|
|
526
|
-
|
|
527
|
-
|
|
527
|
+
if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
|
|
528
|
+
first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
|
|
529
|
+
break
|
|
530
|
+
end
|
|
528
531
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
532
|
+
if token.type == :identifier && token.lexeme == field_name && token.line > header.line &&
|
|
533
|
+
first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
|
|
534
|
+
colon_index = next_non_trivia_token_index(tokens, i + 1)
|
|
535
|
+
return token if colon_index && tokens[colon_index].type == :colon
|
|
536
|
+
end
|
|
533
537
|
|
|
534
|
-
|
|
535
|
-
first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
|
|
536
|
-
colon_index = next_non_trivia_token_index(tokens, i + 1)
|
|
537
|
-
return token if colon_index && tokens[colon_index].type == :colon
|
|
538
|
+
i += 1
|
|
538
539
|
end
|
|
539
540
|
|
|
540
|
-
|
|
541
|
+
nil
|
|
541
542
|
end
|
|
542
543
|
|
|
543
|
-
|
|
544
|
-
|
|
544
|
+
def find_enum_member_token_in_file(path, type_name, member_name)
|
|
545
|
+
tokens = definition_file_tokens(path)
|
|
545
546
|
|
|
546
|
-
|
|
547
|
-
|
|
547
|
+
tokens.each_with_index do |token, index|
|
|
548
|
+
next unless [:enum, :flags].include?(token.type)
|
|
548
549
|
|
|
549
|
-
|
|
550
|
-
|
|
550
|
+
name_index = next_non_trivia_token_index(tokens, index + 1)
|
|
551
|
+
next unless name_index && tokens[name_index].type == :identifier && tokens[name_index].lexeme == type_name
|
|
551
552
|
|
|
552
|
-
|
|
553
|
-
|
|
553
|
+
member_token = find_enum_member_token_in_body(tokens, index, member_name)
|
|
554
|
+
return member_token if member_token
|
|
555
|
+
end
|
|
554
556
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
+
nil
|
|
558
|
+
rescue StandardError
|
|
559
|
+
nil
|
|
557
560
|
end
|
|
558
561
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
end
|
|
562
|
+
def find_enum_member_token_in_body(tokens, header_index, member_name)
|
|
563
|
+
header = tokens[header_index]
|
|
564
|
+
i = header_index + 1
|
|
563
565
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
i = header_index + 1
|
|
566
|
+
while i < tokens.length
|
|
567
|
+
token = tokens[i]
|
|
567
568
|
|
|
568
|
-
|
|
569
|
-
|
|
569
|
+
if token.line > header.line && ![:newline, :indent, :dedent, :eof].include?(token.type) &&
|
|
570
|
+
first_non_trivia_token_on_line?(tokens, i) && token.column <= header.column
|
|
571
|
+
break
|
|
572
|
+
end
|
|
570
573
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
574
|
+
if token.type == :identifier && token.lexeme == member_name && token.line > header.line &&
|
|
575
|
+
first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
|
|
576
|
+
return token
|
|
577
|
+
end
|
|
575
578
|
|
|
576
|
-
|
|
577
|
-
first_non_trivia_token_on_line?(tokens, i) && token.column > header.column
|
|
578
|
-
return token
|
|
579
|
+
i += 1
|
|
579
580
|
end
|
|
580
581
|
|
|
581
|
-
|
|
582
|
+
nil
|
|
582
583
|
end
|
|
583
584
|
|
|
584
|
-
|
|
585
|
-
|
|
585
|
+
def enum_member_value_text(current_uri, module_name, type_name, member_name)
|
|
586
|
+
path = module_path_for_name(current_uri, module_name)
|
|
587
|
+
return nil unless path
|
|
586
588
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
589
|
+
declaration = definition_file_ast(path)&.declarations&.find do |decl|
|
|
590
|
+
(decl.is_a?(AST::EnumDecl) || decl.is_a?(AST::FlagsDecl)) && decl.name == type_name
|
|
591
|
+
end
|
|
592
|
+
return nil unless declaration
|
|
590
593
|
|
|
591
|
-
|
|
592
|
-
|
|
594
|
+
member = declaration.members.find { |candidate| candidate.name == member_name }
|
|
595
|
+
return nil unless member&.value
|
|
596
|
+
|
|
597
|
+
MilkTea::PrettyPrinter::ASTFormatter.new.send(:render_expression, member.value)
|
|
598
|
+
rescue StandardError
|
|
599
|
+
nil
|
|
593
600
|
end
|
|
594
|
-
return nil unless declaration
|
|
595
601
|
|
|
596
|
-
|
|
597
|
-
|
|
602
|
+
def definition_file_mtime_key(path)
|
|
603
|
+
stat = File.stat(path)
|
|
604
|
+
"#{stat.mtime.to_i}:#{stat.mtime.nsec}"
|
|
605
|
+
rescue StandardError
|
|
606
|
+
'missing'
|
|
607
|
+
end
|
|
598
608
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
609
|
+
def definition_file_tokens(path, mtime_key: nil)
|
|
610
|
+
cache_key = "#{path}:#{mtime_key || definition_file_mtime_key(path)}"
|
|
611
|
+
@definition_file_token_cache[cache_key] ||= begin
|
|
612
|
+
MilkTea::Lexer.lex(File.read(path), path: path_to_uri(path))
|
|
613
|
+
end
|
|
614
|
+
end
|
|
603
615
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
616
|
+
def definition_lookup_tokens(path, current_uri: nil)
|
|
617
|
+
current_path = current_uri ? uri_to_path(current_uri) : nil
|
|
618
|
+
if current_path && File.expand_path(current_path) == File.expand_path(path)
|
|
619
|
+
workspace_tokens = @workspace.get_tokens(current_uri)
|
|
620
|
+
return workspace_tokens if workspace_tokens
|
|
621
|
+
end
|
|
610
622
|
|
|
611
|
-
|
|
612
|
-
cache_key = "#{path}:#{mtime_key || definition_file_mtime_key(path)}"
|
|
613
|
-
@definition_file_token_cache[cache_key] ||= begin
|
|
614
|
-
MilkTea::Lexer.lex(File.read(path), path: path_to_uri(path))
|
|
623
|
+
definition_file_tokens(path)
|
|
615
624
|
end
|
|
616
|
-
end
|
|
617
625
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
626
|
+
def definition_file_ast(path)
|
|
627
|
+
mtime_key = definition_file_mtime_key(path)
|
|
628
|
+
cache_key = "#{path}:#{mtime_key}"
|
|
629
|
+
@definition_file_ast_cache[cache_key] ||= begin
|
|
630
|
+
MilkTea::Parser.parse(nil, path: path_to_uri(path), tokens: definition_file_tokens(path, mtime_key: mtime_key))
|
|
631
|
+
end
|
|
623
632
|
end
|
|
624
633
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
def definition_file_ast(path)
|
|
629
|
-
mtime_key = definition_file_mtime_key(path)
|
|
630
|
-
cache_key = "#{path}:#{mtime_key}"
|
|
631
|
-
@definition_file_ast_cache[cache_key] ||= begin
|
|
632
|
-
MilkTea::Parser.parse(nil, path: path_to_uri(path), tokens: definition_file_tokens(path, mtime_key: mtime_key))
|
|
633
|
-
end
|
|
634
|
-
end
|
|
634
|
+
def resolve_interface_binding_at_position(uri, facts, token, lsp_line, lsp_char)
|
|
635
|
+
binding = facts.interfaces[token.lexeme]
|
|
636
|
+
return binding if binding
|
|
635
637
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
return binding if binding
|
|
638
|
+
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
639
|
+
return nil unless dot_receiver
|
|
639
640
|
|
|
640
|
-
|
|
641
|
-
|
|
641
|
+
facts.imports[dot_receiver]&.interfaces&.fetch(token.lexeme, nil)
|
|
642
|
+
end
|
|
642
643
|
|
|
643
|
-
facts
|
|
644
|
-
|
|
644
|
+
def resolve_interface_method_target_at_token(facts, token)
|
|
645
|
+
facts.interfaces.each_value do |interface_binding|
|
|
646
|
+
method_binding = interface_binding.methods[token.lexeme]
|
|
647
|
+
next unless method_binding
|
|
648
|
+
next unless method_binding.ast.line == token.line
|
|
649
|
+
next unless method_binding.ast.column == token.column
|
|
645
650
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
method_binding = interface_binding.methods[token.lexeme]
|
|
649
|
-
next unless method_binding
|
|
650
|
-
next unless method_binding.ast.line == token.line
|
|
651
|
-
next unless method_binding.ast.respond_to?(:column) && method_binding.ast.column == token.column
|
|
651
|
+
return { interface: interface_binding, method: method_binding }
|
|
652
|
+
end
|
|
652
653
|
|
|
653
|
-
|
|
654
|
+
nil
|
|
654
655
|
end
|
|
655
656
|
|
|
656
|
-
|
|
657
|
-
|
|
657
|
+
def interface_implementation_locations(interface_binding)
|
|
658
|
+
seen = Set.new
|
|
659
|
+
@workspace.all_documents.filter_map do |doc_uri|
|
|
660
|
+
facts = @workspace.get_facts(doc_uri)
|
|
661
|
+
next unless facts
|
|
658
662
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
@workspace.all_documents.filter_map do |doc_uri|
|
|
662
|
-
facts = @workspace.get_facts(doc_uri)
|
|
663
|
-
next unless facts
|
|
663
|
+
facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
|
|
664
|
+
next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
|
|
664
665
|
|
|
665
|
-
|
|
666
|
-
|
|
666
|
+
location = interface_receiver_definition_location(doc_uri, receiver_type)
|
|
667
|
+
next unless location
|
|
667
668
|
|
|
668
|
-
|
|
669
|
-
|
|
669
|
+
key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
|
|
670
|
+
next if seen.include?(key)
|
|
670
671
|
|
|
671
|
-
|
|
672
|
-
|
|
672
|
+
seen << key
|
|
673
|
+
locations << location
|
|
674
|
+
end
|
|
675
|
+
end.flatten
|
|
676
|
+
end
|
|
673
677
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
678
|
+
def interface_method_implementation_locations(interface_binding, interface_method)
|
|
679
|
+
seen = Set.new
|
|
680
|
+
@workspace.all_documents.filter_map do |doc_uri|
|
|
681
|
+
facts = @workspace.get_facts(doc_uri)
|
|
682
|
+
next unless facts
|
|
679
683
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
@workspace.all_documents.filter_map do |doc_uri|
|
|
683
|
-
facts = @workspace.get_facts(doc_uri)
|
|
684
|
-
next unless facts
|
|
684
|
+
facts.implemented_interfaces.each_with_object([]) do |(receiver_type, interfaces), locations|
|
|
685
|
+
next unless interfaces.any? { |candidate| same_interface_binding?(candidate, interface_binding) }
|
|
685
686
|
|
|
686
|
-
|
|
687
|
-
|
|
687
|
+
method = methods_for_receiver_type(facts, receiver_type)[interface_method.name]
|
|
688
|
+
next unless method
|
|
688
689
|
|
|
689
|
-
|
|
690
|
-
|
|
690
|
+
module_name = receiver_module_name(receiver_type)
|
|
691
|
+
location = module_member_binding_location(doc_uri, module_name, interface_method.name, method)
|
|
692
|
+
location ||= module_member_definition_location(doc_uri, module_name, interface_method.name)
|
|
693
|
+
next unless location
|
|
691
694
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
location ||= module_member_definition_location(doc_uri, module_name, interface_method.name)
|
|
695
|
-
next unless location
|
|
695
|
+
key = [location[:uri], location.dig(:range, :start, :line), location.dig(:range, :start, :character)]
|
|
696
|
+
next if seen.include?(key)
|
|
696
697
|
|
|
697
|
-
|
|
698
|
-
|
|
698
|
+
seen << key
|
|
699
|
+
locations << location
|
|
700
|
+
end
|
|
701
|
+
end.flatten
|
|
702
|
+
end
|
|
699
703
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
end
|
|
703
|
-
end.flatten
|
|
704
|
-
end
|
|
704
|
+
def interface_receiver_definition_location(current_uri, receiver_type)
|
|
705
|
+
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
|
|
705
706
|
|
|
706
|
-
|
|
707
|
-
|
|
707
|
+
if receiver_type.module_name.nil? || receiver_type.module_name.empty?
|
|
708
|
+
token = local_type_definition_token(current_uri, receiver_type.name)
|
|
709
|
+
token ||= @workspace.find_definition_token(current_uri, receiver_type.name)
|
|
710
|
+
return { uri: current_uri, range: token_to_range(token) } if token
|
|
711
|
+
end
|
|
708
712
|
|
|
709
|
-
|
|
710
|
-
token = local_type_definition_token(current_uri, receiver_type.name)
|
|
711
|
-
token ||= @workspace.find_definition_token(current_uri, receiver_type.name)
|
|
712
|
-
return { uri: current_uri, range: token_to_range(token) } if token
|
|
713
|
+
module_member_definition_location(current_uri, receiver_type.module_name, receiver_type.name)
|
|
713
714
|
end
|
|
714
715
|
|
|
715
|
-
|
|
716
|
-
|
|
716
|
+
def receiver_module_name(receiver_type)
|
|
717
|
+
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
|
|
717
718
|
|
|
718
|
-
|
|
719
|
-
|
|
719
|
+
receiver_type.module_name
|
|
720
|
+
end
|
|
720
721
|
|
|
721
|
-
|
|
722
|
-
|
|
722
|
+
def local_type_definition_token(uri, name)
|
|
723
|
+
tokens = @workspace.get_tokens(uri)
|
|
724
|
+
return nil unless tokens
|
|
723
725
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
726
|
+
tokens.each_cons(2) do |kw_tok, id_tok|
|
|
727
|
+
next unless [:struct, :opaque, :enum, :flags, :variant, :union].include?(kw_tok.type)
|
|
728
|
+
next unless id_tok.type == :identifier && id_tok.lexeme == name
|
|
727
729
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
next unless id_tok.type == :identifier && id_tok.lexeme == name
|
|
730
|
+
return id_tok
|
|
731
|
+
end
|
|
731
732
|
|
|
732
|
-
|
|
733
|
+
nil
|
|
733
734
|
end
|
|
734
735
|
|
|
735
|
-
|
|
736
|
+
def same_interface_binding?(left, right)
|
|
737
|
+
left.name == right.name && left.module_name == right.module_name
|
|
738
|
+
end
|
|
736
739
|
end
|
|
737
740
|
|
|
738
|
-
def same_interface_binding?(left, right)
|
|
739
|
-
left.name == right.name && left.module_name == right.module_name
|
|
740
|
-
end
|
|
741
|
-
end
|
|
742
741
|
def named_argument_definition_location(uri, name, tokens, token_index, stages: nil)
|
|
743
742
|
return nil unless named_argument_label_token?(tokens, token_index)
|
|
744
743
|
|