mt-lang 0.2.13 → 0.2.14
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 -1
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +14 -0
- data/lib/milk_tea/lsp/server/completion.rb +3 -3
- data/lib/milk_tea/lsp/server/definition.rb +2 -2
- data/lib/milk_tea/lsp/server/hover.rb +44 -35
- data/lib/milk_tea/lsp/server/inlay_hints.rb +47 -26
- data/lib/milk_tea/lsp/server/references.rb +24 -0
- data/lib/milk_tea/lsp/server/rename.rb +50 -50
- data/lib/milk_tea/lsp/server/signature_help.rb +15 -6
- data/lib/milk_tea/lsp/workspace/caches.rb +9 -1
- data/std/option.mt +6 -0
- data/std/result.mt +11 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 684d2aada4af1e2b5fc1c0685e26004ed9442931692cb25007777b09df77dbe5
|
|
4
|
+
data.tar.gz: 5f16c0ce02404a51f4ac8dd8c12b8047fb4ae5ab442b1269ba7ce8c58809a065
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e129d1a7a428094755af01cb5bb98c29fb78ee9003b6938cb4335eb0e58763804a9e1c902f5d1563111a20c7b70ca69f4497f11c4cf476ed5b9ef8696ccc9ed
|
|
7
|
+
data.tar.gz: ffc46a4a1658c84a2fa6d2d7d6331b98164487c488112055adc9a2f20367074f26a02002d0a36ec493f9f9738ac2123f80a2e1e04fbaa5b364a54509898a2644
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -166,6 +166,7 @@ module MilkTea
|
|
|
166
166
|
module_binding = @ctx.imported_modules[module_path]
|
|
167
167
|
unless module_binding
|
|
168
168
|
install_fallback_builtin_type(module_path)
|
|
169
|
+
@ctx.imports[module_path] = empty_module_binding(module_path) unless @ctx.imports.key?(module_path)
|
|
169
170
|
next
|
|
170
171
|
end
|
|
171
172
|
|
|
@@ -178,6 +179,19 @@ module MilkTea
|
|
|
178
179
|
end
|
|
179
180
|
end
|
|
180
181
|
|
|
182
|
+
def empty_module_binding(module_path)
|
|
183
|
+
ModuleBinding.new(
|
|
184
|
+
name: module_path,
|
|
185
|
+
types: {}, type_declarations: {}, interfaces: {},
|
|
186
|
+
attributes: {}, attribute_applications: {},
|
|
187
|
+
values: {}, functions: {}, methods: {},
|
|
188
|
+
implemented_interfaces: {}, imports: {},
|
|
189
|
+
private_types: {}, private_interfaces: {}, private_attributes: {},
|
|
190
|
+
private_values: {}, private_functions: {}, private_methods: {},
|
|
191
|
+
private_implemented_interfaces: {},
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
|
|
181
195
|
def install_fallback_builtin_type(module_path)
|
|
182
196
|
case module_path
|
|
183
197
|
when "std.option"
|
|
@@ -742,7 +742,7 @@ module MilkTea
|
|
|
742
742
|
end
|
|
743
743
|
|
|
744
744
|
def method_dispatch_receiver_type_for_completion(receiver_type)
|
|
745
|
-
return receiver_type.definition if receiver_type.is_a?(Types::StructInstance)
|
|
745
|
+
return receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
|
|
746
746
|
|
|
747
747
|
if receiver_type.is_a?(Types::Nullable)
|
|
748
748
|
dispatch_base_type = method_dispatch_receiver_type_for_completion(receiver_type.base)
|
|
@@ -765,7 +765,7 @@ module MilkTea
|
|
|
765
765
|
|
|
766
766
|
def project_field_receiver_type_for_completion(type, facts = nil)
|
|
767
767
|
type = project_receiver_type_for_completion(type)
|
|
768
|
-
return type.definition if type.is_a?(Types::StructInstance)
|
|
768
|
+
return type.definition if type.is_a?(Types::StructInstance) || type.is_a?(Types::VariantInstance)
|
|
769
769
|
return field_type_from_struct_definition(type, facts) if facts
|
|
770
770
|
|
|
771
771
|
type
|
|
@@ -792,7 +792,7 @@ module MilkTea
|
|
|
792
792
|
|
|
793
793
|
def field_owner_type(receiver_type, facts = nil)
|
|
794
794
|
aggregate_type = project_field_receiver_type_for_completion(receiver_type, facts)
|
|
795
|
-
return aggregate_type.definition if aggregate_type.is_a?(Types::StructInstance)
|
|
795
|
+
return aggregate_type.definition if aggregate_type.is_a?(Types::StructInstance) || aggregate_type.is_a?(Types::VariantInstance)
|
|
796
796
|
|
|
797
797
|
aggregate_type
|
|
798
798
|
end
|
|
@@ -704,7 +704,7 @@ module MilkTea
|
|
|
704
704
|
end
|
|
705
705
|
|
|
706
706
|
def interface_receiver_definition_location(current_uri, receiver_type)
|
|
707
|
-
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance)
|
|
707
|
+
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
|
|
708
708
|
|
|
709
709
|
if receiver_type.module_name.nil? || receiver_type.module_name.empty?
|
|
710
710
|
token = local_type_definition_token(current_uri, receiver_type.name)
|
|
@@ -716,7 +716,7 @@ module MilkTea
|
|
|
716
716
|
end
|
|
717
717
|
|
|
718
718
|
def receiver_module_name(receiver_type)
|
|
719
|
-
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance)
|
|
719
|
+
receiver_type = receiver_type.definition if receiver_type.is_a?(Types::StructInstance) || receiver_type.is_a?(Types::VariantInstance)
|
|
720
720
|
|
|
721
721
|
receiver_type.module_name
|
|
722
722
|
end
|
|
@@ -285,6 +285,7 @@ module MilkTea
|
|
|
285
285
|
'subscribe' => 'function subscribe(listener) -> Result[Subscription, EventError]',
|
|
286
286
|
'subscribe_once' => 'function subscribe_once(listener) -> Result[Subscription, EventError]',
|
|
287
287
|
'unsubscribe' => 'function unsubscribe(subscription) -> bool',
|
|
288
|
+
'emit' => 'function emit() / function emit(payload)',
|
|
288
289
|
'wait' => 'function wait() -> Task[Result[T, EventError]]',
|
|
289
290
|
},
|
|
290
291
|
'str_buffer' => {
|
|
@@ -313,21 +314,23 @@ module MilkTea
|
|
|
313
314
|
token = context&.fetch(:token, nil)
|
|
314
315
|
token_kind = token&.type || :none
|
|
315
316
|
unless token&.type == :identifier
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
317
|
+
unless member_access_token?(context)
|
|
318
|
+
info = builtin_keyword_hover_info(token) ||
|
|
319
|
+
BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
|
|
320
|
+
if info
|
|
321
|
+
result_state = 'hit'
|
|
322
|
+
return {
|
|
323
|
+
contents: {
|
|
324
|
+
kind: 'markdown',
|
|
325
|
+
value: render_hover_markdown(info)
|
|
326
|
+
},
|
|
327
|
+
range: token_to_range(token)
|
|
328
|
+
}
|
|
329
|
+
end
|
|
328
330
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
+
result_state = 'not-identifier'
|
|
332
|
+
return nil
|
|
333
|
+
end
|
|
331
334
|
end
|
|
332
335
|
|
|
333
336
|
info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
|
|
@@ -362,10 +365,11 @@ module MilkTea
|
|
|
362
365
|
token_index = context[:token_index]
|
|
363
366
|
end
|
|
364
367
|
|
|
365
|
-
return nil unless token&.type == :identifier
|
|
366
|
-
|
|
367
368
|
tokens ||= @workspace.get_tokens(uri) || []
|
|
368
369
|
token_index = tokens.index(token) if token_index.nil?
|
|
370
|
+
member_access_kw = token_index && keyword_member_access_token?(tokens, token_index)
|
|
371
|
+
return nil unless token&.type == :identifier || member_access_kw
|
|
372
|
+
|
|
369
373
|
if token_index
|
|
370
374
|
module_info = module_declaration_info_at(tokens, token_index)
|
|
371
375
|
if module_info
|
|
@@ -462,11 +466,11 @@ module MilkTea
|
|
|
462
466
|
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
463
467
|
elsif (binding = facts.values[name])
|
|
464
468
|
signature = value_hover_signature(binding)
|
|
465
|
-
elsif (member_info = find_member_in_types(facts, name))
|
|
469
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
|
|
466
470
|
type, member, value = member_info
|
|
467
471
|
signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
|
|
468
472
|
resolved_via_type_member = true
|
|
469
|
-
elsif (arm_sig = find_variant_arm_in_types(facts, name))
|
|
473
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
|
|
470
474
|
signature = arm_sig
|
|
471
475
|
resolved_via_type_member = true
|
|
472
476
|
elsif (import_binding = facts.imports[name])
|
|
@@ -522,7 +526,7 @@ module MilkTea
|
|
|
522
526
|
if (method_binding = methods[name])
|
|
523
527
|
signature = method_signature(method_binding)
|
|
524
528
|
else
|
|
525
|
-
type_base = receiver_type.to_s[/^([
|
|
529
|
+
type_base = receiver_type.to_s[/^([A-Za-z_]+)/, 1]
|
|
526
530
|
if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
|
|
527
531
|
signature = method_sigs[name]
|
|
528
532
|
end
|
|
@@ -550,19 +554,6 @@ module MilkTea
|
|
|
550
554
|
end
|
|
551
555
|
end
|
|
552
556
|
|
|
553
|
-
unless signature
|
|
554
|
-
unless token_index && tokens && (tokens[previous_non_trivia_token_index(tokens, token_index)]&.type == :dot || call_argument_token?(tokens, token_index))
|
|
555
|
-
local_def = @workspace.find_definition_token_global(
|
|
556
|
-
name,
|
|
557
|
-
preferred_uri: uri,
|
|
558
|
-
before_line: lsp_line + 1,
|
|
559
|
-
before_char: lsp_char + 1,
|
|
560
|
-
)
|
|
561
|
-
if local_def
|
|
562
|
-
signature = resolve_lexical_local_hover_signature(local_def[:uri], name, local_def[:token])
|
|
563
|
-
end
|
|
564
|
-
end
|
|
565
|
-
end
|
|
566
557
|
end
|
|
567
558
|
|
|
568
559
|
return nil unless signature
|
|
@@ -998,9 +989,10 @@ module MilkTea
|
|
|
998
989
|
source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
|
|
999
990
|
|
|
1000
991
|
if segment[:token_index] == token_index
|
|
992
|
+
definition_entry = hover_definition_entry_from_location(source_location)
|
|
1001
993
|
return {
|
|
1002
994
|
signature: field_hover_signature(segment[:name], field_type),
|
|
1003
|
-
docs:
|
|
995
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
1004
996
|
source: hover_source_label_from_location(source_location),
|
|
1005
997
|
source_uri: hover_source_uri_from_location(source_location),
|
|
1006
998
|
source_line: hover_source_line_from_location(source_location),
|
|
@@ -1015,7 +1007,7 @@ module MilkTea
|
|
|
1015
1007
|
if segment[:token_index] == token_index
|
|
1016
1008
|
return {
|
|
1017
1009
|
signature: type_hover_signature(segment[:name], nested),
|
|
1018
|
-
docs:
|
|
1010
|
+
docs: BUILTIN_TYPE_DOCS[segment[:name]],
|
|
1019
1011
|
}
|
|
1020
1012
|
end
|
|
1021
1013
|
current_type = nested
|
|
@@ -1030,10 +1022,11 @@ module MilkTea
|
|
|
1030
1022
|
|
|
1031
1023
|
source_location = module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding])
|
|
1032
1024
|
source_location ||= module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
|
|
1025
|
+
definition_entry = hover_definition_entry_from_location(source_location)
|
|
1033
1026
|
|
|
1034
1027
|
return {
|
|
1035
1028
|
signature: method_signature(method_info[:binding]),
|
|
1036
|
-
docs:
|
|
1029
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
1037
1030
|
source: hover_source_label_from_location(source_location),
|
|
1038
1031
|
source_uri: hover_source_uri_from_location(source_location),
|
|
1039
1032
|
source_line: hover_source_line_from_location(source_location),
|
|
@@ -1511,6 +1504,22 @@ module MilkTea
|
|
|
1511
1504
|
prev_index && tokens[prev_index].type == :dot
|
|
1512
1505
|
end
|
|
1513
1506
|
|
|
1507
|
+
def member_access_token?(context)
|
|
1508
|
+
tokens = context[:tokens]
|
|
1509
|
+
token_index = context[:token_index]
|
|
1510
|
+
return false unless tokens && token_index
|
|
1511
|
+
prev = previous_non_trivia_token_index(tokens, token_index)
|
|
1512
|
+
prev && tokens[prev].type == :dot
|
|
1513
|
+
end
|
|
1514
|
+
|
|
1515
|
+
def keyword_member_access_token?(tokens, token_index)
|
|
1516
|
+
return false unless tokens && token_index
|
|
1517
|
+
tok = tokens[token_index]
|
|
1518
|
+
return false unless tok && tok.type != :identifier
|
|
1519
|
+
prev = previous_non_trivia_token_index(tokens, token_index)
|
|
1520
|
+
prev && tokens[prev].type == :dot
|
|
1521
|
+
end
|
|
1522
|
+
|
|
1514
1523
|
def builtin_value_specialization_info(name, tokens, token_index)
|
|
1515
1524
|
return nil unless %w[zero default reinterpret].include?(name)
|
|
1516
1525
|
|
|
@@ -44,47 +44,62 @@ module MilkTea
|
|
|
44
44
|
while i < tokens.length - 1
|
|
45
45
|
callee = tokens[i]
|
|
46
46
|
next_tok = tokens[i + 1]
|
|
47
|
-
|
|
48
47
|
prev_tok = i > 0 ? tokens[i - 1] : nil
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
lparen_index = nil
|
|
49
|
+
binding = nil
|
|
50
|
+
lparen_index = nil
|
|
53
51
|
|
|
52
|
+
if callee.type == :identifier && prev_tok&.type != :function
|
|
53
|
+
# Direct function call: func(...)
|
|
54
54
|
if next_tok&.type == :lparen
|
|
55
55
|
binding = facts.functions[callee.lexeme]
|
|
56
|
+
binding ||= facts.imports.each_value.find { |mod| mod.functions.key?(callee.lexeme) }&.functions&.dig(callee.lexeme)
|
|
56
57
|
lparen_index = i + 1
|
|
57
58
|
elsif next_tok&.type == :dot
|
|
58
59
|
member = tokens[i + 2]
|
|
59
60
|
member_lparen = tokens[i + 3]
|
|
60
61
|
if member&.type == :identifier && member_lparen&.type == :lparen
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
# Module-qualified call: mod.func(...)
|
|
63
|
+
mod_binding = facts.imports[callee.lexeme]
|
|
64
|
+
if mod_binding
|
|
65
|
+
binding = mod_binding.functions[member.lexeme]
|
|
66
|
+
else
|
|
67
|
+
# Instance method call: obj.method(...) or Type.static(...)
|
|
68
|
+
receiver_type = resolve_dot_receiver_value_type(facts, callee.lexeme, callee.line, callee.column)
|
|
69
|
+
receiver_type ||= facts.types[callee.lexeme]
|
|
70
|
+
unless receiver_type
|
|
71
|
+
receiver_type = facts.imports.each_value.find { |mod| mod.types.key?(callee.lexeme) }&.types&.dig(callee.lexeme)
|
|
72
|
+
end
|
|
73
|
+
if receiver_type
|
|
74
|
+
methods = methods_for_receiver_type(facts, receiver_type)
|
|
75
|
+
binding = methods[member.lexeme] || methods["static:#{member.lexeme}"]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
63
78
|
lparen_index = i + 3
|
|
64
79
|
end
|
|
65
80
|
end
|
|
81
|
+
end
|
|
66
82
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
i = closing_index if closing_index
|
|
83
|
+
if binding && lparen_index
|
|
84
|
+
arg_starts, closing_index = collect_call_argument_starts(tokens, lparen_index)
|
|
85
|
+
params_list = binding.respond_to?(:type) ? binding.type.params : []
|
|
86
|
+
|
|
87
|
+
arg_starts.each_with_index do |arg_tok, index|
|
|
88
|
+
break if index >= params_list.length
|
|
89
|
+
next unless position_in_range?(arg_tok.line - 1, arg_tok.column - 1, start_line, start_char, end_line, end_char)
|
|
90
|
+
next if self_describing_argument_expression?(tokens, arg_tok)
|
|
91
|
+
param_name = params_list[index].name
|
|
92
|
+
next if arg_tok.type == :identifier && arg_tok.lexeme == param_name
|
|
93
|
+
|
|
94
|
+
hints << {
|
|
95
|
+
position: { line: arg_tok.line - 1, character: arg_tok.column - 1 },
|
|
96
|
+
label: "#{params_list[index].name}: ",
|
|
97
|
+
kind: 2,
|
|
98
|
+
paddingRight: true
|
|
99
|
+
}
|
|
87
100
|
end
|
|
101
|
+
|
|
102
|
+
i = closing_index if closing_index
|
|
88
103
|
end
|
|
89
104
|
|
|
90
105
|
i += 1
|
|
@@ -121,6 +136,12 @@ module MilkTea
|
|
|
121
136
|
next unless position_in_range?(func.line - 1, func.column - 1, start_line, start_char, end_line, end_char)
|
|
122
137
|
|
|
123
138
|
binding = facts.functions[func.name]
|
|
139
|
+
unless binding
|
|
140
|
+
facts.imports.each_value do |mod|
|
|
141
|
+
binding = mod.functions[func.name]
|
|
142
|
+
break if binding
|
|
143
|
+
end
|
|
144
|
+
end
|
|
124
145
|
next unless binding
|
|
125
146
|
|
|
126
147
|
return_type = binding.type.return_type
|
|
@@ -311,6 +311,30 @@ module MilkTea
|
|
|
311
311
|
unless scoped.nil?
|
|
312
312
|
return scoped.map { |entry| { range: entry[:range], kind: 1 } }
|
|
313
313
|
end
|
|
314
|
+
|
|
315
|
+
binding_id = begin
|
|
316
|
+
rename_target_binding_id(uri, token, lsp_line, lsp_char, facts)
|
|
317
|
+
rescue StandardError
|
|
318
|
+
nil
|
|
319
|
+
end
|
|
320
|
+
if binding_id
|
|
321
|
+
ranges = begin
|
|
322
|
+
scoped_binding_occurrence_ranges(uri, token.lexeme, facts, binding_id, include_declaration: true)
|
|
323
|
+
rescue StandardError
|
|
324
|
+
[]
|
|
325
|
+
end
|
|
326
|
+
unless ranges.empty?
|
|
327
|
+
return ranges.map do |range|
|
|
328
|
+
{
|
|
329
|
+
range: {
|
|
330
|
+
start: { line: range[:line] - 1, character: range[:column] - 1 },
|
|
331
|
+
end: { line: range[:line] - 1, character: range[:column] - 1 + range[:length] },
|
|
332
|
+
},
|
|
333
|
+
kind: 1,
|
|
334
|
+
}
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
314
338
|
end
|
|
315
339
|
|
|
316
340
|
toks = @workspace.get_tokens(uri) || []
|
|
@@ -70,11 +70,6 @@ module MilkTea
|
|
|
70
70
|
workspace_symbol_changes = workspace_symbol_identity_rename_changes(uri, token, lsp_line, lsp_char, new_name)
|
|
71
71
|
return { changes: workspace_symbol_changes } if workspace_symbol_changes
|
|
72
72
|
|
|
73
|
-
if (facts = @workspace.get_facts(uri))
|
|
74
|
-
module_symbol_changes = module_level_symbol_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
75
|
-
return { changes: module_symbol_changes } if module_symbol_changes
|
|
76
|
-
end
|
|
77
|
-
|
|
78
73
|
lexical_changes = lexical_rename_changes_in_document(uri, token.lexeme, new_name)
|
|
79
74
|
return { changes: lexical_changes } if lexical_changes
|
|
80
75
|
|
|
@@ -202,27 +197,6 @@ module MilkTea
|
|
|
202
197
|
{ uri => edits }
|
|
203
198
|
end
|
|
204
199
|
|
|
205
|
-
def module_level_symbol_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
206
|
-
name = token.lexeme
|
|
207
|
-
module_level = facts.functions.key?(name) || facts.values.key?(name) || facts.types.key?(name) || facts.interfaces&.key?(name)
|
|
208
|
-
return nil unless module_level
|
|
209
|
-
|
|
210
|
-
related_uris = @workspace.related_open_document_uris(uri)
|
|
211
|
-
changes = {}
|
|
212
|
-
[uri, *related_uris].uniq.each do |doc_uri|
|
|
213
|
-
edits = []
|
|
214
|
-
doc_tokens = @workspace.get_tokens(doc_uri) || []
|
|
215
|
-
doc_tokens.each do |tok|
|
|
216
|
-
next unless tok.type == :identifier && tok.lexeme == name
|
|
217
|
-
edits << { range: token_to_range(tok), newText: new_name }
|
|
218
|
-
end
|
|
219
|
-
changes[doc_uri] = edits unless edits.empty?
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
return nil if changes.empty?
|
|
223
|
-
changes
|
|
224
|
-
end
|
|
225
|
-
|
|
226
200
|
def import_alias_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
227
201
|
alias_name = token.lexeme
|
|
228
202
|
if facts
|
|
@@ -286,22 +260,28 @@ module MilkTea
|
|
|
286
260
|
type_name_member_access?(tokens, cursor_index, facts)
|
|
287
261
|
return nil unless cursor_is_enum_member
|
|
288
262
|
|
|
289
|
-
|
|
290
|
-
|
|
263
|
+
changes = {}
|
|
264
|
+
[uri, *@workspace.related_open_document_uris(uri)].uniq.each do |doc_uri|
|
|
265
|
+
doc_tokens = @workspace.get_tokens(doc_uri) || []
|
|
266
|
+
doc_facts = doc_uri == uri ? facts : @workspace.get_facts(doc_uri)
|
|
267
|
+
edits = doc_tokens.each_with_index.filter_map do |tok, i|
|
|
268
|
+
next unless tok.type == :identifier && tok.lexeme == token.lexeme
|
|
291
269
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
270
|
+
enum_member_decl = variant_enum_member_declaration?(doc_tokens, i)
|
|
271
|
+
enum_member_access = type_name_member_access?(doc_tokens, i, doc_facts)
|
|
272
|
+
next unless enum_member_decl || enum_member_access
|
|
295
273
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
274
|
+
{
|
|
275
|
+
range: token_to_range(tok),
|
|
276
|
+
newText: new_name,
|
|
277
|
+
}
|
|
278
|
+
end
|
|
301
279
|
|
|
302
|
-
|
|
280
|
+
changes[doc_uri] = edits unless edits.empty?
|
|
281
|
+
end
|
|
303
282
|
|
|
304
|
-
|
|
283
|
+
return nil if changes.empty?
|
|
284
|
+
changes
|
|
305
285
|
end
|
|
306
286
|
|
|
307
287
|
def scoped_local_reference_locations(uri, token, lsp_line, lsp_char, facts, include_declaration:)
|
|
@@ -482,16 +462,28 @@ module MilkTea
|
|
|
482
462
|
struct_type = find_struct_containing_field(facts, field_name)
|
|
483
463
|
return nil unless struct_type
|
|
484
464
|
|
|
465
|
+
changes = collect_struct_field_changes(uri, field_name, new_name)
|
|
466
|
+
related_uris = @workspace.related_open_document_uris(uri)
|
|
467
|
+
related_uris.each do |related_uri|
|
|
468
|
+
next if related_uri == uri
|
|
469
|
+
related_changes = collect_struct_field_changes(related_uri, field_name, new_name)
|
|
470
|
+
changes[related_uri] = related_changes if related_changes
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
return nil if changes.empty?
|
|
474
|
+
changes
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def collect_struct_field_changes(uri, field_name, new_name)
|
|
478
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
485
479
|
edits = []
|
|
486
480
|
tokens.each_with_index do |tok, i|
|
|
487
481
|
next unless tok.type == :identifier && tok.lexeme == field_name
|
|
488
|
-
next unless struct_field_edit_context?(tokens, i,
|
|
482
|
+
next unless struct_field_edit_context?(tokens, i, nil)
|
|
489
483
|
|
|
490
484
|
edits << { range: token_to_range(tok), newText: new_name }
|
|
491
485
|
end
|
|
492
|
-
|
|
493
|
-
return nil if edits.empty?
|
|
494
|
-
{ uri => edits }
|
|
486
|
+
edits.empty? ? nil : edits
|
|
495
487
|
end
|
|
496
488
|
|
|
497
489
|
def struct_field_cursor_context?(tokens, index)
|
|
@@ -555,17 +547,25 @@ module MilkTea
|
|
|
555
547
|
receiver_type = method_info[:receiver_type]
|
|
556
548
|
return nil unless receiver_type
|
|
557
549
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
550
|
+
changes = {}
|
|
551
|
+
[uri, *@workspace.related_open_document_uris(uri)].uniq.each do |doc_uri|
|
|
552
|
+
edits = []
|
|
553
|
+
doc_tokens = @workspace.get_tokens(doc_uri) || []
|
|
554
|
+
doc_tokens.each_with_index do |tok, i|
|
|
555
|
+
next unless tok.type == :identifier && tok.lexeme == method_name
|
|
563
556
|
|
|
564
|
-
|
|
557
|
+
is_call = i > 0 && doc_tokens[i - 1].type == :dot
|
|
558
|
+
is_def = doc_uri == uri && tok.line == token.line && tok.column == token.column
|
|
559
|
+
next unless is_call || is_def
|
|
560
|
+
|
|
561
|
+
edits << { range: token_to_range(tok), newText: new_name }
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
changes[doc_uri] = edits unless edits.empty?
|
|
565
565
|
end
|
|
566
566
|
|
|
567
|
-
return nil if
|
|
568
|
-
|
|
567
|
+
return nil if changes.empty?
|
|
568
|
+
changes
|
|
569
569
|
end
|
|
570
570
|
|
|
571
571
|
def find_method_at_position(uri, token, facts)
|
|
@@ -28,18 +28,25 @@ module MilkTea
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
if (receiver_type = resolve_dot_receiver_value_type(facts, dot_recv, lsp_line + 1, lsp_char + 1)
|
|
31
|
+
if (receiver_type = resolve_dot_receiver_value_type(facts, dot_recv, lsp_line + 1, lsp_char + 1) ||
|
|
32
|
+
resolve_dot_receiver_value_type(facts, dot_recv.sub(/\[.*\]\z/, ""), lsp_line + 1, lsp_char + 1))
|
|
32
33
|
methods = methods_for_receiver_type(facts, receiver_type)
|
|
33
34
|
if (binding = methods[name] || methods["static:#{name}"])
|
|
34
35
|
return [binding, name]
|
|
35
36
|
end
|
|
36
37
|
end
|
|
37
38
|
|
|
38
|
-
if (type_receiver = resolve_type_receiver_info(facts, dot_recv, nil)
|
|
39
|
+
if (type_receiver = resolve_type_receiver_info(facts, dot_recv, nil) ||
|
|
40
|
+
resolve_type_receiver_info(facts, dot_recv.sub(/\[.*\]\z/, ""), nil))
|
|
39
41
|
methods = methods_for_receiver_type(facts, type_receiver[:type])
|
|
40
42
|
if (binding = methods[name] || methods["static:#{name}"])
|
|
41
43
|
return [binding, name]
|
|
42
44
|
end
|
|
45
|
+
if type_receiver[:type].respond_to?(:arms) && (arm = type_receiver[:type].arms[name])
|
|
46
|
+
if arm.respond_to?(:payload) && arm.payload
|
|
47
|
+
return [arm.payload, name]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
43
50
|
end
|
|
44
51
|
end
|
|
45
52
|
|
|
@@ -60,7 +67,7 @@ module MilkTea
|
|
|
60
67
|
end
|
|
61
68
|
|
|
62
69
|
# 6. Type constructor (struct constructor)
|
|
63
|
-
if (type = facts.types[name])
|
|
70
|
+
if (type = facts.types[name] || facts.imports.each_value.find { |mod| mod.types.key?(name) }&.types&.dig(name))
|
|
64
71
|
if type.respond_to?(:fields) && !type.fields.empty?
|
|
65
72
|
return [type, name]
|
|
66
73
|
end
|
|
@@ -99,12 +106,13 @@ module MilkTea
|
|
|
99
106
|
end
|
|
100
107
|
|
|
101
108
|
return nil unless extending
|
|
102
|
-
facts.types[extending.type_name]
|
|
109
|
+
facts.types[extending.type_name] ||
|
|
110
|
+
facts.imports.each_value.find { |mod| mod.types.key?(extending.type_name) }&.types&.dig(extending.type_name)
|
|
103
111
|
end
|
|
104
112
|
|
|
105
113
|
def build_signature_from_binding(binding, name, ctx)
|
|
106
|
-
if binding.is_a?(Types::Struct) || binding.is_a?(Types::StructInstance)
|
|
107
|
-
fields = binding.fields
|
|
114
|
+
if binding.is_a?(Types::Struct) || binding.is_a?(Types::StructInstance) || binding.is_a?(Types::VariantArmPayload)
|
|
115
|
+
fields = binding.is_a?(Types::StructInstance) ? binding.definition.fields : binding.fields
|
|
108
116
|
params_list = fields.map { |fname, ftype| Types::Registry.parameter(fname, ftype) }
|
|
109
117
|
return_type_label = binding.is_a?(Types::StructInstance) ? binding.to_s : binding.name
|
|
110
118
|
elsif binding.respond_to?(:[])
|
|
@@ -120,6 +128,7 @@ module MilkTea
|
|
|
120
128
|
activeParameter: ctx[:active_parameter],
|
|
121
129
|
}
|
|
122
130
|
else
|
|
131
|
+
return nil unless binding.respond_to?(:type) && binding.type.respond_to?(:params)
|
|
123
132
|
params_list = binding.type.params
|
|
124
133
|
return_type_label = binding.type.return_type
|
|
125
134
|
end
|
|
@@ -6,7 +6,15 @@ module MilkTea
|
|
|
6
6
|
module WorkspaceCaches
|
|
7
7
|
def get_content(uri)
|
|
8
8
|
@document_state_mutex.synchronize do
|
|
9
|
-
@open_documents[uri] || @indexed_documents[uri] ||
|
|
9
|
+
@open_documents[uri] || @indexed_documents[uri] ||
|
|
10
|
+
begin
|
|
11
|
+
path = uri_to_path(uri)
|
|
12
|
+
if path && File.file?(path)
|
|
13
|
+
@indexed_documents[uri] = File.read(path)
|
|
14
|
+
end
|
|
15
|
+
rescue StandardError
|
|
16
|
+
nil
|
|
17
|
+
end || ''
|
|
10
18
|
end
|
|
11
19
|
end
|
|
12
20
|
|
data/std/option.mt
CHANGED
|
@@ -8,6 +8,7 @@ public variant Option[T]:
|
|
|
8
8
|
none
|
|
9
9
|
|
|
10
10
|
extending Option[T]:
|
|
11
|
+
## Returns true when the option holds a value.
|
|
11
12
|
public function is_some() -> bool:
|
|
12
13
|
match this:
|
|
13
14
|
Option.some:
|
|
@@ -15,6 +16,7 @@ extending Option[T]:
|
|
|
15
16
|
Option.none:
|
|
16
17
|
return false
|
|
17
18
|
|
|
19
|
+
## Returns true when the option holds no value.
|
|
18
20
|
public function is_none() -> bool:
|
|
19
21
|
match this:
|
|
20
22
|
Option.some:
|
|
@@ -22,6 +24,7 @@ extending Option[T]:
|
|
|
22
24
|
Option.none:
|
|
23
25
|
return true
|
|
24
26
|
|
|
27
|
+
## Returns the contained value or aborts via fatal.
|
|
25
28
|
public function unwrap() -> T:
|
|
26
29
|
match this:
|
|
27
30
|
Option.some as payload:
|
|
@@ -29,6 +32,7 @@ extending Option[T]:
|
|
|
29
32
|
Option.none:
|
|
30
33
|
fatal(c"called Option.unwrap on a none value")
|
|
31
34
|
|
|
35
|
+
## Returns the contained value or aborts with the given message.
|
|
32
36
|
public function expect(msg: str) -> T:
|
|
33
37
|
match this:
|
|
34
38
|
Option.some as payload:
|
|
@@ -36,6 +40,7 @@ extending Option[T]:
|
|
|
36
40
|
Option.none:
|
|
37
41
|
fatal(msg)
|
|
38
42
|
|
|
43
|
+
## Returns the contained value or a default.
|
|
39
44
|
public function unwrap_or(default: T) -> T:
|
|
40
45
|
match this:
|
|
41
46
|
Option.some as payload:
|
|
@@ -43,6 +48,7 @@ extending Option[T]:
|
|
|
43
48
|
Option.none:
|
|
44
49
|
return default
|
|
45
50
|
|
|
51
|
+
## Returns the contained value or calls a fallback closure.
|
|
46
52
|
public function unwrap_or_else(f: proc() -> T) -> T:
|
|
47
53
|
match this:
|
|
48
54
|
Option.some as payload:
|
data/std/result.mt
CHANGED
|
@@ -11,6 +11,7 @@ public variant Result[T, E]:
|
|
|
11
11
|
failure(error: E)
|
|
12
12
|
|
|
13
13
|
extending Result[T, E]:
|
|
14
|
+
## Returns true when the result holds a success value.
|
|
14
15
|
public function is_success() -> bool:
|
|
15
16
|
match this:
|
|
16
17
|
Result.success:
|
|
@@ -18,6 +19,7 @@ extending Result[T, E]:
|
|
|
18
19
|
Result.failure:
|
|
19
20
|
return false
|
|
20
21
|
|
|
22
|
+
## Returns true when the result holds a failure value.
|
|
21
23
|
public function is_failure() -> bool:
|
|
22
24
|
match this:
|
|
23
25
|
Result.success:
|
|
@@ -25,6 +27,7 @@ extending Result[T, E]:
|
|
|
25
27
|
Result.failure:
|
|
26
28
|
return true
|
|
27
29
|
|
|
30
|
+
## Returns the success value or aborts via fatal.
|
|
28
31
|
public function unwrap() -> T:
|
|
29
32
|
match this:
|
|
30
33
|
Result.success as payload:
|
|
@@ -32,6 +35,7 @@ extending Result[T, E]:
|
|
|
32
35
|
Result.failure:
|
|
33
36
|
fatal(c"called Result.unwrap on a failure value")
|
|
34
37
|
|
|
38
|
+
## Returns the success value or aborts with the given message.
|
|
35
39
|
public function expect(msg: str) -> T:
|
|
36
40
|
match this:
|
|
37
41
|
Result.success as payload:
|
|
@@ -39,6 +43,7 @@ extending Result[T, E]:
|
|
|
39
43
|
Result.failure:
|
|
40
44
|
fatal(msg)
|
|
41
45
|
|
|
46
|
+
## Returns the failure error value or aborts via fatal.
|
|
42
47
|
public function unwrap_error() -> E:
|
|
43
48
|
match this:
|
|
44
49
|
Result.success:
|
|
@@ -46,6 +51,7 @@ extending Result[T, E]:
|
|
|
46
51
|
Result.failure as payload:
|
|
47
52
|
return payload.error
|
|
48
53
|
|
|
54
|
+
## Returns the failure error value or aborts with the given message.
|
|
49
55
|
public function expect_error(msg: str) -> E:
|
|
50
56
|
match this:
|
|
51
57
|
Result.success:
|
|
@@ -53,6 +59,7 @@ extending Result[T, E]:
|
|
|
53
59
|
Result.failure as payload:
|
|
54
60
|
return payload.error
|
|
55
61
|
|
|
62
|
+
## Returns the success value or a default.
|
|
56
63
|
public function unwrap_or(default: T) -> T:
|
|
57
64
|
match this:
|
|
58
65
|
Result.success as payload:
|
|
@@ -60,6 +67,7 @@ extending Result[T, E]:
|
|
|
60
67
|
Result.failure:
|
|
61
68
|
return default
|
|
62
69
|
|
|
70
|
+
## Returns the success value or calls a fallback closure with the error.
|
|
63
71
|
public function unwrap_or_else(f: proc(error: E) -> T) -> T:
|
|
64
72
|
match this:
|
|
65
73
|
Result.success as payload:
|
|
@@ -67,6 +75,7 @@ extending Result[T, E]:
|
|
|
67
75
|
Result.failure as payload:
|
|
68
76
|
return f(error=payload.error)
|
|
69
77
|
|
|
78
|
+
## Maps the error through a closure while preserving the success value.
|
|
70
79
|
public function map_error[F](f: proc(error: E) -> F) -> Result[T, F]:
|
|
71
80
|
match this:
|
|
72
81
|
Result.success as payload:
|
|
@@ -74,6 +83,7 @@ extending Result[T, E]:
|
|
|
74
83
|
Result.failure as payload:
|
|
75
84
|
return Result[T, F].failure(error = f(payload.error))
|
|
76
85
|
|
|
86
|
+
## Converts the result into an Option, discarding the error.
|
|
77
87
|
public function ok() -> Option[T]:
|
|
78
88
|
match this:
|
|
79
89
|
Result.success as payload:
|
|
@@ -81,6 +91,7 @@ extending Result[T, E]:
|
|
|
81
91
|
Result.failure:
|
|
82
92
|
return Option[T].none
|
|
83
93
|
|
|
94
|
+
## Converts the failure into an Option, discarding the success value.
|
|
84
95
|
public function error() -> Option[E]:
|
|
85
96
|
match this:
|
|
86
97
|
Result.success:
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mt-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -583,7 +583,7 @@ metadata:
|
|
|
583
583
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
584
584
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
585
585
|
post_install_message: |
|
|
586
|
-
Milk Tea 0.2.
|
|
586
|
+
Milk Tea 0.2.14 installed!
|
|
587
587
|
|
|
588
588
|
System requirements:
|
|
589
589
|
- A C compiler (gcc or clang) must be available on PATH
|