mt-lang 0.4.22 → 0.4.24

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: 60f503669467624ebec5461f2f5fb5c3dae9216718b4c445f182323b90e9f505
4
- data.tar.gz: d5ace59e3fdadbe3a7ea75f740d0d1d2953088d1799b42e9e6899c900e50595a
3
+ metadata.gz: 95423784419c8060f10277cb7abbb1fe1cd955fe648008781d1184976968e2d8
4
+ data.tar.gz: 6e1b33f4c2a17226dc34ba00618b89be6f329841c5badc7a53ccd022daa3c54d
5
5
  SHA512:
6
- metadata.gz: e74f76c097577a41ccc21462f7ede0d2c2a77f84f883e0ca3026b6b3f966e4b87ba3cfc91eca5dc16165edbc50a6f2bcff6be7ef6be751a1ba95f86b472b6e00
7
- data.tar.gz: 652e7de9f0afd01aeac1358af1c47a2a19bce244ec53838b5cfc65b103d44cafea61210d01ca766bf390d4b649268d50d6ac2c057ce40e09f64e25b24c4a3d76
6
+ metadata.gz: aec1e36ac602ad755b89252058932df48abd25c0e645e212fa404afd25b23679e86d6cf45a970a36d566b08c9be774231496cf59766f64efa366da382e559963
7
+ data.tar.gz: 85af5d83647fd5cb635bec77a3ae8846be1b6f8f62638b5c82a2f99b9f76f2de6fb08455b6660e0cace75669e9281456a3d7336043ef3009988e50fc3efb4c0c
data/bin/mtc CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
5
 
6
+ RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable) && !RubyVM::YJIT.enabled?
7
+
6
8
  require "milk_tea"
7
9
 
8
10
  exit(MilkTea::CLI.start(ARGV))
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.4.22"
6
+ VERSION = "0.4.24"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -188,6 +188,7 @@ module MilkTea
188
188
  return lower_str_buffer_to_span_expression(lowered, expected_type) if str_buffer_to_span_compatible?(lowered.type, expected_type)
189
189
  return lower_array_to_span_expression(lowered, expected_type) if array_to_span_compatible?(lowered.type, expected_type)
190
190
  return cast_expression(lowered, expected_type) if contextual_numeric_compatibility?(expression, lowered.type, expected_type, env:, external_numeric:, contextual_int_to_float:)
191
+ return wrap_nullable_field_value(expected_type, lowered, env) if expected_type.is_a?(Types::Nullable) && lowered.type == expected_type.base
191
192
 
192
193
  lowered
193
194
  end
@@ -10,11 +10,11 @@ module MilkTea
10
10
  POINTER_SIZE = Fiddle::SIZEOF_VOIDP
11
11
 
12
12
  def self.size_of(type)
13
- size_and_alignment(type, {})&.first
13
+ size_and_alignment(type, nil)&.first
14
14
  end
15
15
 
16
16
  def self.alignment_of(type)
17
- size_and_alignment(type, {})&.last
17
+ size_and_alignment(type, nil)&.last
18
18
  end
19
19
 
20
20
  def self.offset_of(type, field_name)
@@ -38,6 +38,14 @@ module MilkTea
38
38
  end
39
39
  end
40
40
 
41
+ # Computes [size, alignment] for a type.
42
+ #
43
+ # `stack` carries the aggregates on the current root-to-leaf path,
44
+ # pass-down only (never popped). A field whose type reaches any aggregate
45
+ # on that path participates in a storage cycle, and the C backend embeds
46
+ # exactly those fields as pointers (see
47
+ # CBackend#build_cyclic_aggregate_pairs and the cyclic field emission in
48
+ # type_declaration.rb), so layout sizes back-edge fields as raw pointers.
41
49
  def self.size_and_alignment(type, stack)
42
50
  case type
43
51
  when Types::Primitive
@@ -48,24 +56,24 @@ module MilkTea
48
56
  if type.is_a?(Types::Function) || layout_pointer_like_nullable_base?(type.base)
49
57
  [POINTER_SIZE, POINTER_SIZE]
50
58
  else
51
- with_stack(type, stack) do
52
- layout = struct_layout(nullable_opt_layout_fields(type.base), packed: false, alignment: nil, stack:)
59
+ with_stack(type, stack) do |next_stack|
60
+ layout = struct_layout(nullable_opt_layout_fields(type.base), packed: false, alignment: nil, stack: next_stack)
53
61
  [layout[:size], layout[:alignment]]
54
62
  end
55
63
  end
56
64
  when Types::StringView, Types::Span, Types::Task, Types::Struct, Types::StructInstance
57
- with_stack(type, stack) do
58
- layout = struct_layout(ordered_fields(type), packed: packed_layout?(type), alignment: explicit_alignment(type), stack:)
65
+ with_stack(type, stack) do |next_stack|
66
+ layout = struct_layout(ordered_fields(type), packed: packed_layout?(type), alignment: explicit_alignment(type), stack: next_stack)
59
67
  [layout[:size], layout[:alignment]]
60
68
  end
61
69
  when Types::Union
62
- with_stack(type, stack) do
63
- layout = union_layout(ordered_fields(type), packed: packed_layout?(type), alignment: explicit_alignment(type), stack:)
70
+ with_stack(type, stack) do |next_stack|
71
+ layout = union_layout(ordered_fields(type), packed: packed_layout?(type), alignment: explicit_alignment(type), stack: next_stack)
64
72
  [layout[:size], layout[:alignment]]
65
73
  end
66
74
  when Types::Variant, Types::VariantInstance
67
- with_stack(type, stack) do
68
- layout = variant_layout(type, stack:)
75
+ with_stack(type, stack) do |next_stack|
76
+ layout = variant_layout(type, stack: next_stack)
69
77
  [layout[:size], layout[:alignment]]
70
78
  end
71
79
  when Types::GenericInstance
@@ -128,8 +136,8 @@ module MilkTea
128
136
  when "str_buffer"
129
137
  return unless str_buffer_type?(type)
130
138
 
131
- with_stack(type, stack) do
132
- layout = struct_layout(str_buffer_fields(type), packed: false, alignment: nil, stack:)
139
+ with_stack(type, stack) do |next_stack|
140
+ layout = struct_layout(str_buffer_fields(type), packed: false, alignment: nil, stack: next_stack)
133
141
  [layout[:size], layout[:alignment]]
134
142
  end
135
143
  end
@@ -151,7 +159,7 @@ module MilkTea
151
159
 
152
160
  def self.struct_layout(fields, packed:, alignment:, stack:)
153
161
  field_infos = fields.map do |field_name, field_type|
154
- field_layout = size_and_alignment(field_type, stack)
162
+ field_layout = field_size_and_alignment(field_type, stack)
155
163
  return nil unless field_layout
156
164
 
157
165
  [field_name, field_layout.first, field_layout.last]
@@ -162,7 +170,7 @@ module MilkTea
162
170
 
163
171
  def self.union_layout(fields, packed:, alignment:, stack:)
164
172
  field_infos = fields.map do |_field_name, field_type|
165
- field_layout = size_and_alignment(field_type, stack)
173
+ field_layout = field_size_and_alignment(field_type, stack)
166
174
  return nil unless field_layout
167
175
 
168
176
  field_layout
@@ -171,6 +179,30 @@ module MilkTea
171
179
  union_layout_from_layouts(field_infos.map { |size, field_alignment| { size:, alignment: field_alignment } }, packed:, alignment:)
172
180
  end
173
181
 
182
+ # A field whose type reaches any aggregate on the current path is a
183
+ # storage-cycle back edge. The C backend emits such fields as pointers
184
+ # (element pointer for arrays), so they occupy pointer-size storage here.
185
+ def self.field_size_and_alignment(field_type, stack)
186
+ return [POINTER_SIZE, POINTER_SIZE] if cyclic_back_edge?(field_type, stack)
187
+
188
+ size_and_alignment(field_type, stack)
189
+ end
190
+
191
+ def self.cyclic_back_edge?(field_type, stack)
192
+ return false if stack.nil? || stack.empty?
193
+
194
+ aggregate_reaches_in_progress?(field_type, stack, {})
195
+ end
196
+
197
+ def self.aggregate_reaches_in_progress?(type, stack, visited)
198
+ return false if visited.key?(type.object_id)
199
+
200
+ visited[type.object_id] = true
201
+ return true if stack.key?(type)
202
+
203
+ reachability_children(type).any? { |child| aggregate_reaches_in_progress?(child, stack, visited) }
204
+ end
205
+
174
206
  def self.struct_layout_from_infos(field_infos, packed:, alignment:)
175
207
  offsets = {}
176
208
  offset = 0
@@ -253,13 +285,52 @@ module MilkTea
253
285
  remainder.zero? ? value : value + alignment - remainder
254
286
  end
255
287
 
288
+ # `stack` is the set of aggregates on the current path, pass-down only.
289
+ # A nil or empty stack means the caller is not inside an aggregate yet.
290
+ # Yields the extended stack; returns nil when `type` is already in progress
291
+ # (callers treat that as unreachable while mirroring backend semantics).
256
292
  def self.with_stack(type, stack)
257
- return if stack[type]
293
+ next_stack = (stack || {}).dup
294
+ return nil if next_stack.key?(type)
295
+
296
+ next_stack[type] = true
297
+ yield(next_stack)
298
+ end
299
+
300
+ # Structural expansion used for back-edge detection. Mirrors the
301
+ # CBackend's `aggregate_type_dependencies` so pointer-broken cyclic
302
+ # fields agree with the emitted C struct layout.
303
+ def self.reachability_children(type)
304
+ case type
305
+ when Types::Nullable
306
+ [type.base]
307
+ when Types::GenericInstance
308
+ if pointer_type?(type)
309
+ []
310
+ elsif array_type?(type)
311
+ [array_element_type(type)]
312
+ else
313
+ []
314
+ end
315
+ when Types::Span
316
+ [type.element_type]
317
+ when Types::Struct, Types::StructInstance, Types::Union
318
+ type.fields.values
319
+ when Types::Variant, Types::VariantInstance
320
+ type.arm_names.flat_map { |name| type.arm(name).values }
321
+ when Types::VariantArmPayload
322
+ type.fields.values
323
+ else
324
+ []
325
+ end
326
+ end
327
+
328
+ def self.pointer_type?(type)
329
+ type.is_a?(Types::GenericInstance) && %w[ptr const_ptr own ref].include?(type.name)
330
+ end
258
331
 
259
- stack[type] = true
260
- yield
261
- ensure
262
- stack.delete(type)
332
+ def self.array_element_type(type)
333
+ type.arguments.first
263
334
  end
264
335
  end
265
336
  end
data/std/vec.mt CHANGED
@@ -348,6 +348,7 @@ extending Iter[T]:
348
348
  total += 1
349
349
 
350
350
 
351
+ extending Vec[T]:
351
352
  public editable function sort() -> void:
352
353
  if this.len <= 1:
353
354
  return
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.4.22
4
+ version: 0.4.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long (Teefan) Tran
@@ -630,7 +630,7 @@ metadata:
630
630
  homepage_uri: https://teefan.github.io/mt-lang/
631
631
  source_code_uri: https://github.com/teefan/mt-lang
632
632
  post_install_message: |
633
- Milk Tea 0.4.22 installed!
633
+ Milk Tea 0.4.24 installed!
634
634
 
635
635
  System requirements:
636
636
  - A C compiler (gcc or clang) must be available on PATH