mt-lang 0.3.34 → 0.3.37
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/README.md +2 -2
- data/docs/index.html +5 -5
- data/docs/language-design.md +3 -3
- data/docs/language-manual.md +1 -1
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +12 -2
- data/lib/milk_tea/bindings/bindgen.rb +5 -0
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +4 -0
- data/lib/milk_tea/core/c_backend/expressions.rb +25 -3
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +15 -2
- data/lib/milk_tea/core/c_backend/type_collectors.rb +39 -2
- data/lib/milk_tea/core/compile_time.rb +78 -72
- data/lib/milk_tea/core/lowering/block.rb +6 -7
- data/lib/milk_tea/core/lowering/declarations.rb +40 -1
- data/lib/milk_tea/core/lowering/loops.rb +25 -1
- data/lib/milk_tea/core/lowering/resolve.rb +11 -3
- data/lib/milk_tea/core/lowering/utils.rb +6 -2
- data/lib/milk_tea/core/parser/statements.rb +35 -7
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +4 -1
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +12 -2
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +1 -1
- data/lib/milk_tea/tooling/linter/visitors.rb +4 -1
- data/std/box2d.mt +14 -14
- data/std/c/box2d.mt +19 -19
- 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: 84f8e5a5913811a35cd5cd470c43f3827aee62bfe5b151add730d45fe341bee2
|
|
4
|
+
data.tar.gz: fd76e0d6f88abfe0fda004829430effc5b7030957754b6d3d3eebbd6739b96b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc533975db0511ab0f5ac62887ec101ebae699841d3cdbc5079faf1e2a0be877e1ceb71d56b3605ca7c37c60c43019fd3288e690325a21cf87806ca2cff138b5
|
|
7
|
+
data.tar.gz: 89d0efc35e9bfec7c1d9c5a612e2f136d3c6fd8f80259f88a657ac46be896ff79c43c0810f98eba8312139151c343c59205b2a3b5fd72af60d2de2fdfc0fd16a
|
data/README.md
CHANGED
|
@@ -939,7 +939,7 @@ See module source for full method surface. Iterator forms:
|
|
|
939
939
|
|
|
940
940
|
Text categories:
|
|
941
941
|
|
|
942
|
-
- `str` -> string view. The `+` operator concatenates two `str` values
|
|
942
|
+
- `str` -> string view. The `+` operator concatenates two `str` values into a per-thread scratch buffer (no heap allocation), returning a borrowed `str`; the result stays valid while cumulative concatenations on that thread remain within the scratch buffer budget. For loops or repeated concatenation, prefer `string.String` for amortized building.
|
|
943
943
|
- `cstr` -> C ABI string
|
|
944
944
|
- `str_buffer[N]` -> fixed-capacity mutable UTF-8 text buffer
|
|
945
945
|
|
|
@@ -959,7 +959,7 @@ Format strings:
|
|
|
959
959
|
|
|
960
960
|
- `f"count=#{count}"` has type `str`.
|
|
961
961
|
- Allowed interpolations: `str`, `cstr`, `bool`, numeric primitives, integer-backed enums and flags, plus types implementing `format_len() -> ptr_uint` and `append_format(output: ref[std.string.String]) -> void`.
|
|
962
|
-
- `f"..."`
|
|
962
|
+
- Dynamic `f"..."` expressions build into a heap-backed temporary that the compiler releases after use. A dynamic `f"..."` may be returned from a function (or stored in a `str` local): ownership of that buffer transfers to the caller. `std.fmt.format(f"...")` returns an owned `string.String` when you want explicit owned-text lifetime management.
|
|
963
963
|
- Float and double interpolations support `:.N` precision.
|
|
964
964
|
- Integer primitive and integer-backed enum/flags interpolations support `:x` (lowercase hex) and `:X` (uppercase hex).
|
|
965
965
|
- Integer primitive and integer-backed enum/flags interpolations support `:o` / `:O` (octal) and `:b` / `:B` (binary).
|
data/docs/index.html
CHANGED
|
@@ -1262,7 +1262,7 @@ let d: dyn[Drawable] = adapt[Drawable](ref_of(entity))</code></pre>
|
|
|
1262
1262
|
<tr><td><code>ptr_int</code> <code>ptr_uint</code></td><td>Pointer-sized integers</td></tr>
|
|
1263
1263
|
<tr><td><code>float</code> <code>double</code></td><td>Floating-point</td></tr>
|
|
1264
1264
|
<tr><td><code>void</code></td><td>No value</td></tr>
|
|
1265
|
-
<tr><td><code>str</code></td><td>UTF-8 string view (borrowed). The <code>+</code> operator concatenates two <code>str</code> values
|
|
1265
|
+
<tr><td><code>str</code></td><td>UTF-8 string view (borrowed). The <code>+</code> operator concatenates two <code>str</code> values into a per-thread scratch buffer (no allocation); the result is valid while the scratch budget lasts.</td></tr>
|
|
1266
1266
|
<tr><td><code>cstr</code></td><td>NUL-terminated C string</td></tr>
|
|
1267
1267
|
<tr><td><code>vec2</code> <code>vec3</code> <code>vec4</code></td><td>Float vectors with <code>.x .y .z .w</code></td></tr>
|
|
1268
1268
|
<tr><td><code>ivec2</code> <code>ivec3</code> <code>ivec4</code></td><td>Integer vectors</td></tr>
|
|
@@ -1871,7 +1871,7 @@ function field_equal[T](a: const_ptr[T], b: const_ptr[T]) -> bool:
|
|
|
1871
1871
|
<div class="table-wrap">
|
|
1872
1872
|
<table class="attr-table">
|
|
1873
1873
|
<tr><th>Type</th><th>Ownership</th><th>Use Case</th></tr>
|
|
1874
|
-
<tr><td><code>str</code></td><td>Borrowed</td><td>Read-only UTF-8 view (literals, format strings, slicing)</td></tr>
|
|
1874
|
+
<tr><td><code>str</code></td><td>Borrowed</td><td>Read-only UTF-8 view (literals, format strings, slicing); a stored or returned dynamic format string carries its own heap buffer</td></tr>
|
|
1875
1875
|
<tr><td><code>cstr</code></td><td>Borrowed</td><td>NUL-terminated C ABI string (<code>c"hello"</code>)</td></tr>
|
|
1876
1876
|
<tr><td><code>str_buffer[N]</code></td><td>Owned (stack)</td><td>Fixed-capacity mutable UTF-8 builder</td></tr>
|
|
1877
1877
|
<tr><td><code>std.string.String</code></td><td>Owned (heap)</td><td>Growable owned text via <code>fmt.format(f"...")</code></td></tr>
|
|
@@ -1889,9 +1889,9 @@ let info = f"value=#{pi:.4}"
|
|
|
1889
1889
|
## Hex format for ints
|
|
1890
1890
|
let hex = f"address=#{ptr_value:x}"
|
|
1891
1891
|
|
|
1892
|
-
## Owned text
|
|
1892
|
+
## Owned text with explicit release
|
|
1893
1893
|
import std.fmt
|
|
1894
|
-
let owned = fmt.format(f"count=#{count}") ## -> string.String</code></pre>
|
|
1894
|
+
let owned = fmt.format(f"count=#{count}") ## -> string.String (call .release())</code></pre>
|
|
1895
1895
|
</div>
|
|
1896
1896
|
<p>Interpolated expressions must be <code>str</code>, <code>cstr</code>, <code>bool</code>, a numeric primitive, an integer-backed enum or flags type, or a type implementing <code>format_len()</code> and <code>append_format()</code> (custom formatting hooks). The compiler lowers <code>fmt.format(f"...")</code>, <code>str_buffer.append_format(f"...")</code>, and <code>string.String.append_format(f"...")</code> directly to the formatted output without an intermediate allocation.</p>
|
|
1897
1897
|
|
|
@@ -2242,7 +2242,7 @@ function attach(window: ref[Window]) -> Result[void, EventError]:
|
|
|
2242
2242
|
<tr><td><code>std.gzip</code> <code>std.tar</code></td><td>Compression</td></tr>
|
|
2243
2243
|
<tr><td><code>std.sync</code> <code>std.thread</code> <code>std.jobs</code></td><td>Concurrency</td></tr>
|
|
2244
2244
|
<tr><td><code>std.fsm</code> <code>std.goap</code> <code>std.behavior_tree</code></td><td>AI / State machines</td></tr>
|
|
2245
|
-
<tr><td><code>std.
|
|
2245
|
+
<tr><td><code>std.box</code></td><td>Explicit single-value heap storage for shared mutable state</td></tr>
|
|
2246
2246
|
</table>
|
|
2247
2247
|
</div>
|
|
2248
2248
|
</section>
|
data/docs/language-design.md
CHANGED
|
@@ -28,7 +28,7 @@ The output target is beautiful C. The generated C should be readable enough that
|
|
|
28
28
|
- No macro system that rewrites arbitrary ASTs
|
|
29
29
|
- No garbage collector
|
|
30
30
|
- No implicit conversions between unrelated primitive types
|
|
31
|
-
- No user-invisible allocation for
|
|
31
|
+
- No user-invisible allocation for collections, ordinary values, or method calls. Capturing a `proc` may allocate a ref-counted closure environment as part of proc value semantics. Dynamic format strings are the one text case that builds a heap-backed temporary, released after use (see the text-construction rule in §1); other owned text and storage use explicit allocating surfaces.
|
|
32
32
|
|
|
33
33
|
## Design rules
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ If code allocates, takes an address, dereferences a raw pointer, performs an FFI
|
|
|
38
38
|
|
|
39
39
|
FFI visibility belongs at the declaration site. Raw `external` files expose exact ABI types. Imported foreign declarations may project those raw types into ordinary Milk Tea types, but the projection rule, temporary-storage rule, and ownership rule must be declared there instead of repeated at every call site.
|
|
40
40
|
|
|
41
|
-
The same rule applies to text construction. Plain string literals
|
|
41
|
+
The same rule applies to text construction. Plain string literals are borrowed `str` values. A dynamic format string `f"..."` builds into a heap-backed temporary that the compiler releases after the surrounding statement; returning it (or storing it in a `str` local) transfers ownership of that buffer to the caller. The `+` operator on `str` concatenates into a per-thread scratch buffer without allocating — the result is a borrowed `str` valid until that buffer's budget is exhausted. For loops or amortized building, and whenever ownership should stay explicit and controllable, `string.String` and `str_buffer[N]` remain the explicit surfaces with visible cost; `std.fmt.format(f"...")` is the explicit owned-text path returning a `string.String`.
|
|
42
42
|
|
|
43
43
|
### 2. C is the ABI ground truth
|
|
44
44
|
|
|
@@ -762,7 +762,7 @@ Built-in operators should match familiar C behavior where possible:
|
|
|
762
762
|
|
|
763
763
|
No user-defined operator overloading.
|
|
764
764
|
|
|
765
|
-
The `+` operator also concatenates two `str` values
|
|
765
|
+
The `+` operator also concatenates two `str` values into a per-thread scratch buffer, returning a borrowed `str`; `cstr` values are not concatenable. This is the one operator exception to the arithmetic rules, and it is described in the text-construction rule under Design rules §1.
|
|
766
766
|
|
|
767
767
|
Built-in vector, matrix, and quaternion types support component-wise arithmetic with the standard operators:
|
|
768
768
|
|
data/docs/language-manual.md
CHANGED
|
@@ -1072,7 +1072,7 @@ Rules:
|
|
|
1072
1072
|
11. `+`, `-`
|
|
1073
1073
|
12. `*`, `/`, `%`
|
|
1074
1074
|
|
|
1075
|
-
The `+` operator also concatenates two `str` operands, producing a
|
|
1075
|
+
The `+` operator also concatenates two `str` operands into a per-thread scratch buffer, producing a borrowed `str` (no heap allocation) whose validity is bounded by the scratch buffer budget (§2.3). It does not concatenate `cstr` or mixed `str`/`cstr` operands.
|
|
1076
1076
|
|
|
1077
1077
|
### 5.4 Assignment operators
|
|
1078
1078
|
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -22,8 +22,14 @@ module MilkTea
|
|
|
22
22
|
"cstr"
|
|
23
23
|
else
|
|
24
24
|
pointee = pointer_candidate.sub(/\s*\*\z/, "")
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
if function_type_typedef?(pointee)
|
|
26
|
+
# `Name *` where Name is a function-type typedef is a function
|
|
27
|
+
# pointer, which is exactly what the `fn` type already is.
|
|
28
|
+
map_c_type(pointee, context:)
|
|
29
|
+
else
|
|
30
|
+
pointer_name = top_level_const_qualified?(pointee) ? "const_ptr" : "ptr"
|
|
31
|
+
"#{pointer_name}[#{map_c_type(pointee, context:)}]"
|
|
32
|
+
end
|
|
27
33
|
end
|
|
28
34
|
else
|
|
29
35
|
unqualified = strip_qualifiers(normalized)
|
|
@@ -515,6 +521,10 @@ module MilkTea
|
|
|
515
521
|
qual_type.end_with?("*")
|
|
516
522
|
end
|
|
517
523
|
|
|
524
|
+
def function_type_typedef?(qual_type)
|
|
525
|
+
@function_type_typedef_names.include?(strip_qualifiers(qual_type))
|
|
526
|
+
end
|
|
527
|
+
|
|
518
528
|
def c_string_pointer?(qual_type)
|
|
519
529
|
pointee = qual_type.sub(/\s*\*\z/, "")
|
|
520
530
|
unqualified = strip_qualifiers(pointee)
|
|
@@ -147,6 +147,11 @@ module MilkTea
|
|
|
147
147
|
@visible_typedef_names = top_level_nodes.filter_map do |node|
|
|
148
148
|
node["name"] if node["kind"] == "TypedefDecl" && allowed_declaration_name?(node["name"])
|
|
149
149
|
end
|
|
150
|
+
@function_type_typedef_names = top_level_nodes.filter_map do |node|
|
|
151
|
+
if node["kind"] == "TypedefDecl" && allowed_declaration_name?(node["name"]) && extract_function_proto(node) && !function_pointer_type?(type_qual_type(node))
|
|
152
|
+
node["name"]
|
|
153
|
+
end
|
|
154
|
+
end
|
|
150
155
|
build_alias_maps(top_level_nodes)
|
|
151
156
|
|
|
152
157
|
declarations = []
|
|
@@ -139,6 +139,8 @@ module MilkTea
|
|
|
139
139
|
end
|
|
140
140
|
when Types::Task
|
|
141
141
|
[task_type_name(type)]
|
|
142
|
+
when Types::Dyn
|
|
143
|
+
[dyn_type_name(type)]
|
|
142
144
|
when Types::Proc
|
|
143
145
|
[proc_type_name(type)]
|
|
144
146
|
when Types::GenericInstance
|
|
@@ -153,6 +155,8 @@ module MilkTea
|
|
|
153
155
|
end
|
|
154
156
|
when Types::Function
|
|
155
157
|
[]
|
|
158
|
+
when Types::Tuple
|
|
159
|
+
[tuple_type_name(type)]
|
|
156
160
|
when Types::Struct, Types::StructInstance, Types::Union, Types::Variant, Types::VariantInstance, Types::Event, Types::Subscription
|
|
157
161
|
[named_type_c_name(type)]
|
|
158
162
|
when Types::VariantArmPayload
|
|
@@ -347,7 +347,22 @@ module MilkTea
|
|
|
347
347
|
def emit_address_of_operand(expression)
|
|
348
348
|
return emit_expression(expression.operand) if expression.is_a?(IR::Unary) && expression.operator == "*"
|
|
349
349
|
|
|
350
|
-
"&#{wrap_expression(expression)}"
|
|
350
|
+
return "&#{wrap_expression(expression)}" if c_expression_lvalue?(expression)
|
|
351
|
+
|
|
352
|
+
"&(#{c_type(expression.type)}[1]){ #{emit_expression(expression)} }[0]"
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def c_expression_lvalue?(expression)
|
|
356
|
+
case expression
|
|
357
|
+
when IR::Name, IR::CheckedIndex, IR::CheckedSpanIndex, IR::AggregateLiteral, IR::ArrayLiteral, IR::VariantLiteral, IR::ZeroInit
|
|
358
|
+
true
|
|
359
|
+
when IR::Member, IR::Index
|
|
360
|
+
c_expression_lvalue?(expression.receiver)
|
|
361
|
+
when IR::Unary
|
|
362
|
+
expression.operator == "*"
|
|
363
|
+
else
|
|
364
|
+
false
|
|
365
|
+
end
|
|
351
366
|
end
|
|
352
367
|
|
|
353
368
|
def emit_cast_operand(expression)
|
|
@@ -464,7 +479,12 @@ module MilkTea
|
|
|
464
479
|
def emit_addressof_field_initializer(field_type, value)
|
|
465
480
|
c_type_name = named_type_c_name(field_type)
|
|
466
481
|
inner = value.expression
|
|
467
|
-
|
|
482
|
+
source = if c_expression_lvalue?(inner)
|
|
483
|
+
"&(#{emit_expression(inner)})"
|
|
484
|
+
else
|
|
485
|
+
"&(#{c_type(field_type)}[1]){ #{emit_expression(inner)} }[0]"
|
|
486
|
+
end
|
|
487
|
+
"((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), #{source}, sizeof(#{c_type_name})))"
|
|
468
488
|
end
|
|
469
489
|
|
|
470
490
|
def emit_cyclic_array_initializer(field_type, value)
|
|
@@ -479,8 +499,10 @@ module MilkTea
|
|
|
479
499
|
init = emit_initializer(value)
|
|
480
500
|
source_expr = if init.start_with?("{")
|
|
481
501
|
"&(#{c_type(field_type)})#{init}"
|
|
482
|
-
|
|
502
|
+
elsif c_expression_lvalue?(value)
|
|
483
503
|
"&(#{init})"
|
|
504
|
+
else
|
|
505
|
+
"&(#{c_type(field_type)}[1]){ #{init} }[0]"
|
|
484
506
|
end
|
|
485
507
|
"((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
|
|
486
508
|
end
|
|
@@ -104,7 +104,17 @@ module MilkTea
|
|
|
104
104
|
def emit_struct_equality_helpers
|
|
105
105
|
struct_decls_by_linkage = (emitted_aggregate_structs + collect_generic_struct_decls).each_with_object({}) { |decl, map| map[decl.linkage_name] = decl }
|
|
106
106
|
struct_equality_types
|
|
107
|
-
.filter_map
|
|
107
|
+
.filter_map do |type|
|
|
108
|
+
if type.is_a?(Types::VariantArmPayload)
|
|
109
|
+
type
|
|
110
|
+
elsif struct_decls_by_linkage.key?(named_type_c_name(type))
|
|
111
|
+
struct_decls_by_linkage[named_type_c_name(type)]
|
|
112
|
+
elsif type.is_a?(Types::Struct)
|
|
113
|
+
# External structs (raw ABI bindings) are not lowered into
|
|
114
|
+
# @program.structs, but their field layout is still known.
|
|
115
|
+
type
|
|
116
|
+
end
|
|
117
|
+
end
|
|
108
118
|
.flat_map { |decl_or_type| emit_struct_equality_helper(decl_or_type) }
|
|
109
119
|
end
|
|
110
120
|
|
|
@@ -112,11 +122,14 @@ module MilkTea
|
|
|
112
122
|
if struct_decl_or_type.is_a?(IR::StructDecl)
|
|
113
123
|
outer_c = struct_decl_or_type.linkage_name
|
|
114
124
|
fields = struct_decl_or_type.fields
|
|
115
|
-
|
|
125
|
+
elsif struct_decl_or_type.is_a?(Types::VariantArmPayload)
|
|
116
126
|
payload = struct_decl_or_type
|
|
117
127
|
outer_c = named_type_c_name(payload)
|
|
118
128
|
arm_fields = payload.variant_type.arm(payload.arm_name) || {}
|
|
119
129
|
fields = arm_fields.map { |name, field_type| IR::Field.new(name:, type: field_type) }
|
|
130
|
+
else
|
|
131
|
+
outer_c = named_type_c_name(struct_decl_or_type)
|
|
132
|
+
fields = struct_decl_or_type.fields.map { |name, field_type| IR::Field.new(name:, type: field_type) }
|
|
120
133
|
end
|
|
121
134
|
|
|
122
135
|
lines = ["static bool mt_struct_eq_#{outer_c}(struct #{outer_c} left, struct #{outer_c} right) {"]
|
|
@@ -266,6 +266,10 @@ module MilkTea
|
|
|
266
266
|
simd_types = []
|
|
267
267
|
visited = {}
|
|
268
268
|
|
|
269
|
+
all_emitted_top_level_values.each do |value|
|
|
270
|
+
collect_simd_type(value.type, simd_types, visited)
|
|
271
|
+
end
|
|
272
|
+
|
|
269
273
|
emitted_functions.each do |function|
|
|
270
274
|
collect_simd_type(function.return_type, simd_types, visited)
|
|
271
275
|
function.params.each do |param|
|
|
@@ -280,6 +284,16 @@ module MilkTea
|
|
|
280
284
|
end
|
|
281
285
|
end
|
|
282
286
|
|
|
287
|
+
@program.unions.each do |union_decl|
|
|
288
|
+
union_decl.fields.each do |field|
|
|
289
|
+
collect_simd_type(field.type, simd_types, visited)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
each_variant_arm_field_type do |field_type|
|
|
294
|
+
collect_simd_type(field_type, simd_types, visited)
|
|
295
|
+
end
|
|
296
|
+
|
|
283
297
|
simd_types.uniq
|
|
284
298
|
end
|
|
285
299
|
|
|
@@ -299,9 +313,32 @@ module MilkTea
|
|
|
299
313
|
return unless type
|
|
300
314
|
return if visited[type]
|
|
301
315
|
|
|
302
|
-
|
|
316
|
+
visited[type] = true
|
|
317
|
+
|
|
318
|
+
case type
|
|
319
|
+
when Types::Simd
|
|
303
320
|
simd_types << type
|
|
304
|
-
|
|
321
|
+
when Types::Nullable
|
|
322
|
+
collect_simd_type(type.base, simd_types, visited)
|
|
323
|
+
when Types::GenericInstance
|
|
324
|
+
type.arguments.each do |argument|
|
|
325
|
+
collect_simd_type(argument, simd_types, visited) unless argument.is_a?(Types::LiteralTypeArg)
|
|
326
|
+
end
|
|
327
|
+
when Types::Function
|
|
328
|
+
type.params.each do |param|
|
|
329
|
+
collect_simd_type(param.type, simd_types, visited)
|
|
330
|
+
end
|
|
331
|
+
collect_simd_type(type.return_type, simd_types, visited)
|
|
332
|
+
when Types::Struct, Types::Union
|
|
333
|
+
type.fields.each_value do |field_type|
|
|
334
|
+
collect_simd_type(field_type, simd_types, visited)
|
|
335
|
+
end
|
|
336
|
+
when Types::Variant
|
|
337
|
+
type.arm_names.each do |arm_name|
|
|
338
|
+
type.arm(arm_name).each_value do |field_type|
|
|
339
|
+
collect_simd_type(field_type, simd_types, visited)
|
|
340
|
+
end
|
|
341
|
+
end
|
|
305
342
|
end
|
|
306
343
|
end
|
|
307
344
|
|
|
@@ -78,6 +78,10 @@ module MilkTea
|
|
|
78
78
|
nil
|
|
79
79
|
when AST::ExpressionList
|
|
80
80
|
expression.elements.filter_map { |element| evaluate(element) }
|
|
81
|
+
when AST::RangeExpr
|
|
82
|
+
start_val = evaluate(expression.start_expr)
|
|
83
|
+
end_val = evaluate(expression.end_expr)
|
|
84
|
+
start_val.is_a?(Integer) && end_val.is_a?(Integer) ? (start_val...end_val).to_a : nil
|
|
81
85
|
when AST::IntegerLiteral, AST::FloatLiteral, AST::BooleanLiteral
|
|
82
86
|
expression.value
|
|
83
87
|
when AST::StringLiteral
|
|
@@ -184,6 +188,8 @@ module MilkTea
|
|
|
184
188
|
right = evaluate(expression.right)
|
|
185
189
|
|
|
186
190
|
case expression.operator
|
|
191
|
+
when ".."
|
|
192
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? (left...right).to_a : nil
|
|
187
193
|
when "=="
|
|
188
194
|
CompileTime.equality_result(left, right)
|
|
189
195
|
when "!="
|
|
@@ -243,35 +249,41 @@ module MilkTea
|
|
|
243
249
|
result = nil
|
|
244
250
|
|
|
245
251
|
statements.each do |statement|
|
|
246
|
-
|
|
247
|
-
when AST::LocalDecl
|
|
248
|
-
result = evaluate_local_decl(statement, scopes:)
|
|
249
|
-
when AST::ReturnStmt
|
|
250
|
-
value = statement.value ? evaluate_expression(statement.value, scopes:) : nil
|
|
251
|
-
raise ReturnValue.new(value)
|
|
252
|
-
when AST::WhileStmt
|
|
253
|
-
result = evaluate_while(statement, scopes:)
|
|
254
|
-
when AST::ForStmt
|
|
255
|
-
result = evaluate_for(statement, scopes:)
|
|
256
|
-
when AST::Assignment
|
|
257
|
-
result = evaluate_assignment(statement, scopes:)
|
|
258
|
-
when AST::IfStmt
|
|
259
|
-
result = evaluate_if(statement, scopes:)
|
|
260
|
-
when AST::ExpressionStmt
|
|
261
|
-
evaluate_expression(statement.expression, scopes:)
|
|
262
|
-
when AST::PassStmt, AST::BreakStmt, AST::ContinueStmt
|
|
263
|
-
# no-op at compile time
|
|
264
|
-
when AST::EmitStmt
|
|
265
|
-
# evaluated during lowering
|
|
266
|
-
result = nil
|
|
267
|
-
else
|
|
268
|
-
result = nil
|
|
269
|
-
end
|
|
252
|
+
result = evaluate_statement(statement, scopes:)
|
|
270
253
|
end
|
|
271
254
|
|
|
272
255
|
result
|
|
273
256
|
end
|
|
274
257
|
|
|
258
|
+
def evaluate_statement(statement, scopes:)
|
|
259
|
+
case statement
|
|
260
|
+
when AST::LocalDecl
|
|
261
|
+
evaluate_local_decl(statement, scopes:)
|
|
262
|
+
when AST::ReturnStmt
|
|
263
|
+
value = statement.value ? evaluate_expression(statement.value, scopes:) : nil
|
|
264
|
+
raise ReturnValue.new(value)
|
|
265
|
+
when AST::WhileStmt
|
|
266
|
+
evaluate_while(statement, scopes:)
|
|
267
|
+
when AST::ForStmt
|
|
268
|
+
evaluate_for(statement, scopes:)
|
|
269
|
+
when AST::MatchStmt
|
|
270
|
+
evaluate_match(statement, scopes:)
|
|
271
|
+
when AST::Assignment
|
|
272
|
+
evaluate_assignment(statement, scopes:)
|
|
273
|
+
when AST::IfStmt
|
|
274
|
+
evaluate_if(statement, scopes:)
|
|
275
|
+
when AST::ExpressionStmt
|
|
276
|
+
evaluate_expression(statement.expression, scopes:)
|
|
277
|
+
when AST::PassStmt, AST::BreakStmt, AST::ContinueStmt
|
|
278
|
+
# no-op at compile time
|
|
279
|
+
when AST::EmitStmt
|
|
280
|
+
# emitted declarations are collected during lowering
|
|
281
|
+
nil
|
|
282
|
+
else
|
|
283
|
+
nil
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
275
287
|
def evaluate_expression(expression, scopes:)
|
|
276
288
|
case expression
|
|
277
289
|
when AST::Identifier
|
|
@@ -304,11 +316,34 @@ module MilkTea
|
|
|
304
316
|
value = evaluate_expression(assignment.value, scopes:)
|
|
305
317
|
case assignment.target
|
|
306
318
|
when AST::Identifier
|
|
319
|
+
if assignment.operator != "="
|
|
320
|
+
current = @variables[assignment.target.name]
|
|
321
|
+
value = apply_compile_time_binary(assignment.operator.chomp("="), current, value)
|
|
322
|
+
end
|
|
307
323
|
@variables[assignment.target.name] = value
|
|
308
324
|
end
|
|
309
325
|
value
|
|
310
326
|
end
|
|
311
327
|
|
|
328
|
+
def apply_compile_time_binary(operator, left, right)
|
|
329
|
+
case operator
|
|
330
|
+
when "+" then left.is_a?(Numeric) && right.is_a?(Numeric) ? left + right : nil
|
|
331
|
+
when "-" then left.is_a?(Numeric) && right.is_a?(Numeric) ? left - right : nil
|
|
332
|
+
when "*" then left.is_a?(Numeric) && right.is_a?(Numeric) ? left * right : nil
|
|
333
|
+
when "/" then left.is_a?(Numeric) && right.is_a?(Numeric) && !zero_numeric?(right) ? left / right : nil
|
|
334
|
+
when "%" then left.is_a?(Integer) && right.is_a?(Integer) && !right.zero? ? left % right : nil
|
|
335
|
+
when "&" then left.is_a?(Integer) && right.is_a?(Integer) ? left & right : nil
|
|
336
|
+
when "|" then left.is_a?(Integer) && right.is_a?(Integer) ? left | right : nil
|
|
337
|
+
when "^" then left.is_a?(Integer) && right.is_a?(Integer) ? left ^ right : nil
|
|
338
|
+
when "<<" then left.is_a?(Integer) && right.is_a?(Integer) ? left << right : nil
|
|
339
|
+
when ">>" then left.is_a?(Integer) && right.is_a?(Integer) ? left >> right : nil
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def zero_numeric?(value)
|
|
344
|
+
(value.is_a?(Integer) && value.zero?) || (value.is_a?(Float) && value.zero?)
|
|
345
|
+
end
|
|
346
|
+
|
|
312
347
|
def evaluate_while(statement, scopes:)
|
|
313
348
|
result = nil
|
|
314
349
|
iterations = 0
|
|
@@ -319,17 +354,7 @@ module MilkTea
|
|
|
319
354
|
break unless condition
|
|
320
355
|
break unless CompileTime.boolean_value?(condition)
|
|
321
356
|
|
|
322
|
-
statement.body.each
|
|
323
|
-
case body_stmt
|
|
324
|
-
when AST::ReturnStmt
|
|
325
|
-
value = body_stmt.value ? evaluate_expression(body_stmt.value, scopes:) : nil
|
|
326
|
-
raise ReturnValue.new(value)
|
|
327
|
-
when AST::Assignment
|
|
328
|
-
evaluate_assignment(body_stmt, scopes:)
|
|
329
|
-
when AST::ExpressionStmt
|
|
330
|
-
evaluate_expression(body_stmt.expression, scopes:)
|
|
331
|
-
end
|
|
332
|
-
end
|
|
357
|
+
statement.body.each { |body_stmt| evaluate_statement(body_stmt, scopes:) }
|
|
333
358
|
iterations += 1
|
|
334
359
|
end
|
|
335
360
|
|
|
@@ -347,21 +372,7 @@ module MilkTea
|
|
|
347
372
|
|
|
348
373
|
iterable.each do |element|
|
|
349
374
|
@variables[loop_var_name] = element
|
|
350
|
-
statement.body.each
|
|
351
|
-
case body_stmt
|
|
352
|
-
when AST::ReturnStmt
|
|
353
|
-
value = body_stmt.value ? evaluate_expression(body_stmt.value, scopes:) : nil
|
|
354
|
-
raise ReturnValue.new(value)
|
|
355
|
-
when AST::Assignment
|
|
356
|
-
evaluate_assignment(body_stmt, scopes:)
|
|
357
|
-
when AST::ExpressionStmt
|
|
358
|
-
evaluate_expression(body_stmt.expression, scopes:)
|
|
359
|
-
when AST::IfStmt
|
|
360
|
-
result = evaluate_if(body_stmt, scopes:)
|
|
361
|
-
when AST::WhileStmt
|
|
362
|
-
result = evaluate_while(body_stmt, scopes:)
|
|
363
|
-
end
|
|
364
|
-
end
|
|
375
|
+
statement.body.each { |body_stmt| evaluate_statement(body_stmt, scopes:) }
|
|
365
376
|
end
|
|
366
377
|
|
|
367
378
|
result
|
|
@@ -371,32 +382,27 @@ module MilkTea
|
|
|
371
382
|
statement.branches.each do |branch|
|
|
372
383
|
condition = evaluate_expression(branch.condition, scopes:)
|
|
373
384
|
if CompileTime.boolean_value?(condition) && condition
|
|
374
|
-
branch.body.each
|
|
375
|
-
case body_stmt
|
|
376
|
-
when AST::ReturnStmt
|
|
377
|
-
value = body_stmt.value ? evaluate_expression(body_stmt.value, scopes:) : nil
|
|
378
|
-
raise ReturnValue.new(value)
|
|
379
|
-
when AST::Assignment
|
|
380
|
-
evaluate_assignment(body_stmt, scopes:)
|
|
381
|
-
when AST::ExpressionStmt
|
|
382
|
-
evaluate_expression(body_stmt.expression, scopes:)
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
+
branch.body.each { |body_stmt| evaluate_statement(body_stmt, scopes:) }
|
|
385
386
|
return condition
|
|
386
387
|
end
|
|
387
388
|
end
|
|
388
389
|
|
|
389
390
|
if statement.else_body
|
|
390
|
-
statement.else_body.each
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
391
|
+
statement.else_body.each { |body_stmt| evaluate_statement(body_stmt, scopes:) }
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
nil
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def evaluate_match(statement, scopes:)
|
|
398
|
+
scrutinee = evaluate_expression(statement.expression, scopes:)
|
|
399
|
+
return nil unless scrutinee
|
|
400
|
+
|
|
401
|
+
statement.arms.each do |arm|
|
|
402
|
+
wildcard = arm.pattern.is_a?(AST::Identifier) && arm.pattern.name == "_"
|
|
403
|
+
if wildcard || CompileTime.equality_result(scrutinee, evaluate_expression(arm.pattern, scopes:)) == true
|
|
404
|
+
arm.body.each { |body_stmt| evaluate_statement(body_stmt, scopes:) }
|
|
405
|
+
return scrutinee
|
|
400
406
|
end
|
|
401
407
|
end
|
|
402
408
|
|
|
@@ -506,7 +512,7 @@ module MilkTea
|
|
|
506
512
|
end
|
|
507
513
|
|
|
508
514
|
def self.core_member_handles(type)
|
|
509
|
-
type.members.map { |name
|
|
515
|
+
type.members.map { |name| Types::MemberHandle.new(nil, name, type.member_value(name)) }
|
|
510
516
|
end
|
|
511
517
|
|
|
512
518
|
def self.core_evaluate_type_returning(
|
|
@@ -186,6 +186,7 @@ module MilkTea
|
|
|
186
186
|
mutable: false,
|
|
187
187
|
pointer: false,
|
|
188
188
|
const_value: element,
|
|
189
|
+
substitute_const_value: true,
|
|
189
190
|
)
|
|
190
191
|
emit_stmts, other_stmts = statement.body.partition { |s| s.is_a?(AST::EmitStmt) }
|
|
191
192
|
emit_stmts.each do |emit_stmt|
|
|
@@ -486,13 +487,11 @@ module MilkTea
|
|
|
486
487
|
expected_type: return_type,
|
|
487
488
|
contextual_int_to_float: contextual_int_to_float_target?(return_type),
|
|
488
489
|
) : nil
|
|
489
|
-
if prepared_cleanups.any? && cstr_trackable_type?(return_type)
|
|
490
|
-
raise LoweringError.new("formatted string temporaries cannot be returned as borrowed text; use std.fmt.format(f\"...\") when ownership must escape",
|
|
491
|
-
line: statement.line, column: statement.column, path: @ctx.current_analysis_path)
|
|
492
|
-
end
|
|
493
|
-
|
|
494
490
|
prepared_cleanup_list = prepared_cleanups.flat_map(&:itself)
|
|
495
|
-
if prepared_cleanup_list.any? &&
|
|
491
|
+
if prepared_cleanup_list.any? && (cstr_trackable_type?(return_type) ||
|
|
492
|
+
(return_type.is_a?(Types::Struct) && struct_contains_string_field?(return_type)))
|
|
493
|
+
# A dynamic f-string temp owns its heap buffer; returning it transfers
|
|
494
|
+
# ownership to the caller, so the format release must not run.
|
|
496
495
|
prepared_cleanup_list = prepared_cleanup_list.reject { |stmt| stmt.is_a?(IR::ExpressionStmt) && stmt.expression.is_a?(IR::Call) && stmt.expression.callee == "mt_format_str_release" }
|
|
497
496
|
end
|
|
498
497
|
cleanup = prepared_cleanup_list + cleanup_statements(local_defers, active_defers)
|
|
@@ -793,7 +792,7 @@ module MilkTea
|
|
|
793
792
|
else_body: nil,
|
|
794
793
|
)
|
|
795
794
|
end
|
|
796
|
-
local_defers.concat(prepared_cleanups)
|
|
795
|
+
local_defers.concat(reject_format_releases_for_assignment(prepared_cleanups, storage_type))
|
|
797
796
|
if contains_proc_storage_type?(storage_type)
|
|
798
797
|
local_value = IR::Name.new(name: linkage_name, type: storage_type, pointer: false)
|
|
799
798
|
local_defers << lower_proc_nullable_release_statements(local_value, storage_type)
|
|
@@ -23,6 +23,7 @@ module MilkTea
|
|
|
23
23
|
expanded_declarations.grep(AST::ConstDecl).filter_map do |decl|
|
|
24
24
|
type = @ctx.values.fetch(decl.name).type
|
|
25
25
|
const_value = @ctx.values.fetch(decl.name).const_value
|
|
26
|
+
ensure_registered_storage_type_types(type)
|
|
26
27
|
|
|
27
28
|
next if type == Types::BUILTIN_TYPE_META_TYPE
|
|
28
29
|
|
|
@@ -35,7 +36,7 @@ module MilkTea
|
|
|
35
36
|
value = lower_const_value_literal(type, const_value)
|
|
36
37
|
end
|
|
37
38
|
elsif decl.block_body || decl.value.is_a?(AST::ExpressionList)
|
|
38
|
-
raise LoweringError.new("constant #{decl.name} has no compile-time value", line: decl.line, column: decl.column)
|
|
39
|
+
raise LoweringError.new("constant #{decl.name} has no compile-time value", line: decl.line, column: decl.column, path: @ctx.current_analysis_path)
|
|
39
40
|
else
|
|
40
41
|
value = lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
|
|
41
42
|
if (decl.value.is_a?(AST::Call) || decl.value.is_a?(AST::Specialization)) && static_initializer_ir_has_call?(value)
|
|
@@ -78,6 +79,43 @@ module MilkTea
|
|
|
78
79
|
end
|
|
79
80
|
end
|
|
80
81
|
|
|
82
|
+
## Register C struct typedefs for every tuple type reachable from a
|
|
83
|
+
## module-storage type (consts and globals). `ensure_tuple_struct` is
|
|
84
|
+
## normally called while lowering tuple *expressions*, so a tuple that
|
|
85
|
+
## only appears in static storage never gets its `mt_tuple_...` typedef
|
|
86
|
+
## emitted; the C compiler then fails with "unknown type name".
|
|
87
|
+
def ensure_registered_storage_type_types(type, seen = {})
|
|
88
|
+
return if type.nil? || seen[type]
|
|
89
|
+
|
|
90
|
+
seen[type] = true
|
|
91
|
+
if type.is_a?(Types::Tuple)
|
|
92
|
+
ensure_tuple_struct(type)
|
|
93
|
+
type.element_types.each { |element_type| ensure_registered_storage_type_types(element_type, seen) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
case type
|
|
97
|
+
when Types::Nullable
|
|
98
|
+
ensure_registered_storage_type_types(type.base, seen)
|
|
99
|
+
when Types::Span
|
|
100
|
+
ensure_registered_storage_type_types(type.element_type, seen)
|
|
101
|
+
when Types::Task
|
|
102
|
+
ensure_registered_storage_type_types(type.result_type, seen)
|
|
103
|
+
when Types::GenericInstance, Types::StructInstance, Types::VariantInstance
|
|
104
|
+
type.arguments.each do |argument|
|
|
105
|
+
ensure_registered_storage_type_types(argument, seen) unless argument.is_a?(Types::LiteralTypeArg)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if type.respond_to?(:fields) && type.fields
|
|
110
|
+
type.fields.each_value { |field_type| ensure_registered_storage_type_types(field_type, seen) }
|
|
111
|
+
end
|
|
112
|
+
if type.respond_to?(:arms)
|
|
113
|
+
type.arms.each_value do |arm_fields|
|
|
114
|
+
arm_fields.each_value { |field_type| ensure_registered_storage_type_types(field_type, seen) }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
81
119
|
def lower_const_value_literal(type, const_value)
|
|
82
120
|
case const_value
|
|
83
121
|
when Integer
|
|
@@ -130,6 +168,7 @@ module MilkTea
|
|
|
130
168
|
next unless decl.is_a?(AST::VarDecl) || decl.is_a?(AST::EventDecl)
|
|
131
169
|
|
|
132
170
|
type = @ctx.values.fetch(decl.name).type
|
|
171
|
+
ensure_registered_storage_type_types(type)
|
|
133
172
|
ensure_event_runtime(type) if type.is_a?(Types::Event)
|
|
134
173
|
value = if decl.is_a?(AST::VarDecl) && decl.value
|
|
135
174
|
lower_static_storage_initializer(decl.value, env: empty_env, expected_type: type)
|
|
@@ -643,6 +643,8 @@ module MilkTea
|
|
|
643
643
|
end
|
|
644
644
|
end
|
|
645
645
|
|
|
646
|
+
written_scalar_captures = captures.select { |c| written_names.include?(c.name) && !array_capture_names.include?(c.name) }
|
|
647
|
+
|
|
646
648
|
@artifacts.synthetic_structs << IR::StructDecl.new(
|
|
647
649
|
name: cap_struct_c_name, linkage_name: cap_struct_c_name,
|
|
648
650
|
fields: cap_fields, packed: false, alignment: nil,
|
|
@@ -674,6 +676,14 @@ module MilkTea
|
|
|
674
676
|
|
|
675
677
|
rewritten_body = array_capture_names.empty? ? block_body : rewrite_pfor_array_captures(block_body, array_capture_names)
|
|
676
678
|
worker_body.concat(rewritten_body)
|
|
679
|
+
|
|
680
|
+
written_scalar_captures.each do |c|
|
|
681
|
+
worker_body << IR::Assignment.new(
|
|
682
|
+
target: IR::Member.new(receiver: cap_name_ir, member: c.name, type: c.type),
|
|
683
|
+
operator: "=",
|
|
684
|
+
value: IR::Name.new(name: c.name, type: c.type, pointer: false),
|
|
685
|
+
)
|
|
686
|
+
end
|
|
677
687
|
end
|
|
678
688
|
|
|
679
689
|
@artifacts.synthetic_functions << IR::Function.new(
|
|
@@ -715,7 +725,7 @@ module MilkTea
|
|
|
715
725
|
)
|
|
716
726
|
end
|
|
717
727
|
|
|
718
|
-
{ worker_c_name:, cap_local_name:, cap_struct_type:, cap_init:, capture_names: Set.new(captures.map(&:name)), written_names:, captureless: }
|
|
728
|
+
{ worker_c_name:, cap_local_name:, cap_struct_type:, cap_init:, capture_names: Set.new(captures.map(&:name)), written_names:, written_scalar_captures: captureless ? [] : written_scalar_captures, captureless: }
|
|
719
729
|
end
|
|
720
730
|
|
|
721
731
|
validate_pfor_write_conflicts!(block_infos)
|
|
@@ -768,6 +778,20 @@ module MilkTea
|
|
|
768
778
|
type: void_type,
|
|
769
779
|
))
|
|
770
780
|
|
|
781
|
+
block_infos.each do |info|
|
|
782
|
+
info[:written_scalar_captures].each do |c|
|
|
783
|
+
call_site << IR::Assignment.new(
|
|
784
|
+
target: IR::Name.new(name: c.name, type: c.type, pointer: false),
|
|
785
|
+
operator: "=",
|
|
786
|
+
value: IR::Member.new(
|
|
787
|
+
receiver: IR::Name.new(name: info[:cap_local_name], type: info[:cap_struct_type], pointer: false),
|
|
788
|
+
member: c.name,
|
|
789
|
+
type: c.type,
|
|
790
|
+
),
|
|
791
|
+
)
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
|
|
771
795
|
IR::BlockStmt.new(body: call_site)
|
|
772
796
|
end
|
|
773
797
|
|
|
@@ -745,7 +745,7 @@ module MilkTea
|
|
|
745
745
|
end
|
|
746
746
|
return function_type_for_name(expression.name) if @ctx.functions.key?(expression.name)
|
|
747
747
|
|
|
748
|
-
raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column)
|
|
748
|
+
raise LoweringError.new("unknown identifier #{expression.name}", line: expression.line, column: expression.column, path: @ctx.current_analysis_path)
|
|
749
749
|
when AST::MemberAccess
|
|
750
750
|
if (type_expr = resolve_type_expression(expression.receiver))
|
|
751
751
|
member_type = resolve_type_member(type_expr, expression.member)
|
|
@@ -784,7 +784,7 @@ module MilkTea
|
|
|
784
784
|
end
|
|
785
785
|
|
|
786
786
|
return receiver_type.field(expression.member) if receiver_type.respond_to?(:field)
|
|
787
|
-
raise LoweringError.new("unknown member #{expression.member}", line: expression.line, column: expression.column)
|
|
787
|
+
raise LoweringError.new("unknown member #{expression.member}", line: expression.line, column: expression.column, path: @ctx.current_analysis_path)
|
|
788
788
|
when AST::IndexAccess
|
|
789
789
|
receiver_type = infer_expression_type(expression.receiver, env:)
|
|
790
790
|
index_type = infer_expression_type(expression.index, env:)
|
|
@@ -1677,7 +1677,15 @@ module MilkTea
|
|
|
1677
1677
|
evaluate_attribute_arg_call(expression.arguments, env:)
|
|
1678
1678
|
else
|
|
1679
1679
|
callee_name = expression.callee.callee.is_a?(AST::Identifier) ? expression.callee.callee.name : nil
|
|
1680
|
-
if callee_name
|
|
1680
|
+
if callee_name == "array"
|
|
1681
|
+
values = []
|
|
1682
|
+
expression.arguments.each do |argument|
|
|
1683
|
+
val = compile_time_const_value(argument.value, env:)
|
|
1684
|
+
return nil unless val
|
|
1685
|
+
values << val
|
|
1686
|
+
end
|
|
1687
|
+
values
|
|
1688
|
+
elsif callee_name
|
|
1681
1689
|
func = @ctx.functions[callee_name]
|
|
1682
1690
|
if func&.ast&.respond_to?(:const) && func.ast.const
|
|
1683
1691
|
evaluate_const_function_body_lower(func, expression.arguments)
|
|
@@ -459,8 +459,8 @@ module MilkTea
|
|
|
459
459
|
end
|
|
460
460
|
end
|
|
461
461
|
|
|
462
|
-
def local_binding(type:, linkage_name:, mutable:, pointer:, storage_type: nil, projection: nil, cstr_backed: false, cstr_list_backed: false, const_value: nil)
|
|
463
|
-
{ type:, storage_type: storage_type || type, linkage_name:, mutable:, pointer:, projection:, cstr_backed:, cstr_list_backed:, const_value: }
|
|
462
|
+
def local_binding(type:, linkage_name:, mutable:, pointer:, storage_type: nil, projection: nil, cstr_backed: false, cstr_list_backed: false, const_value: nil, substitute_const_value: false)
|
|
463
|
+
{ type:, storage_type: storage_type || type, linkage_name:, mutable:, pointer:, projection:, cstr_backed:, cstr_list_backed:, const_value:, substitute_const_value: }
|
|
464
464
|
end
|
|
465
465
|
|
|
466
466
|
def callable_type?(type)
|
|
@@ -904,6 +904,10 @@ module MilkTea
|
|
|
904
904
|
visible_type = binding[:type]
|
|
905
905
|
projection = binding[:projection]
|
|
906
906
|
|
|
907
|
+
if binding[:substitute_const_value] && !binding[:const_value].nil?
|
|
908
|
+
return lower_const_value_literal(visible_type, binding[:const_value])
|
|
909
|
+
end
|
|
910
|
+
|
|
907
911
|
if projection == :result_success_value
|
|
908
912
|
local_ref = IR::Name.new(name: binding[:linkage_name], type: storage_type, pointer: binding[:pointer])
|
|
909
913
|
return variant_binding_projection_expression(local_ref, storage_type, "success", "value", visible_type)
|
|
@@ -297,7 +297,7 @@ module MilkTea
|
|
|
297
297
|
expression = nil
|
|
298
298
|
arms = []
|
|
299
299
|
expression = parse_expression
|
|
300
|
-
arms = parse_match_arms(arms)
|
|
300
|
+
arms = normalize_mixed_match_arms(parse_match_arms(arms))
|
|
301
301
|
if arms.first&.is_a?(AST::MatchExprArm)
|
|
302
302
|
expr = AST::MatchExpr.new(expression:, arms:, line:, column: token.column, length: token.lexeme.length)
|
|
303
303
|
AST::ExpressionStmt.new(expression: expr, line:)
|
|
@@ -311,12 +311,13 @@ module MilkTea
|
|
|
311
311
|
recovered_arms = synchronize_to_match_arm_boundary
|
|
312
312
|
target_line = line
|
|
313
313
|
if recovered_arms
|
|
314
|
+
combined_arms = normalize_mixed_match_arms(arms + recovered_arms)
|
|
314
315
|
stmt =
|
|
315
|
-
if
|
|
316
|
-
expr = AST::MatchExpr.new(expression: expression || recovery_error_expr(e), arms:
|
|
316
|
+
if combined_arms.first&.is_a?(AST::MatchExprArm)
|
|
317
|
+
expr = AST::MatchExpr.new(expression: expression || recovery_error_expr(e), arms: combined_arms, line: target_line, column: token.column, length: token.lexeme.length)
|
|
317
318
|
AST::ExpressionStmt.new(expression: expr, line: target_line)
|
|
318
319
|
else
|
|
319
|
-
AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms:
|
|
320
|
+
AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms: combined_arms, line: target_line, column: token.column, length: token.lexeme.length)
|
|
320
321
|
end
|
|
321
322
|
return stmt
|
|
322
323
|
end
|
|
@@ -335,6 +336,33 @@ module MilkTea
|
|
|
335
336
|
arms
|
|
336
337
|
end
|
|
337
338
|
|
|
339
|
+
## A statement match may mix inline value arms (`pattern: expr`) with
|
|
340
|
+
## block arms. The inline form is a single expression statement, so when
|
|
341
|
+
## any arm is a block the inline arms are rewritten to block arms with a
|
|
342
|
+
## single expression-statement body. This keeps MatchStmt arms
|
|
343
|
+
## homogeneous (all MatchArm) and MatchExpr arms homogeneous (all
|
|
344
|
+
## MatchExprArm); the sema / control-flow / lowering consumers rely on
|
|
345
|
+
## that invariant.
|
|
346
|
+
def normalize_mixed_match_arms(arms)
|
|
347
|
+
return arms unless arms.any? { |arm| arm.is_a?(AST::MatchExprArm) } && arms.any? { |arm| arm.is_a?(AST::MatchArm) }
|
|
348
|
+
|
|
349
|
+
arms.map do |arm|
|
|
350
|
+
if arm.is_a?(AST::MatchExprArm)
|
|
351
|
+
AST::MatchArm.new(
|
|
352
|
+
pattern: arm.pattern,
|
|
353
|
+
binding_name: arm.binding_name,
|
|
354
|
+
binding_line: arm.binding_line,
|
|
355
|
+
binding_column: arm.binding_column,
|
|
356
|
+
body: [AST::ExpressionStmt.new(expression: arm.value, line: arm.line)],
|
|
357
|
+
line: arm.line,
|
|
358
|
+
column: arm.column,
|
|
359
|
+
)
|
|
360
|
+
else
|
|
361
|
+
arm
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
338
366
|
def parse_match_arm_body(arms = [])
|
|
339
367
|
skip_newlines
|
|
340
368
|
until check(:dedent) || eof?
|
|
@@ -652,7 +680,7 @@ module MilkTea
|
|
|
652
680
|
token = previous
|
|
653
681
|
line = token.line
|
|
654
682
|
discriminant = parse_expression
|
|
655
|
-
branches = parse_match_arms([])
|
|
683
|
+
branches = normalize_mixed_match_arms(parse_match_arms([]))
|
|
656
684
|
else_body = if check(:else)
|
|
657
685
|
if check_next(:newline) || check_next(:indent)
|
|
658
686
|
parse_else_branch_body
|
|
@@ -734,14 +762,14 @@ module MilkTea
|
|
|
734
762
|
line = token.line
|
|
735
763
|
arms = []
|
|
736
764
|
expression = parse_expression
|
|
737
|
-
arms = parse_match_arms(arms)
|
|
765
|
+
arms = normalize_mixed_match_arms(parse_match_arms(arms))
|
|
738
766
|
AST::MatchStmt.new(expression:, arms:, inline: true, line:, column: token.column, length: token.lexeme.length)
|
|
739
767
|
rescue ParseError => e
|
|
740
768
|
raise unless @recovery_errors
|
|
741
769
|
|
|
742
770
|
@recovery_errors << e
|
|
743
771
|
recovered_arms = synchronize_to_match_arm_boundary
|
|
744
|
-
return AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms: arms + recovered_arms, inline: true, line:, column: token.column, length: token.lexeme.length) if recovered_arms
|
|
772
|
+
return AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms: normalize_mixed_match_arms(arms + recovered_arms), inline: true, line:, column: token.column, length: token.lexeme.length) if recovered_arms
|
|
745
773
|
|
|
746
774
|
recovery_error_stmt(e)
|
|
747
775
|
end
|
|
@@ -211,7 +211,8 @@ module MilkTea
|
|
|
211
211
|
when IR::NullableSpanIndex
|
|
212
212
|
"nullable_span_index<#{expression.receiver_type}>(#{render_expression(expression.receiver)}, #{render_expression(expression.index)})"
|
|
213
213
|
when IR::Call
|
|
214
|
-
|
|
214
|
+
callee_text = expression.callee.is_a?(String) ? expression.callee : render_expression(expression.callee)
|
|
215
|
+
wrap("#{callee_text}(#{expression.arguments.map { |argument| render_expression(argument) }.join(', ')})", parent_precedence, POSTFIX_PRECEDENCE)
|
|
215
216
|
when IR::Unary
|
|
216
217
|
operand = render_expression(expression.operand, UNARY_PRECEDENCE)
|
|
217
218
|
text = expression.operator == "not" ? "not #{operand}" : "#{expression.operator}#{operand}"
|
|
@@ -258,6 +259,8 @@ module MilkTea
|
|
|
258
259
|
end
|
|
259
260
|
when IR::ArrayLiteral
|
|
260
261
|
"#{expression.type}(#{expression.elements.map { |element| render_expression(element) }.join(', ')})"
|
|
262
|
+
when IR::SimdLaneWith
|
|
263
|
+
"#{render_expression(expression.src)}.with(#{render_expression(expression.index)}, #{render_expression(expression.value)})"
|
|
261
264
|
when IR::Assignment
|
|
262
265
|
"#{render_expression(expression.target)} #{expression.operator} #{render_expression(expression.value)}"
|
|
263
266
|
else
|
|
@@ -101,11 +101,21 @@ module MilkTea
|
|
|
101
101
|
|
|
102
102
|
def find_method_by_receiver_name(module_binding, receiver_type, name)
|
|
103
103
|
module_binding.methods.each do |key, methods|
|
|
104
|
-
|
|
104
|
+
next unless key.is_a?(receiver_type.class)
|
|
105
|
+
next unless key.name == receiver_type.name
|
|
106
|
+
next unless same_type_module?(key, receiver_type)
|
|
107
|
+
return methods[name] if methods.key?(name)
|
|
105
108
|
end
|
|
106
109
|
nil
|
|
107
110
|
end
|
|
108
111
|
|
|
112
|
+
def same_type_module?(type_a, type_b)
|
|
113
|
+
module_a = receiver_type_module_name(type_a)
|
|
114
|
+
module_b = receiver_type_module_name(type_b)
|
|
115
|
+
return true if module_a.nil? || module_b.nil?
|
|
116
|
+
module_a == module_b
|
|
117
|
+
end
|
|
118
|
+
|
|
109
119
|
def reachable_module_binding_for_type(receiver_type)
|
|
110
120
|
module_name = receiver_type_module_name(receiver_type)
|
|
111
121
|
return nil unless module_name
|
|
@@ -709,7 +719,7 @@ module MilkTea
|
|
|
709
719
|
|
|
710
720
|
def sized_layout_type?(type)
|
|
711
721
|
case type
|
|
712
|
-
when Types::Primitive, Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::Span, Types::StringView, Types::Task, Types::Event, Types::Subscription
|
|
722
|
+
when Types::Primitive, Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::Tuple, Types::Span, Types::StringView, Types::Task, Types::Event, Types::Subscription
|
|
713
723
|
true
|
|
714
724
|
when Types::Nullable
|
|
715
725
|
true
|
|
@@ -173,7 +173,7 @@ module MilkTea
|
|
|
173
173
|
|
|
174
174
|
if (type_ref = type_ref_from_specialization(callee))
|
|
175
175
|
specialized_type = resolve_type_ref(type_ref)
|
|
176
|
-
return if specialized_type.is_a?(Types::Struct) ||
|
|
176
|
+
return if specialized_type.is_a?(Types::Struct) || task_type?(specialized_type) || specialized_type.is_a?(Types::Vector) || specialized_type.is_a?(Types::Matrix) || specialized_type.is_a?(Types::Quaternion) || specialized_type.is_a?(Types::Simd)
|
|
177
177
|
end
|
|
178
178
|
end
|
|
179
179
|
|
|
@@ -846,7 +846,10 @@ module MilkTea
|
|
|
846
846
|
return false unless else_body
|
|
847
847
|
text << else_body
|
|
848
848
|
|
|
849
|
-
|
|
849
|
+
# The inline form would start at the `if` keyword's column, so the real
|
|
850
|
+
# line width includes the surrounding block's indentation.
|
|
851
|
+
indent = statement.branches.first.column.to_i - 1
|
|
852
|
+
(indent + text.strip.length) > 120
|
|
850
853
|
end
|
|
851
854
|
|
|
852
855
|
def source_line_from(line, column)
|
data/std/box2d.mt
CHANGED
|
@@ -111,9 +111,9 @@ public const B2_PI: float = c.B2_PI
|
|
|
111
111
|
public const B2_MAX_POLYGON_VERTICES: int = c.B2_MAX_POLYGON_VERTICES
|
|
112
112
|
public const B2_DEFAULT_CATEGORY_BITS: int = c.B2_DEFAULT_CATEGORY_BITS
|
|
113
113
|
|
|
114
|
-
public foreign function set_allocator(alloc_fcn:
|
|
114
|
+
public foreign function set_allocator(alloc_fcn: AllocFcn, free_fcn: FreeFcn) -> void = c.b2SetAllocator
|
|
115
115
|
public foreign function get_byte_count() -> int = c.b2GetByteCount
|
|
116
|
-
public foreign function set_assert_fcn(assert_fcn:
|
|
116
|
+
public foreign function set_assert_fcn(assert_fcn: AssertFcn) -> void = c.b2SetAssertFcn
|
|
117
117
|
public foreign function get_version() -> Version = c.b2GetVersion
|
|
118
118
|
public foreign function internal_assert_fcn(condition: str as cstr, file_name: str as cstr, line_number: int) -> int = c.b2InternalAssertFcn
|
|
119
119
|
public foreign function get_ticks() -> ulong = c.b2GetTicks
|
|
@@ -188,9 +188,9 @@ public foreign function dynamic_tree_move_proxy(tree: ptr[DynamicTree], proxy_id
|
|
|
188
188
|
public foreign function dynamic_tree_enlarge_proxy(tree: ptr[DynamicTree], proxy_id: int, aabb: AABB) -> void = c.b2DynamicTree_EnlargeProxy
|
|
189
189
|
public foreign function dynamic_tree_set_category_bits(tree: ptr[DynamicTree], proxy_id: int, category_bits: ptr_uint) -> void = c.b2DynamicTree_SetCategoryBits
|
|
190
190
|
public foreign function dynamic_tree_get_category_bits(tree: ptr[DynamicTree], proxy_id: int) -> ulong = c.b2DynamicTree_GetCategoryBits
|
|
191
|
-
public foreign function dynamic_tree_query(tree: const_ptr[DynamicTree], aabb: AABB, mask_bits: ptr_uint, callback:
|
|
192
|
-
public foreign function dynamic_tree_ray_cast(tree: const_ptr[DynamicTree], input: const_ptr[RayCastInput], mask_bits: ptr_uint, callback:
|
|
193
|
-
public foreign function dynamic_tree_shape_cast(tree: const_ptr[DynamicTree], input: const_ptr[ShapeCastInput], mask_bits: ptr_uint, callback:
|
|
191
|
+
public foreign function dynamic_tree_query(tree: const_ptr[DynamicTree], aabb: AABB, mask_bits: ptr_uint, callback: TreeQueryCallbackFcn, context: ptr[void]) -> TreeStats = c.b2DynamicTree_Query
|
|
192
|
+
public foreign function dynamic_tree_ray_cast(tree: const_ptr[DynamicTree], input: const_ptr[RayCastInput], mask_bits: ptr_uint, callback: TreeRayCastCallbackFcn, context: ptr[void]) -> TreeStats = c.b2DynamicTree_RayCast
|
|
193
|
+
public foreign function dynamic_tree_shape_cast(tree: const_ptr[DynamicTree], input: const_ptr[ShapeCastInput], mask_bits: ptr_uint, callback: TreeShapeCastCallbackFcn, context: ptr[void]) -> TreeStats = c.b2DynamicTree_ShapeCast
|
|
194
194
|
public foreign function dynamic_tree_get_height(tree: const_ptr[DynamicTree]) -> int = c.b2DynamicTree_GetHeight
|
|
195
195
|
public foreign function dynamic_tree_get_area_ratio(tree: const_ptr[DynamicTree]) -> float = c.b2DynamicTree_GetAreaRatio
|
|
196
196
|
public foreign function dynamic_tree_get_root_bounds(tree: const_ptr[DynamicTree]) -> AABB = c.b2DynamicTree_GetRootBounds
|
|
@@ -228,13 +228,13 @@ public foreign function world_draw(world_id: WorldId, inout draw: DebugDraw) ->
|
|
|
228
228
|
public foreign function world_get_body_events(world_id: WorldId) -> BodyEvents = c.b2World_GetBodyEvents
|
|
229
229
|
public foreign function world_get_sensor_events(world_id: WorldId) -> SensorEvents = c.b2World_GetSensorEvents
|
|
230
230
|
public foreign function world_get_contact_events(world_id: WorldId) -> ContactEvents = c.b2World_GetContactEvents
|
|
231
|
-
public foreign function world_overlap_aabb(world_id: WorldId, aabb: AABB, filter: QueryFilter, fcn:
|
|
232
|
-
public foreign function world_overlap_shape(world_id: WorldId, proxy: const_ptr[ShapeProxy], filter: QueryFilter, fcn:
|
|
233
|
-
public foreign function world_cast_ray(world_id: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn:
|
|
231
|
+
public foreign function world_overlap_aabb(world_id: WorldId, aabb: AABB, filter: QueryFilter, fcn: OverlapResultFcn, context: ptr[void]) -> TreeStats = c.b2World_OverlapAABB
|
|
232
|
+
public foreign function world_overlap_shape(world_id: WorldId, proxy: const_ptr[ShapeProxy], filter: QueryFilter, fcn: OverlapResultFcn, context: ptr[void]) -> TreeStats = c.b2World_OverlapShape
|
|
233
|
+
public foreign function world_cast_ray(world_id: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, context: ptr[void]) -> TreeStats = c.b2World_CastRay
|
|
234
234
|
public foreign function world_cast_ray_closest(world_id: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter) -> RayResult = c.b2World_CastRayClosest
|
|
235
|
-
public foreign function world_cast_shape(world_id: WorldId, proxy: const_ptr[ShapeProxy], translation: Vec2, filter: QueryFilter, fcn:
|
|
235
|
+
public foreign function world_cast_shape(world_id: WorldId, proxy: const_ptr[ShapeProxy], translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, context: ptr[void]) -> TreeStats = c.b2World_CastShape
|
|
236
236
|
public foreign function world_cast_mover(world_id: WorldId, mover: const_ptr[Capsule], translation: Vec2, filter: QueryFilter) -> float = c.b2World_CastMover
|
|
237
|
-
public foreign function world_collide_mover(world_id: WorldId, mover: const_ptr[Capsule], filter: QueryFilter, fcn:
|
|
237
|
+
public foreign function world_collide_mover(world_id: WorldId, mover: const_ptr[Capsule], filter: QueryFilter, fcn: PlaneResultFcn, context: ptr[void]) -> void = c.b2World_CollideMover
|
|
238
238
|
public foreign function world_enable_sleeping(world_id: WorldId, flag: bool) -> void = c.b2World_EnableSleeping
|
|
239
239
|
public foreign function world_is_sleeping_enabled(world_id: WorldId) -> bool = c.b2World_IsSleepingEnabled
|
|
240
240
|
public foreign function world_enable_continuous(world_id: WorldId, flag: bool) -> void = c.b2World_EnableContinuous
|
|
@@ -243,8 +243,8 @@ public foreign function world_set_restitution_threshold(world_id: WorldId, value
|
|
|
243
243
|
public foreign function world_get_restitution_threshold(world_id: WorldId) -> float = c.b2World_GetRestitutionThreshold
|
|
244
244
|
public foreign function world_set_hit_event_threshold(world_id: WorldId, value: float) -> void = c.b2World_SetHitEventThreshold
|
|
245
245
|
public foreign function world_get_hit_event_threshold(world_id: WorldId) -> float = c.b2World_GetHitEventThreshold
|
|
246
|
-
public foreign function world_set_custom_filter_callback(world_id: WorldId, fcn:
|
|
247
|
-
public foreign function world_set_pre_solve_callback(world_id: WorldId, fcn:
|
|
246
|
+
public foreign function world_set_custom_filter_callback(world_id: WorldId, fcn: CustomFilterFcn, context: ptr[void]) -> void = c.b2World_SetCustomFilterCallback
|
|
247
|
+
public foreign function world_set_pre_solve_callback(world_id: WorldId, fcn: PreSolveFcn, context: ptr[void]) -> void = c.b2World_SetPreSolveCallback
|
|
248
248
|
public foreign function world_set_gravity(world_id: WorldId, gravity: Vec2) -> void = c.b2World_SetGravity
|
|
249
249
|
public foreign function world_get_gravity(world_id: WorldId) -> Vec2 = c.b2World_GetGravity
|
|
250
250
|
public foreign function world_explode(world_id: WorldId, in explosion_def: ExplosionDef) -> void = c.b2World_Explode
|
|
@@ -258,8 +258,8 @@ public foreign function world_get_profile(world_id: WorldId) -> Profile = c.b2Wo
|
|
|
258
258
|
public foreign function world_get_counters(world_id: WorldId) -> Counters = c.b2World_GetCounters
|
|
259
259
|
public foreign function world_set_user_data(world_id: WorldId, user_data: ptr[void]) -> void = c.b2World_SetUserData
|
|
260
260
|
public foreign function world_get_user_data(world_id: WorldId) -> ptr[void] = c.b2World_GetUserData
|
|
261
|
-
public foreign function world_set_friction_callback(world_id: WorldId, callback:
|
|
262
|
-
public foreign function world_set_restitution_callback(world_id: WorldId, callback:
|
|
261
|
+
public foreign function world_set_friction_callback(world_id: WorldId, callback: FrictionCallback) -> void = c.b2World_SetFrictionCallback
|
|
262
|
+
public foreign function world_set_restitution_callback(world_id: WorldId, callback: RestitutionCallback) -> void = c.b2World_SetRestitutionCallback
|
|
263
263
|
public foreign function world_dump_memory_stats(world_id: WorldId) -> void = c.b2World_DumpMemoryStats
|
|
264
264
|
public foreign function world_rebuild_static_tree(world_id: WorldId) -> void = c.b2World_RebuildStaticTree
|
|
265
265
|
public foreign function world_enable_speculative(world_id: WorldId, flag: bool) -> void = c.b2World_EnableSpeculative
|
data/std/c/box2d.mt
CHANGED
|
@@ -10,9 +10,9 @@ type b2AllocFcn = fn(arg0: uint, arg1: int) -> ptr[void]
|
|
|
10
10
|
type b2FreeFcn = fn(arg0: ptr[void]) -> void
|
|
11
11
|
type b2AssertFcn = fn(arg0: cstr, arg1: cstr, arg2: int) -> int
|
|
12
12
|
|
|
13
|
-
external function b2SetAllocator(allocFcn:
|
|
13
|
+
external function b2SetAllocator(allocFcn: b2AllocFcn, freeFcn: b2FreeFcn) -> void
|
|
14
14
|
external function b2GetByteCount() -> int
|
|
15
|
-
external function b2SetAssertFcn(assertFcn:
|
|
15
|
+
external function b2SetAssertFcn(assertFcn: b2AssertFcn) -> void
|
|
16
16
|
|
|
17
17
|
struct b2Version:
|
|
18
18
|
major: int
|
|
@@ -313,15 +313,15 @@ external function b2DynamicTree_GetCategoryBits(tree: ptr[b2DynamicTree], proxyI
|
|
|
313
313
|
|
|
314
314
|
type b2TreeQueryCallbackFcn = fn(arg0: int, arg1: ulong, arg2: ptr[void]) -> bool
|
|
315
315
|
|
|
316
|
-
external function b2DynamicTree_Query(tree: const_ptr[b2DynamicTree], aabb: b2AABB, maskBits: ptr_uint, callback:
|
|
316
|
+
external function b2DynamicTree_Query(tree: const_ptr[b2DynamicTree], aabb: b2AABB, maskBits: ptr_uint, callback: b2TreeQueryCallbackFcn, context: ptr[void]) -> b2TreeStats
|
|
317
317
|
|
|
318
318
|
type b2TreeRayCastCallbackFcn = fn(arg0: const_ptr[b2RayCastInput], arg1: int, arg2: ulong, arg3: ptr[void]) -> float
|
|
319
319
|
|
|
320
|
-
external function b2DynamicTree_RayCast(tree: const_ptr[b2DynamicTree], input: const_ptr[b2RayCastInput], maskBits: ptr_uint, callback:
|
|
320
|
+
external function b2DynamicTree_RayCast(tree: const_ptr[b2DynamicTree], input: const_ptr[b2RayCastInput], maskBits: ptr_uint, callback: b2TreeRayCastCallbackFcn, context: ptr[void]) -> b2TreeStats
|
|
321
321
|
|
|
322
322
|
type b2TreeShapeCastCallbackFcn = fn(arg0: const_ptr[b2ShapeCastInput], arg1: int, arg2: ulong, arg3: ptr[void]) -> float
|
|
323
323
|
|
|
324
|
-
external function b2DynamicTree_ShapeCast(tree: const_ptr[b2DynamicTree], input: const_ptr[b2ShapeCastInput], maskBits: ptr_uint, callback:
|
|
324
|
+
external function b2DynamicTree_ShapeCast(tree: const_ptr[b2DynamicTree], input: const_ptr[b2ShapeCastInput], maskBits: ptr_uint, callback: b2TreeShapeCastCallbackFcn, context: ptr[void]) -> b2TreeStats
|
|
325
325
|
external function b2DynamicTree_GetHeight(tree: const_ptr[b2DynamicTree]) -> int
|
|
326
326
|
external function b2DynamicTree_GetAreaRatio(tree: const_ptr[b2DynamicTree]) -> float
|
|
327
327
|
external function b2DynamicTree_GetRootBounds(tree: const_ptr[b2DynamicTree]) -> b2AABB
|
|
@@ -382,7 +382,7 @@ const b2_nullChainId: b2ChainId = b2ChainId(index1 = 0, world0 = 0, generation =
|
|
|
382
382
|
const b2_nullJointId: b2JointId = b2JointId(index1 = 0, world0 = 0, generation = 0)
|
|
383
383
|
|
|
384
384
|
type b2TaskCallback = fn(arg0: int, arg1: int, arg2: uint, arg3: ptr[void]) -> void
|
|
385
|
-
type b2EnqueueTaskCallback = fn(arg0:
|
|
385
|
+
type b2EnqueueTaskCallback = fn(arg0: b2TaskCallback, arg1: int, arg2: int, arg3: ptr[void], arg4: ptr[void]) -> ptr[void]
|
|
386
386
|
type b2FinishTaskCallback = fn(arg0: ptr[void], arg1: ptr[void]) -> void
|
|
387
387
|
type b2FrictionCallback = fn(arg0: float, arg1: int, arg2: float, arg3: int) -> float
|
|
388
388
|
type b2RestitutionCallback = fn(arg0: float, arg1: int, arg2: float, arg3: int) -> float
|
|
@@ -404,13 +404,13 @@ struct b2WorldDef:
|
|
|
404
404
|
contactDampingRatio: float
|
|
405
405
|
maxContactPushSpeed: float
|
|
406
406
|
maximumLinearSpeed: float
|
|
407
|
-
frictionCallback:
|
|
408
|
-
restitutionCallback:
|
|
407
|
+
frictionCallback: b2FrictionCallback
|
|
408
|
+
restitutionCallback: b2RestitutionCallback
|
|
409
409
|
enableSleep: bool
|
|
410
410
|
enableContinuous: bool
|
|
411
411
|
workerCount: int
|
|
412
|
-
enqueueTask:
|
|
413
|
-
finishTask:
|
|
412
|
+
enqueueTask: b2EnqueueTaskCallback
|
|
413
|
+
finishTask: b2FinishTaskCallback
|
|
414
414
|
userTaskContext: ptr[void]
|
|
415
415
|
userData: ptr[void]
|
|
416
416
|
internalValue: int
|
|
@@ -942,13 +942,13 @@ external function b2World_Draw(worldId: b2WorldId, draw: ptr[b2DebugDraw]) -> vo
|
|
|
942
942
|
external function b2World_GetBodyEvents(worldId: b2WorldId) -> b2BodyEvents
|
|
943
943
|
external function b2World_GetSensorEvents(worldId: b2WorldId) -> b2SensorEvents
|
|
944
944
|
external function b2World_GetContactEvents(worldId: b2WorldId) -> b2ContactEvents
|
|
945
|
-
external function b2World_OverlapAABB(worldId: b2WorldId, aabb: b2AABB, filter: b2QueryFilter, fcn:
|
|
946
|
-
external function b2World_OverlapShape(worldId: b2WorldId, proxy: const_ptr[b2ShapeProxy], filter: b2QueryFilter, fcn:
|
|
947
|
-
external function b2World_CastRay(worldId: b2WorldId, origin: b2Vec2, translation: b2Vec2, filter: b2QueryFilter, fcn:
|
|
945
|
+
external function b2World_OverlapAABB(worldId: b2WorldId, aabb: b2AABB, filter: b2QueryFilter, fcn: b2OverlapResultFcn, context: ptr[void]) -> b2TreeStats
|
|
946
|
+
external function b2World_OverlapShape(worldId: b2WorldId, proxy: const_ptr[b2ShapeProxy], filter: b2QueryFilter, fcn: b2OverlapResultFcn, context: ptr[void]) -> b2TreeStats
|
|
947
|
+
external function b2World_CastRay(worldId: b2WorldId, origin: b2Vec2, translation: b2Vec2, filter: b2QueryFilter, fcn: b2CastResultFcn, context: ptr[void]) -> b2TreeStats
|
|
948
948
|
external function b2World_CastRayClosest(worldId: b2WorldId, origin: b2Vec2, translation: b2Vec2, filter: b2QueryFilter) -> b2RayResult
|
|
949
|
-
external function b2World_CastShape(worldId: b2WorldId, proxy: const_ptr[b2ShapeProxy], translation: b2Vec2, filter: b2QueryFilter, fcn:
|
|
949
|
+
external function b2World_CastShape(worldId: b2WorldId, proxy: const_ptr[b2ShapeProxy], translation: b2Vec2, filter: b2QueryFilter, fcn: b2CastResultFcn, context: ptr[void]) -> b2TreeStats
|
|
950
950
|
external function b2World_CastMover(worldId: b2WorldId, mover: const_ptr[b2Capsule], translation: b2Vec2, filter: b2QueryFilter) -> float
|
|
951
|
-
external function b2World_CollideMover(worldId: b2WorldId, mover: const_ptr[b2Capsule], filter: b2QueryFilter, fcn:
|
|
951
|
+
external function b2World_CollideMover(worldId: b2WorldId, mover: const_ptr[b2Capsule], filter: b2QueryFilter, fcn: b2PlaneResultFcn, context: ptr[void]) -> void
|
|
952
952
|
external function b2World_EnableSleeping(worldId: b2WorldId, flag: bool) -> void
|
|
953
953
|
external function b2World_IsSleepingEnabled(worldId: b2WorldId) -> bool
|
|
954
954
|
external function b2World_EnableContinuous(worldId: b2WorldId, flag: bool) -> void
|
|
@@ -957,8 +957,8 @@ external function b2World_SetRestitutionThreshold(worldId: b2WorldId, value: flo
|
|
|
957
957
|
external function b2World_GetRestitutionThreshold(worldId: b2WorldId) -> float
|
|
958
958
|
external function b2World_SetHitEventThreshold(worldId: b2WorldId, value: float) -> void
|
|
959
959
|
external function b2World_GetHitEventThreshold(worldId: b2WorldId) -> float
|
|
960
|
-
external function b2World_SetCustomFilterCallback(worldId: b2WorldId, fcn:
|
|
961
|
-
external function b2World_SetPreSolveCallback(worldId: b2WorldId, fcn:
|
|
960
|
+
external function b2World_SetCustomFilterCallback(worldId: b2WorldId, fcn: b2CustomFilterFcn, context: ptr[void]) -> void
|
|
961
|
+
external function b2World_SetPreSolveCallback(worldId: b2WorldId, fcn: b2PreSolveFcn, context: ptr[void]) -> void
|
|
962
962
|
external function b2World_SetGravity(worldId: b2WorldId, gravity: b2Vec2) -> void
|
|
963
963
|
external function b2World_GetGravity(worldId: b2WorldId) -> b2Vec2
|
|
964
964
|
external function b2World_Explode(worldId: b2WorldId, explosionDef: const_ptr[b2ExplosionDef]) -> void
|
|
@@ -972,8 +972,8 @@ external function b2World_GetProfile(worldId: b2WorldId) -> b2Profile
|
|
|
972
972
|
external function b2World_GetCounters(worldId: b2WorldId) -> b2Counters
|
|
973
973
|
external function b2World_SetUserData(worldId: b2WorldId, userData: ptr[void]) -> void
|
|
974
974
|
external function b2World_GetUserData(worldId: b2WorldId) -> ptr[void]
|
|
975
|
-
external function b2World_SetFrictionCallback(worldId: b2WorldId, callback:
|
|
976
|
-
external function b2World_SetRestitutionCallback(worldId: b2WorldId, callback:
|
|
975
|
+
external function b2World_SetFrictionCallback(worldId: b2WorldId, callback: b2FrictionCallback) -> void
|
|
976
|
+
external function b2World_SetRestitutionCallback(worldId: b2WorldId, callback: b2RestitutionCallback) -> void
|
|
977
977
|
external function b2World_DumpMemoryStats(worldId: b2WorldId) -> void
|
|
978
978
|
external function b2World_RebuildStaticTree(worldId: b2WorldId) -> void
|
|
979
979
|
external function b2World_EnableSpeculative(worldId: b2WorldId, flag: bool) -> void
|
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.3.
|
|
4
|
+
version: 0.3.37
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -624,7 +624,7 @@ metadata:
|
|
|
624
624
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
625
625
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
626
626
|
post_install_message: |
|
|
627
|
-
Milk Tea 0.3.
|
|
627
|
+
Milk Tea 0.3.37 installed!
|
|
628
628
|
|
|
629
629
|
System requirements:
|
|
630
630
|
- A C compiler (gcc or clang) must be available on PATH
|