mt-lang 0.2.12 → 0.2.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28dc7f8c8824f11189bdd3cf704d10eefa2e144d466b218b5b34b1693531fe94
4
- data.tar.gz: 73dcea75aeb6fb9c460e6b574e0bb64dc118ca9cd0a028586bd526d7b00acb49
3
+ metadata.gz: 34c858250b3d56b9c9e2184e4cf3a29d180b176e49d77be5bffd52063a458718
4
+ data.tar.gz: 8ad1e294bd42fc71273ee495ff91b632b788a835c1f4d96203f298d6e2b6db6b
5
5
  SHA512:
6
- metadata.gz: c3286442bbca94bd51b9c7aa4166f2b854d9f6bd48da3f6860648f303c30c90e39f2ac531315a5f13a148f3591eab1a5a02dabfd935f6ea136dfe0018012db9d
7
- data.tar.gz: 53cc3240a7b226d152f831775e508a1db5c030f533d4fb6a88084f6564fcffa86954614e86b37f2c0b7650ae5ef27486e9aea05a6eaffe14b2aa5b2be9be0c8a
6
+ metadata.gz: ebd5cae94ad9eaa939d265bbc31d57a1b29ecb53b2abf8e3437b6264d0ce635ca21a64bbaeb930b4526c34a633fd5f8742ed579c3b7aa1ad63e4c953e98d3651
7
+ data.tar.gz: 977bea5a674e4a5a0b7eade459a18a7c7aaf1eb157c7e09bd7c13f4baf2665461e480943e8c8a509f21f399e5e9315c1c9b70d75d500bad20b7d9301af29aed6
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.2.12"
6
+ VERSION = "0.2.13"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -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 = AST::IntegerLiteral.new(lexeme: auto_value.to_s, value: auto_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)
@@ -581,8 +581,13 @@ module MilkTea
581
581
 
582
582
  decl.members.each do |member|
583
583
  begin
584
- actual_type = infer_expression(member.value, scopes: [], expected_type: backing_type)
585
- const_value = evaluate_enum_member_const_value(member.value, enum_type:, member_values:)
584
+ if member.value
585
+ actual_type = infer_expression(member.value, scopes: [], expected_type: backing_type)
586
+ const_value = evaluate_enum_member_const_value(member.value, enum_type:, member_values:)
587
+ else
588
+ const_value = (member_values.values.last&.succ || 0)
589
+ actual_type = backing_type
590
+ end
586
591
 
587
592
  compatible = types_compatible?(actual_type, backing_type, expression: member.value, scopes: [])
588
593
  compatible ||= actual_type.is_a?(Types::EnumBase) && types_compatible?(actual_type.backing_type, backing_type, expression: member.value, scopes: [])
@@ -281,6 +281,12 @@ 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
+ 'wait' => 'function wait() -> Task[Result[T, EventError]]',
289
+ },
284
290
  'str_buffer' => {
285
291
  'assign' => 'static function assign(value: str) -> void',
286
292
  'append' => 'static function append(value: str) -> void',
@@ -307,7 +313,8 @@ module MilkTea
307
313
  token = context&.fetch(:token, nil)
308
314
  token_kind = token&.type || :none
309
315
  unless token&.type == :identifier
310
- info = builtin_keyword_hover_info(token)
316
+ info = builtin_keyword_hover_info(token) ||
317
+ BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
311
318
  if info
312
319
  result_state = 'hit'
313
320
  return {
@@ -412,6 +419,7 @@ module MilkTea
412
419
  signature = nil
413
420
  docs = nil
414
421
  source_location = nil
422
+ resolved_via_type_member = false
415
423
 
416
424
  if (binding = method_binding_at_token(facts, token))
417
425
  signature = method_signature(binding)
@@ -449,11 +457,26 @@ module MilkTea
449
457
  type = facts.types[name]
450
458
  signature = type_hover_signature(name, type)
451
459
  docs ||= BUILTIN_TYPE_DOCS[name]
460
+ elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
461
+ signature = type_hover_signature(name, nested)
462
+ docs ||= BUILTIN_TYPE_DOCS[name]
452
463
  elsif (binding = facts.values[name])
453
464
  signature = value_hover_signature(binding)
465
+ elsif (member_info = find_member_in_types(facts, name))
466
+ type, member, value = member_info
467
+ signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
468
+ resolved_via_type_member = true
469
+ elsif (arm_sig = find_variant_arm_in_types(facts, name))
470
+ signature = arm_sig
471
+ resolved_via_type_member = true
454
472
  elsif (import_binding = facts.imports[name])
455
473
  signature = "module #{import_binding.name}"
456
474
  source_location = module_definition_location(uri, import_binding.name)
475
+ elsif (attr_binding = facts.attributes[name])
476
+ targets = attr_binding.targets.map(&:to_s).join(", ")
477
+ params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
478
+ signature = "attribute [#{targets}] #{name}(#{params_str})"
479
+ source_location ||= module_definition_location(uri, facts.module_name)
457
480
  else
458
481
  dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
459
482
  dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
@@ -516,7 +539,19 @@ module MilkTea
516
539
  end
517
540
 
518
541
  unless signature
519
- unless token_index && tokens && tokens[previous_non_trivia_token_index(tokens, token_index)]&.type == :dot
542
+ if token_index && tokens && parameter_declaration_token?(tokens, token_index)
543
+ signature = resolve_lexical_local_hover_signature(uri, name, tokens[token_index])
544
+ end
545
+ end
546
+
547
+ unless signature
548
+ if token_index && tokens && attribute_target_token?(tokens, token_index)
549
+ signature = "attribute target #{name}"
550
+ end
551
+ end
552
+
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))
520
555
  local_def = @workspace.find_definition_token_global(
521
556
  name,
522
557
  preferred_uri: uri,
@@ -535,6 +570,8 @@ module MilkTea
535
570
 
536
571
  definition_entry = if source_location
537
572
  measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
573
+ elsif resolved_via_type_member
574
+ nil
538
575
  else
539
576
  measure_perf_stage(stages, 'global_definition') do
540
577
  @workspace.find_definition_token_global(
@@ -1386,6 +1423,43 @@ module MilkTea
1386
1423
  "field #{name}: #{type}"
1387
1424
  end
1388
1425
 
1426
+ def find_nested_type_by_short_name(facts, short_name)
1427
+ matches = facts.types.keys.select { |k| k.to_s.end_with?(".#{short_name}") }
1428
+ return nil unless matches.length == 1
1429
+
1430
+ facts.types[matches.first]
1431
+ end
1432
+
1433
+ def find_member_in_types(facts, name)
1434
+ facts.types.reverse_each do |_key, type|
1435
+ next unless type.respond_to?(:members)
1436
+
1437
+ member = type.members.find { |m| m == name }
1438
+ if member
1439
+ value = type.respond_to?(:member_value) ? type.member_value(name) : nil
1440
+ return [type, member, value]
1441
+ end
1442
+ end
1443
+ nil
1444
+ end
1445
+
1446
+ def find_variant_arm_in_types(facts, name)
1447
+ facts.types.reverse_each do |_key, type|
1448
+ arm = nil
1449
+ if type.respond_to?(:arms)
1450
+ arm = type.arms[name]
1451
+ elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
1452
+ arm = type.arm(name)
1453
+ end
1454
+ next unless arm
1455
+
1456
+ fields = arm.map { |fname, ftype| "#{fname}: #{ftype}" }.join(", ")
1457
+ field_str = fields.empty? ? "" : "(#{fields})"
1458
+ return "#{type.name}.#{name}#{field_str}"
1459
+ end
1460
+ nil
1461
+ end
1462
+
1389
1463
  def builtin_hover_info(name, tokens, token_index)
1390
1464
  specialization_info = builtin_value_specialization_info(name, tokens, token_index)
1391
1465
  return specialization_info if specialization_info
@@ -1399,6 +1473,39 @@ module MilkTea
1399
1473
  builtin_call_hover_info(name, tokens, token_index)
1400
1474
  end
1401
1475
 
1476
+ def parameter_declaration_token?(tokens, index)
1477
+ return false unless index && tokens[index]&.type == :identifier
1478
+
1479
+ prev = previous_non_trivia_token_index(tokens, index)
1480
+ return false unless prev
1481
+ return false unless [:lparen, :comma].include?(tokens[prev].type)
1482
+
1483
+ nxt = next_non_trivia_token_index(tokens, index + 1)
1484
+ nxt && tokens[nxt].type == :colon
1485
+ end
1486
+
1487
+ def attribute_target_token?(tokens, index)
1488
+ return false unless index && tokens[index]&.type == :identifier
1489
+
1490
+ prev = previous_non_trivia_token_index(tokens, index)
1491
+ return false unless prev && [:lbracket, :comma].include?(tokens[prev].type)
1492
+
1493
+ after = next_non_trivia_token_index(tokens, index + 1)
1494
+ return false unless after && [:rbracket, :comma].include?(tokens[after].type)
1495
+
1496
+ true
1497
+ end
1498
+
1499
+ def call_argument_token?(tokens, index)
1500
+ return false unless index && tokens[index]&.type == :identifier
1501
+
1502
+ prev = previous_non_trivia_token_index(tokens, index)
1503
+ return false unless prev && [:lparen, :comma].include?(tokens[prev].type)
1504
+
1505
+ nxt = next_non_trivia_token_index(tokens, index + 1)
1506
+ !nxt || ![:colon, :rbracket, :comma].include?(tokens[nxt].type)
1507
+ end
1508
+
1402
1509
  def builtin_in_member_access_context?(tokens, token_index)
1403
1510
  prev_index = previous_non_trivia_token_index(tokens, token_index)
1404
1511
  prev_index && tokens[prev_index].type == :dot
@@ -1439,7 +1546,7 @@ module MilkTea
1439
1546
  end
1440
1547
 
1441
1548
  def builtin_type_constructor_hover_info(name, tokens, token_index)
1442
- return nil unless %w[array span Option Result SoA str_buffer].include?(name)
1549
+ return nil unless %w[array span Option Result SoA str_buffer ref ptr const_ptr own Task atomic].include?(name)
1443
1550
 
1444
1551
  lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1445
1552
  return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
@@ -1494,6 +1601,18 @@ module MilkTea
1494
1601
  '`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
1495
1602
  when 'str_buffer'
1496
1603
  '`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`.'
1604
+ when 'ref'
1605
+ '`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.'
1606
+ when 'ptr'
1607
+ '`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
1608
+ when 'const_ptr'
1609
+ '`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
1610
+ when 'own'
1611
+ '`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
1612
+ when 'Task'
1613
+ '`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
1614
+ when 'atomic'
1615
+ '`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
1616
  end
1498
1617
 
1499
1618
  {
@@ -1734,6 +1853,14 @@ module MilkTea
1734
1853
  when "let" then kind = :let
1735
1854
  when "var" then kind = :var
1736
1855
  when "const" then kind = :const
1856
+ when "struct" then kind = :struct_type
1857
+ when "function", "async", "external", "foreign" then kind = :function
1858
+ when "enum" then kind = :enum_type
1859
+ when "flags" then kind = :flags_type
1860
+ when "union" then kind = :union_type
1861
+ when "variant" then kind = :variant_type
1862
+ when "(" then kind = :param
1863
+ when "," then kind = :param
1737
1864
  end
1738
1865
  end
1739
1866
 
@@ -1760,9 +1887,15 @@ module MilkTea
1760
1887
  end
1761
1888
 
1762
1889
  kind ||= :let
1890
+ unless %i[let var const param].include?(kind)
1891
+ kind = kind.to_s.sub(/_type$/, "")
1892
+ return "#{kind} #{name}"
1893
+ end
1894
+
1895
+ display_kind = kind == :param ? "parameter" : kind.to_s
1763
1896
  mutability = kind == :var ? "mutable" : "immutable"
1764
1897
  if type_str && !type_str.empty?
1765
- "#{kind} #{name}: #{type_str} (#{mutability})"
1898
+ "#{display_kind} #{name}: #{type_str} (#{mutability})"
1766
1899
  else
1767
1900
  "#{kind} #{name} (#{mutability})"
1768
1901
  end
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.12
4
+ version: 0.2.13
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.12 installed!
586
+ Milk Tea 0.2.13 installed!
587
587
 
588
588
  System requirements:
589
589
  - A C compiler (gcc or clang) must be available on PATH