mt-lang 0.3.16 → 0.3.20
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/docs/language-design.md +3 -4
- data/docs/language-manual.md +3 -3
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/{binding_types.rb → bindings.rb} +1 -1
- data/lib/milk_tea/core/c_backend/expressions.rb +34 -23
- data/lib/milk_tea/core/c_backend/feature_detection.rb +25 -45
- data/lib/milk_tea/core/c_backend/type_collectors.rb +18 -30
- data/lib/milk_tea/core/c_backend/type_declaration.rb +0 -6
- data/lib/milk_tea/core/c_backend.rb +63 -54
- data/lib/milk_tea/core/compile_time.rb +279 -74
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +1 -1
- data/lib/milk_tea/core/{compatibility_helpers.rb → intrinsics.rb} +9 -2
- data/lib/milk_tea/core/lexer.rb +55 -48
- data/lib/milk_tea/core/lowering/block.rb +9 -0
- data/lib/milk_tea/core/lowering/calls.rb +2 -0
- data/lib/milk_tea/core/lowering/declarations.rb +1 -1
- data/lib/milk_tea/core/lowering/functions.rb +11 -8
- data/lib/milk_tea/core/lowering/resolve.rb +10 -3
- data/lib/milk_tea/core/lowering/scans.rb +13 -18
- data/lib/milk_tea/core/lowering.rb +18 -18
- data/lib/milk_tea/core/module_binder.rb +9 -10
- data/lib/milk_tea/core/module_loader.rb +64 -57
- data/lib/milk_tea/core/module_path_resolver.rb +1 -4
- data/lib/milk_tea/core/parser/declarations.rb +43 -19
- data/lib/milk_tea/core/parser/expressions.rb +4 -7
- data/lib/milk_tea/core/parser/statements.rb +5 -5
- data/lib/milk_tea/core/parser.rb +43 -17
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +24 -31
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +20 -23
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +117 -85
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +19 -41
- data/lib/milk_tea/core/semantic_analyzer.rb +57 -38
- data/lib/milk_tea/core.rb +6 -2
- data/lib/milk_tea/dap/lldb_dap_backend.rb +153 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +1 -1
- data/lib/milk_tea/dap.rb +1 -1
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +6 -0
- data/lib/milk_tea/lsp.rb +1 -7
- data/lib/milk_tea/{bindings/cli.rb → tooling/bindgen_cli.rb} +1 -1
- data/lib/milk_tea/tooling/cli/commands/bindgen.rb +11 -0
- data/lib/milk_tea/tooling/cli/commands/build.rb +37 -0
- data/lib/milk_tea/tooling/cli/commands/cache.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/check.rb +116 -0
- data/lib/milk_tea/tooling/cli/commands/command_base.rb +8 -0
- data/lib/milk_tea/tooling/cli/commands/completions.rb +48 -0
- data/lib/milk_tea/tooling/cli/commands/dap.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/debug.rb +77 -0
- data/lib/milk_tea/tooling/cli/commands/deps.rb +17 -0
- data/lib/milk_tea/tooling/cli/commands/docs.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/emit_c.rb +64 -0
- data/lib/milk_tea/tooling/cli/commands/format.rb +199 -0
- data/lib/milk_tea/tooling/cli/commands/lex.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/lint.rb +248 -0
- data/lib/milk_tea/tooling/cli/commands/lower.rb +50 -0
- data/lib/milk_tea/tooling/cli/commands/lsp.rb +43 -0
- data/lib/milk_tea/tooling/cli/commands/new.rb +26 -0
- data/lib/milk_tea/tooling/cli/commands/parse.rb +51 -0
- data/lib/milk_tea/tooling/cli/commands/run.rb +99 -0
- data/lib/milk_tea/tooling/cli/commands/snapshot.rb +117 -0
- data/lib/milk_tea/tooling/cli/commands/test.rb +557 -0
- data/lib/milk_tea/tooling/cli/commands/toolchain.rb +16 -0
- data/lib/milk_tea/tooling/cli.rb +101 -1893
- data/lib/milk_tea/tooling.rb +1 -1
- metadata +29 -9
- data/lib/milk_tea/core/compile_time/const_eval.rb +0 -182
- data/lib/milk_tea/core/module_loader/errors.rb +0 -23
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -156
- /data/lib/milk_tea/core/lowering/{async.rb → async/frame_builder.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83f7a9e4ec79d81bd7d2e64ebb469871fecb5e4b3f888c932061d5fa265b7544
|
|
4
|
+
data.tar.gz: c08d508785143d338a6a47adfcedcf605b30e8e9990913a44178344643944178
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95818de5161127d240aacd92b2f8a727e29d1962c11bd9161faa0f0286ac701d2b328352d7ac51bdab23ed2b76a8ccaa7e698490c4bbe5b99edb9452de76cbac
|
|
7
|
+
data.tar.gz: 0d188ebbabd4f175a201ea61c7cde3393a93b9deed991fbb639935b125e565b3b679f16c0fb72c4f96939475d8b6a199362e66920d65e49dd60e6dbc248df372
|
data/docs/language-design.md
CHANGED
|
@@ -521,7 +521,6 @@ The type system must stay simple, explicit, and close to C.
|
|
|
521
521
|
### Primitive types
|
|
522
522
|
|
|
523
523
|
- `bool`
|
|
524
|
-
- `byte`
|
|
525
524
|
- `char`
|
|
526
525
|
- `byte`, `short`, `int`, `long`
|
|
527
526
|
- `ubyte`, `ushort`, `uint`, `ulong`
|
|
@@ -587,7 +586,7 @@ Notes:
|
|
|
587
586
|
- If low-level code needs to validate raw `array[char, N]` storage as text, that conversion belongs in an explicit helper or imported boundary, not as a built-in method family on raw arrays.
|
|
588
587
|
- Addressable `str_buffer[N]` values also coerce to `span[char]`, so writable foreign text APIs can still accept builders directly when they do not want a second application-facing text abstraction.
|
|
589
588
|
- `str_buffer[N]` is not an ABI type. Raw bindings still spell writable text as `ptr[char]` or `span[char]`; `str_buffer[N]` is the caller-side text object.
|
|
590
|
-
- `str_buffer[N]` has a built-in text surface: `.clear()`, `.assign(str)`, `.append(str)`, `.len()`, `.capacity()`, `.as_str()`, and `.as_cstr()`.
|
|
589
|
+
- `str_buffer[N]` has a built-in text surface: `.clear()`, `.assign(str)`, `.append(str)`, `.assign_format(str)`, `.append_format(str)`, `.len()`, `.capacity()`, `.as_str()`, and `.as_cstr()`.
|
|
591
590
|
- `.assign(...)` replaces the current contents and traps at runtime if the new text exceeds capacity.
|
|
592
591
|
- `.append(...)` extends the current contents and traps at runtime if the appended text would exceed capacity.
|
|
593
592
|
- `.len()` returns the tracked text length, revalidating UTF-8 and rescanning for the trailing NUL if the builder was passed through a writable `span[char]` or `ptr[char]` alias.
|
|
@@ -650,7 +649,7 @@ joins the path with underscores (e.g., `module_Rectangle_Edge`).
|
|
|
650
649
|
|
|
651
650
|
#### Enums
|
|
652
651
|
|
|
653
|
-
Enums
|
|
652
|
+
Enums use an integer backing type, defaulting to `int` when omitted; members auto-increment from 0 or the previous explicit value.
|
|
654
653
|
|
|
655
654
|
```mt
|
|
656
655
|
enum WeaponKind: ubyte
|
|
@@ -661,7 +660,7 @@ enum WeaponKind: ubyte
|
|
|
661
660
|
|
|
662
661
|
#### Flags
|
|
663
662
|
|
|
664
|
-
Flags are named bitmasks with
|
|
663
|
+
Flags are named bitmasks with an integer backing type (defaulting to `int` when omitted).
|
|
665
664
|
|
|
666
665
|
```mt
|
|
667
666
|
flags WindowFlags: uint
|
data/docs/language-manual.md
CHANGED
|
@@ -1007,7 +1007,7 @@ Rules:
|
|
|
1007
1007
|
- `ivec2` `ivec3` `ivec4` — integer vectors with `.x` `.y` `.z` `.w` fields
|
|
1008
1008
|
- `mat3` `mat4` — column-major matrices; `mat3` has columns `.col0`–`.col2` (each `vec3`), `mat4` has `.col0`–`.col3` (each `vec4`)
|
|
1009
1009
|
- `quat` — quaternion with `.x` `.y` `.z` `.w` fields; memory-layout compatible with `vec4`
|
|
1010
|
-
- `simd[T, N]` — SIMD vector with `N` lanes of numeric primitive type `T`; total width must be 128 or 256 bits. Supports component-wise arithmetic (`+` `-` `*`
|
|
1010
|
+
- `simd[T, N]` — SIMD vector with `N` lanes of numeric primitive type `T`; total width must be 128 or 256 bits. Supports component-wise arithmetic (`+` `-` `*` `/`, and `%` for integer lanes), bitwise (`&` `|` `^` `~`), shift (`<<` `>>`), and compound assignment. Lane access via compile-time constant index `[i]`. Lowers to GCC/Clang `__attribute__((__vector_size__))`.
|
|
1011
1011
|
|
|
1012
1012
|
Primitive type names are reserved. They cannot be reused for value bindings, parameters, locals, import aliases, or type parameters.
|
|
1013
1013
|
|
|
@@ -1043,7 +1043,7 @@ let q = quat(x = 0.0, y = 0.0, z = 0.0, w = 1.0)
|
|
|
1043
1043
|
- `Option[T]`
|
|
1044
1044
|
- `Result[T, E]`
|
|
1045
1045
|
- `SoA[T, N]` — Structure-of-Arrays: transforms `T`'s fields into separate arrays of length `N`; access as `soa[i].field`
|
|
1046
|
-
- `simd[T, N]` — SIMD vector: fixed-width vector of `N` numeric lanes. Constructed with `simd[T, N](lane0, lane1, ...)`. Supports component-wise `+` `-` `*`
|
|
1046
|
+
- `simd[T, N]` — SIMD vector: fixed-width vector of `N` numeric lanes. Constructed with `simd[T, N](lane0, lane1, ...)`. Supports component-wise `+` `-` `*` `/` (and `%` for integer lanes), bitwise `&` `|` `^` `~`, shift `<<` `>>`, unary `-` `~`, and compound assignment. Lane access via compile-time constant `[i]`. Total width must be 128 or 256 bits. Lowers to GCC/Clang vector extensions.
|
|
1047
1047
|
- `dyn[InterfaceName]` — runtime interface value (fat pointer: data + vtable). Constructed via `adapt[Interface](value: ref[T])`. @see §3.5.
|
|
1048
1048
|
- `atomic[T]` — atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load() -> T`, `store(value: T)`, `add(value: T) -> T`, `sub(value: T) -> T`, `exchange(value: T) -> T`. All operations use sequential consistency. Lowers to C11 `_Atomic T` with `__atomic_*` builtins. `atomic[T]` is zero-initializable and sendable.
|
|
1049
1049
|
- `(T, U)` — tuple type. Positional fields auto-named `_0`, `_1`. Named fields use `(x = T, y = U)`. Copy by value, returns supported.
|
|
@@ -1054,7 +1054,7 @@ let q = quat(x = 0.0, y = 0.0, z = 0.0, w = 1.0)
|
|
|
1054
1054
|
- for pointer-like bases (`ptr[T]`, `const_ptr[T]`, `own[T]`, `cstr`, `fn(...)`, `proc(...)`, opaque), `T?` is a nullable pointer with `null` as the absent value
|
|
1055
1055
|
- for non-pointer value bases (`int`, `bool`, `float`, structs, ...), `T?` is stored inline by value as a tagged optional (a presence flag plus the value); it copies by value with no hidden heap allocation or pointer aliasing
|
|
1056
1056
|
- `null` expresses absence in any nullable context; the explicit typed `null[...]` form's target must be pointer-like
|
|
1057
|
-
- in nullable pointer-like contexts,
|
|
1057
|
+
- in nullable pointer-like contexts, `zero[ptr[T]]` is rejected; use `null` instead
|
|
1058
1058
|
- at an FFI boundary (`external` / `foreign function` parameters and returns), only pointer-like `T?` is allowed; a non-pointer value nullable such as `int?` is rejected — use `ptr[T]?` or pass an explicit struct
|
|
1059
1059
|
|
|
1060
1060
|
### 6.4 Generics
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -331,11 +331,10 @@ module MilkTea
|
|
|
331
331
|
end
|
|
332
332
|
|
|
333
333
|
def emit_cast_operand(expression)
|
|
334
|
-
|
|
335
|
-
when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr, IR::AddressOf, IR::Cast, IR::Unary
|
|
336
|
-
emit_expression(expression)
|
|
337
|
-
else
|
|
334
|
+
if expression.is_a?(IR::Binary) || expression.is_a?(IR::Conditional)
|
|
338
335
|
"(#{emit_expression(expression)})"
|
|
336
|
+
else
|
|
337
|
+
emit_expression(expression)
|
|
339
338
|
end
|
|
340
339
|
end
|
|
341
340
|
|
|
@@ -425,28 +424,16 @@ module MilkTea
|
|
|
425
424
|
|
|
426
425
|
def emit_variant_field_initializer(type, arm_name, field)
|
|
427
426
|
field_type = type.arm(arm_name).fetch(field.name)
|
|
427
|
+
outer_c = named_type_c_name(type)
|
|
428
|
+
|
|
428
429
|
if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
|
|
429
430
|
emit_nullable_some_initializer(field_type, field.value)
|
|
430
431
|
elsif field.value.is_a?(IR::AddressOf) && !field_type.is_a?(Types::Nullable)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
elsif aggregate_field_creates_cycle?(field_type,
|
|
435
|
-
|
|
436
|
-
elem_c_name = c_type(array_element_type(field_type))
|
|
437
|
-
elem_count = array_length(field_type)
|
|
438
|
-
elements = field.value.is_a?(IR::ArrayLiteral) ? field.value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
|
|
439
|
-
"((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
|
|
440
|
-
elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
|
|
441
|
-
!field_type.is_a?(Types::GenericInstance)
|
|
442
|
-
field_c_name = named_type_c_name(field_type)
|
|
443
|
-
init = emit_initializer(field.value)
|
|
444
|
-
source_expr = if init.start_with?("{")
|
|
445
|
-
"&(#{c_type(field_type)})#{init}"
|
|
446
|
-
else
|
|
447
|
-
"&(#{init})"
|
|
448
|
-
end
|
|
449
|
-
"((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
|
|
432
|
+
emit_addressof_field_initializer(field_type, field.value)
|
|
433
|
+
elsif aggregate_field_creates_cycle?(field_type, outer_c) && array_type?(field_type)
|
|
434
|
+
emit_cyclic_array_initializer(field_type, field.value)
|
|
435
|
+
elsif aggregate_field_creates_cycle?(field_type, outer_c) && !field_type.is_a?(Types::GenericInstance)
|
|
436
|
+
emit_cyclic_struct_initializer(field_type, field.value)
|
|
450
437
|
elsif void_storage_field?(field_type)
|
|
451
438
|
emit_void_field_initializer(field.value)
|
|
452
439
|
else
|
|
@@ -454,6 +441,30 @@ module MilkTea
|
|
|
454
441
|
end
|
|
455
442
|
end
|
|
456
443
|
|
|
444
|
+
def emit_addressof_field_initializer(field_type, value)
|
|
445
|
+
c_type_name = named_type_c_name(field_type)
|
|
446
|
+
inner = value.expression
|
|
447
|
+
"((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def emit_cyclic_array_initializer(field_type, value)
|
|
451
|
+
elem_c_name = c_type(array_element_type(field_type))
|
|
452
|
+
elem_count = array_length(field_type)
|
|
453
|
+
elements = value.is_a?(IR::ArrayLiteral) ? value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
|
|
454
|
+
"((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def emit_cyclic_struct_initializer(field_type, value)
|
|
458
|
+
field_c_name = named_type_c_name(field_type)
|
|
459
|
+
init = emit_initializer(value)
|
|
460
|
+
source_expr = if init.start_with?("{")
|
|
461
|
+
"&(#{c_type(field_type)})#{init}"
|
|
462
|
+
else
|
|
463
|
+
"&(#{init})"
|
|
464
|
+
end
|
|
465
|
+
"((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
|
|
466
|
+
end
|
|
467
|
+
|
|
457
468
|
def emit_void_field_initializer(expression)
|
|
458
469
|
"(#{emit_expression(expression)}, 0)"
|
|
459
470
|
end
|
|
@@ -342,66 +342,46 @@ module MilkTea
|
|
|
342
342
|
function.body.any? { |statement| statement_uses_str_equality?(statement) }
|
|
343
343
|
end
|
|
344
344
|
|
|
345
|
-
def
|
|
345
|
+
def any_ir_statement?(statement, expression_pred:, **kwargs)
|
|
346
346
|
case statement
|
|
347
347
|
when IR::LocalDecl
|
|
348
|
-
|
|
348
|
+
statement.value && expression_pred.call(statement.value, **kwargs)
|
|
349
349
|
when IR::Assignment
|
|
350
|
-
|
|
350
|
+
expression_pred.call(statement.target, **kwargs) || expression_pred.call(statement.value, **kwargs)
|
|
351
351
|
when IR::BlockStmt
|
|
352
|
-
statement.body.any? { |inner|
|
|
352
|
+
statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) }
|
|
353
353
|
when IR::WhileStmt
|
|
354
|
-
|
|
354
|
+
expression_pred.call(statement.condition, **kwargs) ||
|
|
355
|
+
statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) }
|
|
355
356
|
when IR::ForStmt
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
statement.body.any? { |inner|
|
|
359
|
-
|
|
357
|
+
any_ir_statement?(statement.init, expression_pred:, **kwargs) ||
|
|
358
|
+
expression_pred.call(statement.condition, **kwargs) ||
|
|
359
|
+
statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } ||
|
|
360
|
+
any_ir_statement?(statement.post, expression_pred:, **kwargs)
|
|
360
361
|
when IR::IfStmt
|
|
361
|
-
|
|
362
|
-
statement.then_body.any? { |inner|
|
|
363
|
-
(statement.else_body && statement.else_body.any? { |inner|
|
|
362
|
+
expression_pred.call(statement.condition, **kwargs) ||
|
|
363
|
+
statement.then_body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } ||
|
|
364
|
+
(statement.else_body && statement.else_body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) })
|
|
364
365
|
when IR::SwitchStmt
|
|
365
|
-
|
|
366
|
+
expression_pred.call(statement.expression, **kwargs) ||
|
|
367
|
+
statement.cases.any? { |switch_case| switch_case.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } }
|
|
366
368
|
when IR::StaticAssert
|
|
367
|
-
|
|
369
|
+
expression_pred.call(statement.condition, **kwargs) || expression_pred.call(statement.message, **kwargs)
|
|
368
370
|
when IR::ReturnStmt
|
|
369
|
-
statement.value &&
|
|
371
|
+
statement.value && expression_pred.call(statement.value, **kwargs)
|
|
370
372
|
when IR::ExpressionStmt
|
|
371
|
-
|
|
373
|
+
expression_pred.call(statement.expression, **kwargs)
|
|
374
|
+
else
|
|
375
|
+
false
|
|
372
376
|
end
|
|
373
377
|
end
|
|
374
378
|
|
|
379
|
+
def statement_uses_named_call?(statement, callees)
|
|
380
|
+
any_ir_statement?(statement, expression_pred: ->(e) { expression_uses_named_call?(e, callees) })
|
|
381
|
+
end
|
|
382
|
+
|
|
375
383
|
def statement_uses_str_equality?(statement)
|
|
376
|
-
|
|
377
|
-
when IR::LocalDecl
|
|
378
|
-
expression_uses_str_equality?(statement.value)
|
|
379
|
-
when IR::Assignment
|
|
380
|
-
expression_uses_str_equality?(statement.target) || expression_uses_str_equality?(statement.value)
|
|
381
|
-
when IR::BlockStmt
|
|
382
|
-
statement.body.any? { |inner| statement_uses_str_equality?(inner) }
|
|
383
|
-
when IR::WhileStmt
|
|
384
|
-
expression_uses_str_equality?(statement.condition) || statement.body.any? { |inner| statement_uses_str_equality?(inner) }
|
|
385
|
-
when IR::ForStmt
|
|
386
|
-
statement_uses_str_equality?(statement.init) ||
|
|
387
|
-
expression_uses_str_equality?(statement.condition) ||
|
|
388
|
-
statement.body.any? { |inner| statement_uses_str_equality?(inner) } ||
|
|
389
|
-
statement_uses_str_equality?(statement.post)
|
|
390
|
-
when IR::IfStmt
|
|
391
|
-
expression_uses_str_equality?(statement.condition) ||
|
|
392
|
-
statement.then_body.any? { |inner| statement_uses_str_equality?(inner) } ||
|
|
393
|
-
(statement.else_body && statement.else_body.any? { |inner| statement_uses_str_equality?(inner) })
|
|
394
|
-
when IR::SwitchStmt
|
|
395
|
-
expression_uses_str_equality?(statement.expression) || statement.cases.any? { |switch_case| switch_case.body.any? { |inner| statement_uses_str_equality?(inner) } }
|
|
396
|
-
when IR::StaticAssert
|
|
397
|
-
expression_uses_str_equality?(statement.condition) || expression_uses_str_equality?(statement.message)
|
|
398
|
-
when IR::ReturnStmt
|
|
399
|
-
statement.value && expression_uses_str_equality?(statement.value)
|
|
400
|
-
when IR::ExpressionStmt
|
|
401
|
-
expression_uses_str_equality?(statement.expression)
|
|
402
|
-
else
|
|
403
|
-
false
|
|
404
|
-
end
|
|
384
|
+
any_ir_statement?(statement, expression_pred: ->(e) { expression_uses_str_equality?(e) })
|
|
405
385
|
end
|
|
406
386
|
|
|
407
387
|
def expression_uses_named_call?(expression, callees)
|
|
@@ -241,21 +241,15 @@ module MilkTea
|
|
|
241
241
|
end
|
|
242
242
|
|
|
243
243
|
def collect_soa_from_statements(statements, soa_types, visited)
|
|
244
|
-
statements
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
when IR::WhileStmt
|
|
254
|
-
collect_soa_from_statements(stmt.body || [], soa_types, visited)
|
|
255
|
-
when IR::ForStmt
|
|
256
|
-
collect_soa_from_statements(stmt.body || [], soa_types, visited)
|
|
257
|
-
end
|
|
258
|
-
end
|
|
244
|
+
each_ir_statement_for_type_collection(statements,
|
|
245
|
+
type_collector_method: :collect_soa_type,
|
|
246
|
+
expression_walker_method: :collect_soa_type_in_expression,
|
|
247
|
+
accumulator: soa_types, visited:)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def collect_soa_type_in_expression(expression, soa_types, visited)
|
|
251
|
+
return unless expression.respond_to?(:type)
|
|
252
|
+
collect_soa_type(expression.type, soa_types, visited)
|
|
259
253
|
end
|
|
260
254
|
|
|
261
255
|
def collect_soa_type(type, soa_types, visited)
|
|
@@ -290,21 +284,15 @@ module MilkTea
|
|
|
290
284
|
end
|
|
291
285
|
|
|
292
286
|
def collect_simd_from_statements(statements, simd_types, visited)
|
|
293
|
-
statements
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
when IR::WhileStmt
|
|
303
|
-
collect_simd_from_statements(stmt.body || [], simd_types, visited)
|
|
304
|
-
when IR::ForStmt
|
|
305
|
-
collect_simd_from_statements(stmt.body || [], simd_types, visited)
|
|
306
|
-
end
|
|
307
|
-
end
|
|
287
|
+
each_ir_statement_for_type_collection(statements,
|
|
288
|
+
type_collector_method: :collect_simd_type,
|
|
289
|
+
expression_walker_method: :collect_simd_type_in_expression,
|
|
290
|
+
accumulator: simd_types, visited:)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def collect_simd_type_in_expression(expression, simd_types, visited)
|
|
294
|
+
return unless expression.respond_to?(:type)
|
|
295
|
+
collect_simd_type(expression.type, simd_types, visited)
|
|
308
296
|
end
|
|
309
297
|
|
|
310
298
|
def collect_simd_type(type, simd_types, visited)
|
|
@@ -61,12 +61,6 @@ module MilkTea
|
|
|
61
61
|
lines
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def variant_self_reference?(type, outer_c)
|
|
65
|
-
return false unless type.is_a?(Types::Variant) || type.is_a?(Types::VariantInstance)
|
|
66
|
-
|
|
67
|
-
named_type_c_name(type) == outer_c
|
|
68
|
-
end
|
|
69
|
-
|
|
70
64
|
def emit_variant(variant_decl)
|
|
71
65
|
lines = []
|
|
72
66
|
outer_c = variant_decl.linkage_name
|
|
@@ -38,6 +38,20 @@ module MilkTea
|
|
|
38
38
|
# scanning a 600 KB source file) never trigger a false positive, yet low
|
|
39
39
|
# enough that a genuinely infinite loop fires a clear fatal within ~1 s.
|
|
40
40
|
LOOP_GUARD_MAX_ITERATIONS = 50_000_000
|
|
41
|
+
EQUALITY_OPERATORS = ["==", "!="].freeze
|
|
42
|
+
|
|
43
|
+
include AggregateUtils
|
|
44
|
+
include TypeSystem
|
|
45
|
+
include Reachability
|
|
46
|
+
include FeatureDetection
|
|
47
|
+
include TypeCollectors
|
|
48
|
+
include Statements
|
|
49
|
+
include ControlFlowEmission
|
|
50
|
+
include RuntimeHelpers
|
|
51
|
+
include FormatHelpers
|
|
52
|
+
include TypeDeclaration
|
|
53
|
+
include Expressions
|
|
54
|
+
include Reinterpret
|
|
41
55
|
|
|
42
56
|
def self.emit(program, emit_line_directives: true, debug_guards: false)
|
|
43
57
|
new(program, emit_line_directives:, debug_guards:).emit
|
|
@@ -61,11 +75,27 @@ module MilkTea
|
|
|
61
75
|
|
|
62
76
|
def emit
|
|
63
77
|
lines = []
|
|
78
|
+
@cyclic_aggregate_pairs = build_cyclic_aggregate_pairs(
|
|
79
|
+
emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls +
|
|
80
|
+
emitted_aggregate_unions +
|
|
81
|
+
emitted_aggregate_variants + collect_generic_variant_decls
|
|
82
|
+
)
|
|
83
|
+
|
|
64
84
|
constants = emitted_constants
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
|
|
86
|
+
emit_preamble(lines)
|
|
87
|
+
emit_conditional_helpers(lines)
|
|
88
|
+
emit_type_declarations(lines)
|
|
89
|
+
emit_function_forward_declarations(lines)
|
|
90
|
+
emit_globals_and_constants(lines, constants)
|
|
91
|
+
emit_per_type_helpers(lines)
|
|
92
|
+
emit_string_literal_constants_section(lines)
|
|
93
|
+
emit_function_definitions(lines)
|
|
94
|
+
|
|
95
|
+
lines.join("\n").rstrip + "\n"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def emit_preamble(lines)
|
|
69
99
|
headers = @program.includes.map(&:header)
|
|
70
100
|
if headers.include?("\"fs_support.h\"") || headers.include?("\"tls_support.h\"") || uses_parallel_for_helper? || uses_spawn_all_helper? || uses_detach_helper?
|
|
71
101
|
lines << "#ifndef _GNU_SOURCE"
|
|
@@ -89,70 +119,61 @@ module MilkTea
|
|
|
89
119
|
lines << "#include #{header}"
|
|
90
120
|
end
|
|
91
121
|
lines << ""
|
|
122
|
+
end
|
|
92
123
|
|
|
124
|
+
def emit_conditional_helpers(lines)
|
|
93
125
|
if uses_string_view?
|
|
94
126
|
lines.concat(emit_string_type)
|
|
95
127
|
lines << ""
|
|
96
128
|
end
|
|
97
|
-
|
|
98
129
|
if uses_vector_math_types?
|
|
99
130
|
lines.concat(emit_vector_math_types)
|
|
100
131
|
lines << ""
|
|
101
132
|
end
|
|
102
|
-
|
|
103
133
|
if uses_fatal_helper?
|
|
104
134
|
lines.concat(emit_fatal_helper)
|
|
105
135
|
lines << ""
|
|
106
136
|
end
|
|
107
|
-
|
|
108
137
|
if uses_format_helpers?
|
|
109
138
|
lines.concat(emit_format_helpers)
|
|
110
139
|
lines << ""
|
|
111
140
|
end
|
|
112
|
-
|
|
113
141
|
if uses_fmt_builder?
|
|
114
142
|
lines.concat(emit_fmt_builder_helpers)
|
|
115
143
|
lines << ""
|
|
116
144
|
end
|
|
117
|
-
|
|
118
145
|
if uses_str_equality_helper?
|
|
119
146
|
lines.concat(emit_str_equality_helper)
|
|
120
147
|
lines << ""
|
|
121
148
|
end
|
|
122
|
-
|
|
123
149
|
if uses_text_buffer_helpers?
|
|
124
150
|
lines.concat(emit_text_buffer_helpers)
|
|
125
151
|
lines << ""
|
|
126
152
|
end
|
|
127
|
-
|
|
128
153
|
if uses_async_memory_helpers?
|
|
129
154
|
lines.concat(emit_async_memory_helpers)
|
|
130
155
|
lines << ""
|
|
131
156
|
end
|
|
132
|
-
|
|
133
157
|
if uses_parallel_for_helper?
|
|
134
158
|
lines.concat(emit_parallel_for_helper)
|
|
135
159
|
lines << ""
|
|
136
160
|
end
|
|
137
|
-
|
|
138
161
|
if uses_spawn_all_helper?
|
|
139
162
|
lines.concat(emit_spawn_all_helper)
|
|
140
163
|
lines << ""
|
|
141
164
|
end
|
|
142
|
-
|
|
143
165
|
if uses_detach_helper?
|
|
144
166
|
lines.concat(emit_detach_helpers)
|
|
145
167
|
lines << ""
|
|
146
168
|
end
|
|
169
|
+
end
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
all_variant_decls,
|
|
153
|
-
)
|
|
171
|
+
def emit_type_declarations(lines)
|
|
172
|
+
all_struct_decls = emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls
|
|
173
|
+
all_variant_decls = emitted_aggregate_variants + collect_generic_variant_decls
|
|
174
|
+
aggregate_decls = sort_aggregate_decls(all_struct_decls, emitted_aggregate_unions, all_variant_decls)
|
|
154
175
|
|
|
155
|
-
forward_declarations = emit_forward_declarations(
|
|
176
|
+
forward_declarations = emit_forward_declarations(@program.opaques, aggregate_decls)
|
|
156
177
|
unless forward_declarations.empty?
|
|
157
178
|
lines.concat(forward_declarations)
|
|
158
179
|
lines << ""
|
|
@@ -222,13 +243,17 @@ module MilkTea
|
|
|
222
243
|
lines.concat(emit_variant_equality_helpers)
|
|
223
244
|
lines << ""
|
|
224
245
|
end
|
|
246
|
+
end
|
|
225
247
|
|
|
248
|
+
def emit_function_forward_declarations(lines)
|
|
226
249
|
function_declarations = emit_function_declarations(emitted_functions)
|
|
227
250
|
unless function_declarations.empty?
|
|
228
251
|
lines.concat(function_declarations)
|
|
229
252
|
lines << ""
|
|
230
253
|
end
|
|
254
|
+
end
|
|
231
255
|
|
|
256
|
+
def emit_globals_and_constants(lines, constants)
|
|
232
257
|
constants.each do |constant|
|
|
233
258
|
@current_line = constant.line if constant.line
|
|
234
259
|
@source_path ||= constant.path if constant.path
|
|
@@ -248,66 +273,50 @@ module MilkTea
|
|
|
248
273
|
lines << emit_static_assert(statement)
|
|
249
274
|
end
|
|
250
275
|
lines << "" unless @program.static_asserts.empty?
|
|
276
|
+
end
|
|
251
277
|
|
|
252
|
-
|
|
253
|
-
|
|
278
|
+
def emit_per_type_helpers(lines)
|
|
279
|
+
collect_reinterpret_helpers.each do |helper|
|
|
254
280
|
lines.concat(emit_reinterpret_helper(helper))
|
|
255
281
|
lines << ""
|
|
256
282
|
end
|
|
257
283
|
|
|
258
|
-
|
|
259
|
-
checked_array_index_types.each do |type|
|
|
284
|
+
collect_checked_array_index_types.each do |type|
|
|
260
285
|
lines.concat(emit_checked_array_index_helper(type))
|
|
261
286
|
lines << ""
|
|
262
287
|
end
|
|
263
288
|
|
|
264
|
-
|
|
265
|
-
checked_span_index_types.each do |type|
|
|
289
|
+
collect_checked_span_index_types.each do |type|
|
|
266
290
|
lines.concat(emit_checked_span_index_helper(type))
|
|
267
291
|
lines << ""
|
|
268
292
|
end
|
|
269
293
|
|
|
270
|
-
|
|
271
|
-
nullable_array_index_types.each do |type|
|
|
294
|
+
collect_checked_array_index_types(nullable_only: true).each do |type|
|
|
272
295
|
lines.concat(emit_nullable_array_index_helper(type))
|
|
273
296
|
lines << ""
|
|
274
297
|
end
|
|
275
298
|
|
|
276
|
-
|
|
277
|
-
nullable_span_index_types.each do |type|
|
|
299
|
+
collect_checked_span_index_types(nullable_only: true).each do |type|
|
|
278
300
|
lines.concat(emit_nullable_span_index_helper(type))
|
|
279
301
|
lines << ""
|
|
280
302
|
end
|
|
303
|
+
end
|
|
281
304
|
|
|
305
|
+
def emit_string_literal_constants_section(lines)
|
|
282
306
|
str_literals = collect_str_literals
|
|
283
|
-
|
|
284
|
-
@str_literal_map = {}
|
|
285
|
-
str_literals.each_with_index { |value, i| @str_literal_map[value] = str_literal_name(i) }
|
|
286
|
-
lines.concat(emit_str_literal_constants(str_literals))
|
|
287
|
-
lines << ""
|
|
288
|
-
end
|
|
307
|
+
return if str_literals.empty?
|
|
289
308
|
|
|
309
|
+
@str_literal_map = {}
|
|
310
|
+
str_literals.each_with_index { |value, i| @str_literal_map[value] = str_literal_name(i) }
|
|
311
|
+
lines.concat(emit_str_literal_constants(str_literals))
|
|
312
|
+
lines << ""
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def emit_function_definitions(lines)
|
|
290
316
|
emitted_functions.each do |function|
|
|
291
317
|
lines.concat(emit_function(function))
|
|
292
318
|
lines << ""
|
|
293
319
|
end
|
|
294
|
-
|
|
295
|
-
lines.join("\n").rstrip + "\n"
|
|
296
320
|
end
|
|
297
|
-
|
|
298
|
-
EQUALITY_OPERATORS = ["==", "!="].freeze
|
|
299
|
-
|
|
300
|
-
include AggregateUtils
|
|
301
|
-
include TypeSystem
|
|
302
|
-
include Reachability
|
|
303
|
-
include FeatureDetection
|
|
304
|
-
include TypeCollectors
|
|
305
|
-
include Statements
|
|
306
|
-
include ControlFlowEmission
|
|
307
|
-
include RuntimeHelpers
|
|
308
|
-
include FormatHelpers
|
|
309
|
-
include TypeDeclaration
|
|
310
|
-
include Expressions
|
|
311
|
-
include Reinterpret
|
|
312
321
|
end
|
|
313
322
|
end
|