mt-lang 0.2.12 → 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/parser/declarations.rb +1 -8
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +21 -2
- 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 +173 -31
- 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
|
@@ -472,20 +472,13 @@ module MilkTea
|
|
|
472
472
|
|
|
473
473
|
members = []
|
|
474
474
|
skip_newlines
|
|
475
|
-
auto_value = 0
|
|
476
475
|
until check(:dedent) || eof?
|
|
477
476
|
member_token = consume_name("expected member name")
|
|
478
477
|
member_name = member_token.lexeme
|
|
479
478
|
if match(:equal)
|
|
480
479
|
value = parse_expression
|
|
481
|
-
if value.is_a?(AST::IntegerLiteral)
|
|
482
|
-
auto_value = value.value + 1
|
|
483
|
-
elsif value.is_a?(AST::UnaryOp) && value.operator == "-" && value.operand.is_a?(AST::IntegerLiteral)
|
|
484
|
-
auto_value = -value.operand.value + 1
|
|
485
|
-
end
|
|
486
480
|
else
|
|
487
|
-
value =
|
|
488
|
-
auto_value += 1
|
|
481
|
+
value = nil
|
|
489
482
|
end
|
|
490
483
|
consume_end_of_statement
|
|
491
484
|
members << AST::EnumMember.new(name: member_name, value:, line: member_token.line, column: member_token.column)
|
|
@@ -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"
|
|
@@ -581,8 +595,13 @@ module MilkTea
|
|
|
581
595
|
|
|
582
596
|
decl.members.each do |member|
|
|
583
597
|
begin
|
|
584
|
-
|
|
585
|
-
|
|
598
|
+
if member.value
|
|
599
|
+
actual_type = infer_expression(member.value, scopes: [], expected_type: backing_type)
|
|
600
|
+
const_value = evaluate_enum_member_const_value(member.value, enum_type:, member_values:)
|
|
601
|
+
else
|
|
602
|
+
const_value = (member_values.values.last&.succ || 0)
|
|
603
|
+
actual_type = backing_type
|
|
604
|
+
end
|
|
586
605
|
|
|
587
606
|
compatible = types_compatible?(actual_type, backing_type, expression: member.value, scopes: [])
|
|
588
607
|
compatible ||= actual_type.is_a?(Types::EnumBase) && types_compatible?(actual_type.backing_type, backing_type, expression: member.value, scopes: [])
|
|
@@ -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
|
|
@@ -281,6 +281,13 @@ module MilkTea
|
|
|
281
281
|
'exchange' => 'static function exchange(value: T) -> T',
|
|
282
282
|
'compare_exchange' => 'static function compare_exchange(expected: T, desired: T) -> bool',
|
|
283
283
|
},
|
|
284
|
+
'event' => {
|
|
285
|
+
'subscribe' => 'function subscribe(listener) -> Result[Subscription, EventError]',
|
|
286
|
+
'subscribe_once' => 'function subscribe_once(listener) -> Result[Subscription, EventError]',
|
|
287
|
+
'unsubscribe' => 'function unsubscribe(subscription) -> bool',
|
|
288
|
+
'emit' => 'function emit() / function emit(payload)',
|
|
289
|
+
'wait' => 'function wait() -> Task[Result[T, EventError]]',
|
|
290
|
+
},
|
|
284
291
|
'str_buffer' => {
|
|
285
292
|
'assign' => 'static function assign(value: str) -> void',
|
|
286
293
|
'append' => 'static function append(value: str) -> void',
|
|
@@ -307,20 +314,23 @@ module MilkTea
|
|
|
307
314
|
token = context&.fetch(:token, nil)
|
|
308
315
|
token_kind = token&.type || :none
|
|
309
316
|
unless token&.type == :identifier
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
|
321
330
|
|
|
322
|
-
|
|
323
|
-
|
|
331
|
+
result_state = 'not-identifier'
|
|
332
|
+
return nil
|
|
333
|
+
end
|
|
324
334
|
end
|
|
325
335
|
|
|
326
336
|
info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
|
|
@@ -355,10 +365,11 @@ module MilkTea
|
|
|
355
365
|
token_index = context[:token_index]
|
|
356
366
|
end
|
|
357
367
|
|
|
358
|
-
return nil unless token&.type == :identifier
|
|
359
|
-
|
|
360
368
|
tokens ||= @workspace.get_tokens(uri) || []
|
|
361
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
|
+
|
|
362
373
|
if token_index
|
|
363
374
|
module_info = module_declaration_info_at(tokens, token_index)
|
|
364
375
|
if module_info
|
|
@@ -412,6 +423,7 @@ module MilkTea
|
|
|
412
423
|
signature = nil
|
|
413
424
|
docs = nil
|
|
414
425
|
source_location = nil
|
|
426
|
+
resolved_via_type_member = false
|
|
415
427
|
|
|
416
428
|
if (binding = method_binding_at_token(facts, token))
|
|
417
429
|
signature = method_signature(binding)
|
|
@@ -449,11 +461,26 @@ module MilkTea
|
|
|
449
461
|
type = facts.types[name]
|
|
450
462
|
signature = type_hover_signature(name, type)
|
|
451
463
|
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
464
|
+
elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
|
|
465
|
+
signature = type_hover_signature(name, nested)
|
|
466
|
+
docs ||= BUILTIN_TYPE_DOCS[name]
|
|
452
467
|
elsif (binding = facts.values[name])
|
|
453
468
|
signature = value_hover_signature(binding)
|
|
469
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
|
|
470
|
+
type, member, value = member_info
|
|
471
|
+
signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
|
|
472
|
+
resolved_via_type_member = true
|
|
473
|
+
elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
|
|
474
|
+
signature = arm_sig
|
|
475
|
+
resolved_via_type_member = true
|
|
454
476
|
elsif (import_binding = facts.imports[name])
|
|
455
477
|
signature = "module #{import_binding.name}"
|
|
456
478
|
source_location = module_definition_location(uri, import_binding.name)
|
|
479
|
+
elsif (attr_binding = facts.attributes[name])
|
|
480
|
+
targets = attr_binding.targets.map(&:to_s).join(", ")
|
|
481
|
+
params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
|
|
482
|
+
signature = "attribute [#{targets}] #{name}(#{params_str})"
|
|
483
|
+
source_location ||= module_definition_location(uri, facts.module_name)
|
|
457
484
|
else
|
|
458
485
|
dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
|
|
459
486
|
dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
|
|
@@ -499,7 +526,7 @@ module MilkTea
|
|
|
499
526
|
if (method_binding = methods[name])
|
|
500
527
|
signature = method_signature(method_binding)
|
|
501
528
|
else
|
|
502
|
-
type_base = receiver_type.to_s[/^([
|
|
529
|
+
type_base = receiver_type.to_s[/^([A-Za-z_]+)/, 1]
|
|
503
530
|
if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
|
|
504
531
|
signature = method_sigs[name]
|
|
505
532
|
end
|
|
@@ -516,18 +543,17 @@ module MilkTea
|
|
|
516
543
|
end
|
|
517
544
|
|
|
518
545
|
unless signature
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
name,
|
|
522
|
-
preferred_uri: uri,
|
|
523
|
-
before_line: lsp_line + 1,
|
|
524
|
-
before_char: lsp_char + 1,
|
|
525
|
-
)
|
|
526
|
-
if local_def
|
|
527
|
-
signature = resolve_lexical_local_hover_signature(local_def[:uri], name, local_def[:token])
|
|
528
|
-
end
|
|
546
|
+
if token_index && tokens && parameter_declaration_token?(tokens, token_index)
|
|
547
|
+
signature = resolve_lexical_local_hover_signature(uri, name, tokens[token_index])
|
|
529
548
|
end
|
|
530
549
|
end
|
|
550
|
+
|
|
551
|
+
unless signature
|
|
552
|
+
if token_index && tokens && attribute_target_token?(tokens, token_index)
|
|
553
|
+
signature = "attribute target #{name}"
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
531
557
|
end
|
|
532
558
|
|
|
533
559
|
return nil unless signature
|
|
@@ -535,6 +561,8 @@ module MilkTea
|
|
|
535
561
|
|
|
536
562
|
definition_entry = if source_location
|
|
537
563
|
measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
|
|
564
|
+
elsif resolved_via_type_member
|
|
565
|
+
nil
|
|
538
566
|
else
|
|
539
567
|
measure_perf_stage(stages, 'global_definition') do
|
|
540
568
|
@workspace.find_definition_token_global(
|
|
@@ -961,9 +989,10 @@ module MilkTea
|
|
|
961
989
|
source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
|
|
962
990
|
|
|
963
991
|
if segment[:token_index] == token_index
|
|
992
|
+
definition_entry = hover_definition_entry_from_location(source_location)
|
|
964
993
|
return {
|
|
965
994
|
signature: field_hover_signature(segment[:name], field_type),
|
|
966
|
-
docs:
|
|
995
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
967
996
|
source: hover_source_label_from_location(source_location),
|
|
968
997
|
source_uri: hover_source_uri_from_location(source_location),
|
|
969
998
|
source_line: hover_source_line_from_location(source_location),
|
|
@@ -978,7 +1007,7 @@ module MilkTea
|
|
|
978
1007
|
if segment[:token_index] == token_index
|
|
979
1008
|
return {
|
|
980
1009
|
signature: type_hover_signature(segment[:name], nested),
|
|
981
|
-
docs:
|
|
1010
|
+
docs: BUILTIN_TYPE_DOCS[segment[:name]],
|
|
982
1011
|
}
|
|
983
1012
|
end
|
|
984
1013
|
current_type = nested
|
|
@@ -993,10 +1022,11 @@ module MilkTea
|
|
|
993
1022
|
|
|
994
1023
|
source_location = module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding])
|
|
995
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)
|
|
996
1026
|
|
|
997
1027
|
return {
|
|
998
1028
|
signature: method_signature(method_info[:binding]),
|
|
999
|
-
docs:
|
|
1029
|
+
docs: hover_doc_comment_for_definition(definition_entry),
|
|
1000
1030
|
source: hover_source_label_from_location(source_location),
|
|
1001
1031
|
source_uri: hover_source_uri_from_location(source_location),
|
|
1002
1032
|
source_line: hover_source_line_from_location(source_location),
|
|
@@ -1386,6 +1416,43 @@ module MilkTea
|
|
|
1386
1416
|
"field #{name}: #{type}"
|
|
1387
1417
|
end
|
|
1388
1418
|
|
|
1419
|
+
def find_nested_type_by_short_name(facts, short_name)
|
|
1420
|
+
matches = facts.types.keys.select { |k| k.to_s.end_with?(".#{short_name}") }
|
|
1421
|
+
return nil unless matches.length == 1
|
|
1422
|
+
|
|
1423
|
+
facts.types[matches.first]
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1426
|
+
def find_member_in_types(facts, name)
|
|
1427
|
+
facts.types.reverse_each do |_key, type|
|
|
1428
|
+
next unless type.respond_to?(:members)
|
|
1429
|
+
|
|
1430
|
+
member = type.members.find { |m| m == name }
|
|
1431
|
+
if member
|
|
1432
|
+
value = type.respond_to?(:member_value) ? type.member_value(name) : nil
|
|
1433
|
+
return [type, member, value]
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1436
|
+
nil
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
def find_variant_arm_in_types(facts, name)
|
|
1440
|
+
facts.types.reverse_each do |_key, type|
|
|
1441
|
+
arm = nil
|
|
1442
|
+
if type.respond_to?(:arms)
|
|
1443
|
+
arm = type.arms[name]
|
|
1444
|
+
elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
|
|
1445
|
+
arm = type.arm(name)
|
|
1446
|
+
end
|
|
1447
|
+
next unless arm
|
|
1448
|
+
|
|
1449
|
+
fields = arm.map { |fname, ftype| "#{fname}: #{ftype}" }.join(", ")
|
|
1450
|
+
field_str = fields.empty? ? "" : "(#{fields})"
|
|
1451
|
+
return "#{type.name}.#{name}#{field_str}"
|
|
1452
|
+
end
|
|
1453
|
+
nil
|
|
1454
|
+
end
|
|
1455
|
+
|
|
1389
1456
|
def builtin_hover_info(name, tokens, token_index)
|
|
1390
1457
|
specialization_info = builtin_value_specialization_info(name, tokens, token_index)
|
|
1391
1458
|
return specialization_info if specialization_info
|
|
@@ -1399,11 +1466,60 @@ module MilkTea
|
|
|
1399
1466
|
builtin_call_hover_info(name, tokens, token_index)
|
|
1400
1467
|
end
|
|
1401
1468
|
|
|
1469
|
+
def parameter_declaration_token?(tokens, index)
|
|
1470
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1471
|
+
|
|
1472
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1473
|
+
return false unless prev
|
|
1474
|
+
return false unless [:lparen, :comma].include?(tokens[prev].type)
|
|
1475
|
+
|
|
1476
|
+
nxt = next_non_trivia_token_index(tokens, index + 1)
|
|
1477
|
+
nxt && tokens[nxt].type == :colon
|
|
1478
|
+
end
|
|
1479
|
+
|
|
1480
|
+
def attribute_target_token?(tokens, index)
|
|
1481
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1482
|
+
|
|
1483
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1484
|
+
return false unless prev && [:lbracket, :comma].include?(tokens[prev].type)
|
|
1485
|
+
|
|
1486
|
+
after = next_non_trivia_token_index(tokens, index + 1)
|
|
1487
|
+
return false unless after && [:rbracket, :comma].include?(tokens[after].type)
|
|
1488
|
+
|
|
1489
|
+
true
|
|
1490
|
+
end
|
|
1491
|
+
|
|
1492
|
+
def call_argument_token?(tokens, index)
|
|
1493
|
+
return false unless index && tokens[index]&.type == :identifier
|
|
1494
|
+
|
|
1495
|
+
prev = previous_non_trivia_token_index(tokens, index)
|
|
1496
|
+
return false unless prev && [:lparen, :comma].include?(tokens[prev].type)
|
|
1497
|
+
|
|
1498
|
+
nxt = next_non_trivia_token_index(tokens, index + 1)
|
|
1499
|
+
!nxt || ![:colon, :rbracket, :comma].include?(tokens[nxt].type)
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1402
1502
|
def builtin_in_member_access_context?(tokens, token_index)
|
|
1403
1503
|
prev_index = previous_non_trivia_token_index(tokens, token_index)
|
|
1404
1504
|
prev_index && tokens[prev_index].type == :dot
|
|
1405
1505
|
end
|
|
1406
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
|
+
|
|
1407
1523
|
def builtin_value_specialization_info(name, tokens, token_index)
|
|
1408
1524
|
return nil unless %w[zero default reinterpret].include?(name)
|
|
1409
1525
|
|
|
@@ -1439,7 +1555,7 @@ module MilkTea
|
|
|
1439
1555
|
end
|
|
1440
1556
|
|
|
1441
1557
|
def builtin_type_constructor_hover_info(name, tokens, token_index)
|
|
1442
|
-
return nil unless %w[array span Option Result SoA str_buffer].include?(name)
|
|
1558
|
+
return nil unless %w[array span Option Result SoA str_buffer ref ptr const_ptr own Task atomic].include?(name)
|
|
1443
1559
|
|
|
1444
1560
|
lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
|
|
1445
1561
|
return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
|
|
@@ -1494,6 +1610,18 @@ module MilkTea
|
|
|
1494
1610
|
'`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
|
|
1495
1611
|
when 'str_buffer'
|
|
1496
1612
|
'`str_buffer[N]` is a fixed-capacity mutable UTF-8 text buffer. Methods: `assign`, `append`, `assign_format`, `append_format`, `clear`, `len`, `as_str`, `as_cstr`.'
|
|
1613
|
+
when 'ref'
|
|
1614
|
+
'`ref[T]` is a non-null borrow reference. Auto-dereferences for member access and method calls. Cannot be stored in module-level variables, constants, or nested containers.'
|
|
1615
|
+
when 'ptr'
|
|
1616
|
+
'`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
|
|
1617
|
+
when 'const_ptr'
|
|
1618
|
+
'`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
|
|
1619
|
+
when 'own'
|
|
1620
|
+
'`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
|
|
1621
|
+
when 'Task'
|
|
1622
|
+
'`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
|
|
1623
|
+
when 'atomic'
|
|
1624
|
+
'`atomic[T]` is an atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load`, `store`, `add`, `sub`, `exchange`.'
|
|
1497
1625
|
end
|
|
1498
1626
|
|
|
1499
1627
|
{
|
|
@@ -1734,6 +1862,14 @@ module MilkTea
|
|
|
1734
1862
|
when "let" then kind = :let
|
|
1735
1863
|
when "var" then kind = :var
|
|
1736
1864
|
when "const" then kind = :const
|
|
1865
|
+
when "struct" then kind = :struct_type
|
|
1866
|
+
when "function", "async", "external", "foreign" then kind = :function
|
|
1867
|
+
when "enum" then kind = :enum_type
|
|
1868
|
+
when "flags" then kind = :flags_type
|
|
1869
|
+
when "union" then kind = :union_type
|
|
1870
|
+
when "variant" then kind = :variant_type
|
|
1871
|
+
when "(" then kind = :param
|
|
1872
|
+
when "," then kind = :param
|
|
1737
1873
|
end
|
|
1738
1874
|
end
|
|
1739
1875
|
|
|
@@ -1760,9 +1896,15 @@ module MilkTea
|
|
|
1760
1896
|
end
|
|
1761
1897
|
|
|
1762
1898
|
kind ||= :let
|
|
1899
|
+
unless %i[let var const param].include?(kind)
|
|
1900
|
+
kind = kind.to_s.sub(/_type$/, "")
|
|
1901
|
+
return "#{kind} #{name}"
|
|
1902
|
+
end
|
|
1903
|
+
|
|
1904
|
+
display_kind = kind == :param ? "parameter" : kind.to_s
|
|
1763
1905
|
mutability = kind == :var ? "mutable" : "immutable"
|
|
1764
1906
|
if type_str && !type_str.empty?
|
|
1765
|
-
"#{
|
|
1907
|
+
"#{display_kind} #{name}: #{type_str} (#{mutability})"
|
|
1766
1908
|
else
|
|
1767
1909
|
"#{kind} #{name} (#{mutability})"
|
|
1768
1910
|
end
|
|
@@ -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
|