mt-lang 0.2.11 → 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: 440292bdf9bb8c311ff6172c6b063defbae416862b2f3369b70c4249bcc09f37
4
- data.tar.gz: 4793a630eff4f1672659c682e3fb9df769e6d7aaf20facc3742216b7af8fe388
3
+ metadata.gz: 34c858250b3d56b9c9e2184e4cf3a29d180b176e49d77be5bffd52063a458718
4
+ data.tar.gz: 8ad1e294bd42fc71273ee495ff91b632b788a835c1f4d96203f298d6e2b6db6b
5
5
  SHA512:
6
- metadata.gz: ba82f455b038f4bfcf2b3d2748db4327fec835bf676f854578aca8c21f5614836b693385c70679cbece42917a7a2093a405029f4e6b7a7fa9dcb2c0a1af13257
7
- data.tar.gz: 51f8316e7466ae58c141168a3f350c2104fc61a859d41e1a21316a7d56c11d7ea0ca49113f7c6aa69fe9bf2a06c055ff6d6d94fa0d931096d76ddc1e38610ccd
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.11"
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: [])
@@ -272,6 +272,34 @@ module MilkTea
272
272
  'Subscription' => 'Opaque handle returned by `event.subscribe`. Pass to `event.unsubscribe` to remove a listener.',
273
273
  }.freeze
274
274
 
275
+ BUILTIN_TYPE_METHOD_SIGNATURES = {
276
+ 'atomic' => {
277
+ 'load' => 'function load() -> T',
278
+ 'store' => 'static function store(value: T) -> void',
279
+ 'add' => 'static function add(value: T) -> T',
280
+ 'sub' => 'static function sub(value: T) -> T',
281
+ 'exchange' => 'static function exchange(value: T) -> T',
282
+ 'compare_exchange' => 'static function compare_exchange(expected: T, desired: T) -> bool',
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
+ },
290
+ 'str_buffer' => {
291
+ 'assign' => 'static function assign(value: str) -> void',
292
+ 'append' => 'static function append(value: str) -> void',
293
+ 'assign_format' => 'static function assign_format(fmt: str) -> void',
294
+ 'append_format' => 'static function append_format(fmt: str) -> void',
295
+ 'clear' => 'static function clear() -> void',
296
+ 'len' => 'static function len() -> ptr_uint',
297
+ 'capacity' => 'static function capacity() -> ptr_uint',
298
+ 'as_str' => 'static function as_str() -> str',
299
+ 'as_cstr' => 'static function as_cstr() -> cstr',
300
+ },
301
+ }.freeze
302
+
275
303
  def handle_hover(params)
276
304
  stages = new_perf_stages
277
305
  total_start = stages ? monotonic_time : nil
@@ -285,7 +313,8 @@ module MilkTea
285
313
  token = context&.fetch(:token, nil)
286
314
  token_kind = token&.type || :none
287
315
  unless token&.type == :identifier
288
- info = builtin_keyword_hover_info(token)
316
+ info = builtin_keyword_hover_info(token) ||
317
+ BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
289
318
  if info
290
319
  result_state = 'hit'
291
320
  return {
@@ -390,6 +419,7 @@ module MilkTea
390
419
  signature = nil
391
420
  docs = nil
392
421
  source_location = nil
422
+ resolved_via_type_member = false
393
423
 
394
424
  if (binding = method_binding_at_token(facts, token))
395
425
  signature = method_signature(binding)
@@ -427,11 +457,26 @@ module MilkTea
427
457
  type = facts.types[name]
428
458
  signature = type_hover_signature(name, type)
429
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]
430
463
  elsif (binding = facts.values[name])
431
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
432
472
  elsif (import_binding = facts.imports[name])
433
473
  signature = "module #{import_binding.name}"
434
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)
435
480
  else
436
481
  dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
437
482
  dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
@@ -465,6 +510,27 @@ module MilkTea
465
510
  end
466
511
  end
467
512
 
513
+ unless signature
514
+ if dot_receiver
515
+ receiver_name = dot_receiver
516
+ receiver_binding = resolve_local_hover_binding(facts, receiver_name, lsp_line + 1, lsp_char + 1) ||
517
+ facts.values[receiver_name] ||
518
+ facts.functions[receiver_name]
519
+ if receiver_binding && receiver_binding.type
520
+ receiver_type = receiver_binding.respond_to?(:storage_type) ? receiver_binding.storage_type : receiver_binding.type
521
+ methods = methods_for_receiver_type(facts, receiver_type)
522
+ if (method_binding = methods[name])
523
+ signature = method_signature(method_binding)
524
+ else
525
+ type_base = receiver_type.to_s[/^([a-z_]+)/, 1]
526
+ if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
527
+ signature = method_sigs[name]
528
+ end
529
+ end
530
+ end
531
+ end
532
+ end
533
+
468
534
  unless signature
469
535
  if token_index && (builtin_info = builtin_hover_info(name, tokens, token_index))
470
536
  signature = builtin_info[:signature]
@@ -473,14 +539,28 @@ module MilkTea
473
539
  end
474
540
 
475
541
  unless signature
476
- local_def = @workspace.find_definition_token_global(
477
- name,
478
- preferred_uri: uri,
479
- before_line: lsp_line + 1,
480
- before_char: lsp_char + 1,
481
- )
482
- if local_def
483
- signature = resolve_lexical_local_hover_signature(local_def[:uri], name, local_def[:token])
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))
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
484
564
  end
485
565
  end
486
566
  end
@@ -490,6 +570,8 @@ module MilkTea
490
570
 
491
571
  definition_entry = if source_location
492
572
  measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
573
+ elsif resolved_via_type_member
574
+ nil
493
575
  else
494
576
  measure_perf_stage(stages, 'global_definition') do
495
577
  @workspace.find_definition_token_global(
@@ -1341,6 +1423,43 @@ module MilkTea
1341
1423
  "field #{name}: #{type}"
1342
1424
  end
1343
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
+
1344
1463
  def builtin_hover_info(name, tokens, token_index)
1345
1464
  specialization_info = builtin_value_specialization_info(name, tokens, token_index)
1346
1465
  return specialization_info if specialization_info
@@ -1354,6 +1473,39 @@ module MilkTea
1354
1473
  builtin_call_hover_info(name, tokens, token_index)
1355
1474
  end
1356
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
+
1357
1509
  def builtin_in_member_access_context?(tokens, token_index)
1358
1510
  prev_index = previous_non_trivia_token_index(tokens, token_index)
1359
1511
  prev_index && tokens[prev_index].type == :dot
@@ -1394,7 +1546,7 @@ module MilkTea
1394
1546
  end
1395
1547
 
1396
1548
  def builtin_type_constructor_hover_info(name, tokens, token_index)
1397
- 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)
1398
1550
 
1399
1551
  lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1400
1552
  return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
@@ -1449,6 +1601,18 @@ module MilkTea
1449
1601
  '`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
1450
1602
  when 'str_buffer'
1451
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`.'
1452
1616
  end
1453
1617
 
1454
1618
  {
@@ -1689,6 +1853,14 @@ module MilkTea
1689
1853
  when "let" then kind = :let
1690
1854
  when "var" then kind = :var
1691
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
1692
1864
  end
1693
1865
  end
1694
1866
 
@@ -1715,9 +1887,15 @@ module MilkTea
1715
1887
  end
1716
1888
 
1717
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
1718
1896
  mutability = kind == :var ? "mutable" : "immutable"
1719
1897
  if type_str && !type_str.empty?
1720
- "#{kind} #{name}: #{type_str} (#{mutability})"
1898
+ "#{display_kind} #{name}: #{type_str} (#{mutability})"
1721
1899
  else
1722
1900
  "#{kind} #{name} (#{mutability})"
1723
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.11
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.11 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