mt-lang 0.2.19 → 0.2.21
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/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/lowering/async/lowering.rb +10 -2
- data/lib/milk_tea/core/lowering/block.rb +10 -2
- data/lib/milk_tea/core/lowering/declarations.rb +5 -1
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +2 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +15 -0
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +73 -9
- 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: e599b2192dada4fb02cbcefc522482028adce79482a53965f2715895ced1c744
|
|
4
|
+
data.tar.gz: 2a4b8540ee7050b98707aee9cdd15b6f18504c8f401f9590c03720a49d88de78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a308513fd5d5aac4ab32c9707b1bb066851b103b4c3ff9521e880f0bdaf7501968329da6fa6a98487077f532189b0931bb4e715e2a495f359e383320ecc1b212
|
|
7
|
+
data.tar.gz: d6f99733d6bc1be8eff2d4002b7b2e7d8aa8b1b6a48fe7ca26631a0ffc3780bafadcee2003c73afa473c457d59c736845d3e34f96e0a13ea1b3a48920b294b2c
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -1074,7 +1074,15 @@ module MilkTea
|
|
|
1074
1074
|
lower_expression(prepared_value, env:, expected_type: target.type)
|
|
1075
1075
|
end
|
|
1076
1076
|
update_cstr_metadata_for_assignment!(statement, prepared_value, env)
|
|
1077
|
-
|
|
1077
|
+
operator = statement.operator
|
|
1078
|
+
if ["+=", "-=", "*=", "/="].include?(operator) &&
|
|
1079
|
+
(target.type.is_a?(Types::Vector) || target.type.is_a?(Types::Matrix) || target.type.is_a?(Types::Quaternion))
|
|
1080
|
+
binary_op = operator[0...-1]
|
|
1081
|
+
expanded = lower_vector_binary_op(binary_op, target, target.type, value, value.type, target.type)
|
|
1082
|
+
value = expanded || IR::Binary.new(operator: binary_op, left: target, right: value, type: target.type)
|
|
1083
|
+
operator = "="
|
|
1084
|
+
end
|
|
1085
|
+
if operator == "=" && contains_proc_storage_type?(target.type)
|
|
1078
1086
|
rhs_name = fresh_c_temp_name(env, "proc_assign")
|
|
1079
1087
|
lowered << IR::LocalDecl.new(name: rhs_name, linkage_name: rhs_name, type: target.type, value:)
|
|
1080
1088
|
rhs = IR::Name.new(name: rhs_name, type: target.type, pointer: false)
|
|
@@ -1082,7 +1090,7 @@ module MilkTea
|
|
|
1082
1090
|
lowered.concat(lower_proc_contained_guarded_release_statements(target, target.type))
|
|
1083
1091
|
lowered << IR::Assignment.new(target:, operator: "=", value: rhs)
|
|
1084
1092
|
else
|
|
1085
|
-
lowered << IR::Assignment.new(target:, operator
|
|
1093
|
+
lowered << IR::Assignment.new(target:, operator:, value:)
|
|
1086
1094
|
end
|
|
1087
1095
|
lowered
|
|
1088
1096
|
end
|
|
@@ -211,7 +211,15 @@ module MilkTea
|
|
|
211
211
|
end
|
|
212
212
|
update_cstr_metadata_for_assignment!(statement, prepared_value, local_env)
|
|
213
213
|
local_defers.concat(suppress_format_releases_for_assignment(prepared_cleanups, target.type))
|
|
214
|
-
|
|
214
|
+
operator = statement.operator
|
|
215
|
+
if ["+=", "-=", "*=", "/="].include?(operator) &&
|
|
216
|
+
(target.type.is_a?(Types::Vector) || target.type.is_a?(Types::Matrix) || target.type.is_a?(Types::Quaternion))
|
|
217
|
+
binary_op = operator[0...-1]
|
|
218
|
+
expanded = lower_vector_binary_op(binary_op, target, target.type, value, value.type, target.type)
|
|
219
|
+
value = expanded || IR::Binary.new(operator: binary_op, left: target, right: value, type: target.type)
|
|
220
|
+
operator = "="
|
|
221
|
+
end
|
|
222
|
+
if operator == "=" && contains_proc_storage_type?(target.type)
|
|
215
223
|
# Materialize the RHS to a C temp to avoid evaluating aggregate literals multiple times
|
|
216
224
|
# and to ensure retain/release operate on a stable struct value throughout the sequence.
|
|
217
225
|
rhs_name = fresh_c_temp_name(local_env, "proc_assign")
|
|
@@ -224,7 +232,7 @@ module MilkTea
|
|
|
224
232
|
lowered.concat(lower_proc_contained_guarded_release_statements(target, target.type))
|
|
225
233
|
lowered << IR::Assignment.new(target:, operator: "=", value: rhs)
|
|
226
234
|
else
|
|
227
|
-
lowered << IR::Assignment.new(target:, operator
|
|
235
|
+
lowered << IR::Assignment.new(target:, operator:, value:)
|
|
228
236
|
end
|
|
229
237
|
when AST::IfStmt
|
|
230
238
|
if statement.inline
|
|
@@ -176,7 +176,11 @@ module MilkTea
|
|
|
176
176
|
enum_type = @ctx.types.fetch(decl.name)
|
|
177
177
|
backing_type = enum_type.backing_type
|
|
178
178
|
members = decl.members.map do |member|
|
|
179
|
-
value =
|
|
179
|
+
value = if member.value
|
|
180
|
+
lower_expression(member.value, env: empty_env, expected_type: backing_type)
|
|
181
|
+
else
|
|
182
|
+
IR::IntegerLiteral.new(value: enum_type.member_value(member.name), type: backing_type)
|
|
183
|
+
end
|
|
180
184
|
IR::EnumMember.new(name: member.name, linkage_name: enum_member_c_name(enum_type, member.name), value:)
|
|
181
185
|
end
|
|
182
186
|
|
|
@@ -260,6 +260,8 @@ module MilkTea
|
|
|
260
260
|
end
|
|
261
261
|
when IR::ArrayLiteral
|
|
262
262
|
"#{expression.type}(#{expression.elements.map { |element| render_expression(element) }.join(', ')})"
|
|
263
|
+
when IR::Assignment
|
|
264
|
+
"#{render_expression(expression.target)} #{expression.operator} #{render_expression(expression.value)}"
|
|
263
265
|
else
|
|
264
266
|
raise ArgumentError, "unsupported IR expression #{expression.class.name}"
|
|
265
267
|
end
|
|
@@ -450,6 +450,21 @@ module MilkTea
|
|
|
450
450
|
raise_sema_error("safe array indexing requires an addressable array value; bind it to a local first")
|
|
451
451
|
end
|
|
452
452
|
|
|
453
|
+
if array_type?(receiver_type) && expression.index.is_a?(AST::IntegerLiteral)
|
|
454
|
+
length = array_length(receiver_type)
|
|
455
|
+
index_val = expression.index.value
|
|
456
|
+
if index_val >= length || index_val < 0
|
|
457
|
+
raise_sema_error("array index #{index_val} is out of bounds for array[T, #{length}]", expression)
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
if array_type?(receiver_type) && expression.index.is_a?(AST::UnaryOp) && expression.index.operator == "-" &&
|
|
462
|
+
expression.index.operand.is_a?(AST::IntegerLiteral)
|
|
463
|
+
length = array_length(receiver_type)
|
|
464
|
+
index_val = -expression.index.operand.value
|
|
465
|
+
raise_sema_error("array index #{index_val} is out of bounds for array[T, #{length}]", expression)
|
|
466
|
+
end
|
|
467
|
+
|
|
453
468
|
infer_index_result_type(receiver_type, index_type)
|
|
454
469
|
end
|
|
455
470
|
|
|
@@ -185,6 +185,7 @@ module MilkTea
|
|
|
185
185
|
|
|
186
186
|
validate_consuming_foreign_expression!(statement.value, scopes:, root_allowed: false) if statement.value
|
|
187
187
|
value_type = statement.value ? infer_expression(statement.value, scopes:, expected_type: return_type) : @ctx.types.fetch("void")
|
|
188
|
+
check_stack_pointer_escape_in_return(statement.value, scopes:) if statement.value
|
|
188
189
|
ensure_assignable!(
|
|
189
190
|
value_type,
|
|
190
191
|
return_type,
|
|
@@ -494,16 +495,21 @@ module MilkTea
|
|
|
494
495
|
line: statement.line, column: statement.column,
|
|
495
496
|
)
|
|
496
497
|
when "+=", "-=", "*=", "/="
|
|
497
|
-
|
|
498
|
+
binary_op = statement.operator[0...-1]
|
|
499
|
+
if (result_type = vector_arithmetic_result(binary_op, target_type, value_type))
|
|
500
|
+
raise_sema_error("operator #{statement.operator} on #{target_type} and #{value_type} produces #{result_type}, expected #{target_type}") unless result_type == target_type
|
|
501
|
+
else
|
|
502
|
+
raise_sema_error("operator #{statement.operator} requires matching numeric types, got #{target_type} and #{value_type}") unless target_type.numeric? && value_type.numeric?
|
|
498
503
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
504
|
+
ensure_assignable!(
|
|
505
|
+
value_type,
|
|
506
|
+
target_type,
|
|
507
|
+
"operator #{statement.operator} requires matching numeric types, got #{target_type} and #{value_type}",
|
|
508
|
+
expression: statement.value,
|
|
509
|
+
contextual_int_to_float: contextual_int_to_float_target?(target_type),
|
|
510
|
+
line: statement.line, column: statement.column,
|
|
511
|
+
)
|
|
512
|
+
end
|
|
507
513
|
when "%="
|
|
508
514
|
unless common_integer_type(target_type, value_type) == target_type
|
|
509
515
|
raise_sema_error("operator #{statement.operator} requires compatible integer types, got #{target_type} and #{value_type}")
|
|
@@ -1322,6 +1328,64 @@ module MilkTea
|
|
|
1322
1328
|
end
|
|
1323
1329
|
end
|
|
1324
1330
|
|
|
1331
|
+
# Walks the returned expression tree to detect ptr_of/ref_of/const_ptr_of
|
|
1332
|
+
# applied to a stack-local variable whose address must not escape the
|
|
1333
|
+
# function. Only flags when the pointer value itself (not a computed
|
|
1334
|
+
# result through a function call) reaches the return.
|
|
1335
|
+
def check_stack_pointer_escape_in_return(expression, scopes:)
|
|
1336
|
+
return unless expression
|
|
1337
|
+
|
|
1338
|
+
if expression.is_a?(AST::Call)
|
|
1339
|
+
check_stack_escape_call(expression, scopes:)
|
|
1340
|
+
elsif expression.is_a?(AST::BinaryOp)
|
|
1341
|
+
check_stack_pointer_escape_in_return(expression.left, scopes:)
|
|
1342
|
+
check_stack_pointer_escape_in_return(expression.right, scopes:)
|
|
1343
|
+
elsif expression.is_a?(AST::UnaryOp)
|
|
1344
|
+
check_stack_pointer_escape_in_return(expression.operand, scopes:)
|
|
1345
|
+
end
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
def check_stack_escape_call(expression, scopes:)
|
|
1349
|
+
callee = expression.callee
|
|
1350
|
+
return unless callee.is_a?(AST::Identifier)
|
|
1351
|
+
return unless %w[ptr_of ref_of const_ptr_of].include?(callee.name)
|
|
1352
|
+
return if expression.arguments.empty?
|
|
1353
|
+
|
|
1354
|
+
arg = expression.arguments.first
|
|
1355
|
+
source = arg.respond_to?(:value) ? arg.value : arg
|
|
1356
|
+
check_stack_local_source(source, scopes:, builtin: callee.name)
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
def check_stack_local_source(expression, scopes:, builtin:)
|
|
1360
|
+
case expression
|
|
1361
|
+
when AST::Identifier
|
|
1362
|
+
binding = lookup_local_binding(expression.name, scopes)
|
|
1363
|
+
return unless binding
|
|
1364
|
+
return unless %i[let var param].include?(binding.kind)
|
|
1365
|
+
return if stack_safe_pointer_source?(binding)
|
|
1366
|
+
raise_sema_error(
|
|
1367
|
+
"#{builtin}(#{expression.name}) cannot be returned: pointer to function-local storage",
|
|
1368
|
+
expression,
|
|
1369
|
+
)
|
|
1370
|
+
when AST::MemberAccess
|
|
1371
|
+
check_stack_local_source(expression.receiver, scopes:, builtin:)
|
|
1372
|
+
when AST::IndexAccess
|
|
1373
|
+
check_stack_local_source(expression.receiver, scopes:, builtin:)
|
|
1374
|
+
end
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
def lookup_local_binding(name, scopes)
|
|
1378
|
+
scopes.reverse_each do |scope|
|
|
1379
|
+
return scope[name] if scope.key?(name)
|
|
1380
|
+
end
|
|
1381
|
+
nil
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1384
|
+
def stack_safe_pointer_source?(binding)
|
|
1385
|
+
return false unless binding.type
|
|
1386
|
+
ref_type?(binding.type) || own_type?(binding.type) || (binding.mutable && binding.kind == :param)
|
|
1387
|
+
end
|
|
1388
|
+
|
|
1325
1389
|
end
|
|
1326
1390
|
end
|
|
1327
1391
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mt-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -586,7 +586,7 @@ metadata:
|
|
|
586
586
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
587
587
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
588
588
|
post_install_message: |
|
|
589
|
-
Milk Tea 0.2.
|
|
589
|
+
Milk Tea 0.2.21 installed!
|
|
590
590
|
|
|
591
591
|
System requirements:
|
|
592
592
|
- A C compiler (gcc or clang) must be available on PATH
|