multiple assign
This commit is contained in:
@@ -2447,6 +2447,9 @@ pub const CodeGen = struct {
|
||||
.assignment => |asgn| {
|
||||
return self.genAssignment(asgn);
|
||||
},
|
||||
.multi_assign => |ma| {
|
||||
return self.genMultiAssign(ma);
|
||||
},
|
||||
.return_stmt => |rs| {
|
||||
// Evaluate return value first, then emit all defers, then return
|
||||
if (rs.value) |val_node| {
|
||||
@@ -2945,6 +2948,65 @@ pub const CodeGen = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn genMultiAssign(self: *CodeGen, ma: ast.MultiAssign) !c.LLVMValueRef {
|
||||
const n = ma.targets.len;
|
||||
|
||||
// Phase 1: Evaluate ALL RHS values into temporaries.
|
||||
// This ensures correctness for aliased swaps (a, b = b, a).
|
||||
const tmp_ptrs = try self.allocator.alloc(c.LLVMValueRef, n);
|
||||
const target_types = try self.allocator.alloc(Type, n);
|
||||
|
||||
for (0..n) |i| {
|
||||
target_types[i] = self.inferType(ma.targets[i]);
|
||||
const llvm_ty = self.typeToLLVM(target_types[i]);
|
||||
const val = try self.genExprAsType(ma.values[i], target_types[i]);
|
||||
const tmp = self.buildEntryBlockAlloca(llvm_ty, "swap_tmp");
|
||||
_ = c.LLVMBuildStore(self.builder, val, tmp);
|
||||
tmp_ptrs[i] = tmp;
|
||||
}
|
||||
|
||||
// Phase 2: Load temporaries and store to each target.
|
||||
for (0..n) |i| {
|
||||
const llvm_ty = self.typeToLLVM(target_types[i]);
|
||||
const val = c.LLVMBuildLoad2(self.builder, llvm_ty, tmp_ptrs[i], "swap_load");
|
||||
try self.storeToLvalue(ma.targets[i], val);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn storeToLvalue(self: *CodeGen, target: *Node, val: c.LLVMValueRef) !void {
|
||||
// Deref assignment: p.* = val
|
||||
if (target.data == .deref_expr) {
|
||||
const de = target.data.deref_expr;
|
||||
const ptr_val = try self.genExpr(de.operand);
|
||||
_ = c.LLVMBuildStore(self.builder, val, ptr_val);
|
||||
return;
|
||||
}
|
||||
|
||||
// Identifier assignment: x = val (with const check)
|
||||
if (target.data == .identifier) {
|
||||
const name = target.data.identifier.name;
|
||||
const lookup = self.lookupValue(name) orelse
|
||||
return self.emitErrorFmt("undefined variable '{s}'", .{name});
|
||||
const entry = lookup.asNamedValue() orelse
|
||||
return self.emitErrorFmt("cannot assign to constant '{s}'", .{name});
|
||||
if (entry.is_const)
|
||||
return self.emitErrorFmt("cannot assign to '{s}'", .{name});
|
||||
_ = c.LLVMBuildStore(self.builder, val, entry.ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Field access and index expressions — use genAddressOf to get the target pointer
|
||||
if (target.data == .field_access or target.data == .index_expr) {
|
||||
const ptr = try self.genAddressOf(target);
|
||||
_ = c.LLVMBuildStore(self.builder, val, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
return self.emitError("multi-assign target must be a variable, field, index, or dereference expression");
|
||||
}
|
||||
|
||||
fn genFieldAssignment(self: *CodeGen, asgn: ast.Assignment) !c.LLVMValueRef {
|
||||
const fa = asgn.target.data.field_access;
|
||||
|
||||
@@ -3276,6 +3338,9 @@ pub const CodeGen = struct {
|
||||
.assignment => |asgn| {
|
||||
return self.genAssignment(asgn);
|
||||
},
|
||||
.multi_assign => |ma| {
|
||||
return self.genMultiAssign(ma);
|
||||
},
|
||||
.return_stmt => |rs| {
|
||||
if (rs.value) |val_node| {
|
||||
const raw_val = try self.genExpr(val_node);
|
||||
|
||||
Reference in New Issue
Block a user