wasm shell + destructuring
This commit is contained in:
@@ -842,7 +842,7 @@ pub const Lowering = struct {
|
||||
/// Statement nodes are lowered as statements (returning null).
|
||||
fn tryLowerAsExpr(self: *Lowering, node: *const Node) ?Ref {
|
||||
return switch (node.data) {
|
||||
.var_decl, .const_decl, .fn_decl, .return_stmt, .assignment, .defer_stmt, .push_stmt, .multi_assign => {
|
||||
.var_decl, .const_decl, .fn_decl, .return_stmt, .assignment, .defer_stmt, .push_stmt, .multi_assign, .destructure_decl => {
|
||||
self.lowerStmt(node);
|
||||
return null;
|
||||
},
|
||||
@@ -860,6 +860,7 @@ pub const Lowering = struct {
|
||||
.defer_stmt => |ds| self.lowerDefer(&ds),
|
||||
.push_stmt => |ps| self.lowerPush(&ps),
|
||||
.multi_assign => |ma| self.lowerMultiAssign(&ma),
|
||||
.destructure_decl => |dd| self.lowerDestructureDecl(&dd),
|
||||
.insert_expr => |ins| self.lowerInsertExpr(ins.expr),
|
||||
.block => self.lowerBlock(node),
|
||||
// Block-local type declarations
|
||||
@@ -1492,29 +1493,13 @@ pub const Lowering = struct {
|
||||
const base = if (is_array) (self.getExprAlloca(ie.object) orelse self.lowerExpr(ie.object)) else self.lowerExpr(ie.object);
|
||||
break :blk self.builder.emit(.{ .index_gep = .{ .lhs = base, .rhs = idx } }, ptr_ty);
|
||||
}
|
||||
// address_of(field_access) → emit struct_gep (pointer to field) when object is a pointer
|
||||
// address_of(field_access) → use lowerExprAsPtr for GEP chain
|
||||
// Handles all cases: pointer-based, index-based, nested field access
|
||||
if (uop.op == .address_of and uop.operand.data == .field_access) {
|
||||
const fa = &uop.operand.data.field_access;
|
||||
const obj_ty = self.inferExprType(fa.object);
|
||||
if (!obj_ty.isBuiltin()) {
|
||||
const ptr_info = self.module.types.get(obj_ty);
|
||||
if (ptr_info == .pointer) {
|
||||
const pointee = ptr_info.pointer.pointee;
|
||||
if (!pointee.isBuiltin()) {
|
||||
const struct_info = self.module.types.get(pointee);
|
||||
if (struct_info == .@"struct") {
|
||||
const field_name_id = self.module.types.internString(fa.field);
|
||||
for (struct_info.@"struct".fields, 0..) |f, fi| {
|
||||
if (f.name == field_name_id) {
|
||||
const obj = self.lowerExpr(fa.object);
|
||||
const field_ptr_ty = self.module.types.ptrTo(f.ty);
|
||||
break :blk self.builder.structGepTyped(obj, @intCast(fi), field_ptr_ty, pointee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const inner_ty = self.inferExprType(uop.operand);
|
||||
const ptr_ty = self.module.types.ptrTo(inner_ty);
|
||||
const ptr = self.lowerExprAsPtr(uop.operand);
|
||||
break :blk self.builder.emit(.{ .addr_of = .{ .operand = ptr } }, ptr_ty);
|
||||
}
|
||||
// address_of(identifier) → return alloca directly (pointer to variable)
|
||||
if (uop.op == .address_of and uop.operand.data == .identifier) {
|
||||
@@ -1527,6 +1512,11 @@ pub const Lowering = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
// address_of(global) → emit global_addr (pointer to global, not load)
|
||||
if (self.global_names.get(id_name)) |gi| {
|
||||
const ptr_ty = self.module.types.ptrTo(gi.ty);
|
||||
break :blk self.builder.emit(.{ .global_addr = gi.id }, ptr_ty);
|
||||
}
|
||||
}
|
||||
const operand = self.lowerExpr(uop.operand);
|
||||
break :blk switch (uop.op) {
|
||||
@@ -4528,6 +4518,12 @@ pub const Lowering = struct {
|
||||
self.collectCaptures(a.target, param_names, captures);
|
||||
self.collectCaptures(a.value, param_names, captures);
|
||||
},
|
||||
.destructure_decl => |dd| {
|
||||
self.collectCaptures(dd.value, param_names, captures);
|
||||
for (dd.names) |name| {
|
||||
param_names.put(name, {}) catch {};
|
||||
}
|
||||
},
|
||||
.field_access => |fa| {
|
||||
self.collectCaptures(fa.object, param_names, captures);
|
||||
},
|
||||
@@ -4813,6 +4809,38 @@ pub const Lowering = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerDestructureDecl(self: *Lowering, dd: *const ast.DestructureDecl) void {
|
||||
// Lower the RHS expression (must produce a tuple)
|
||||
const saved_fbv = self.force_block_value;
|
||||
self.force_block_value = true;
|
||||
const ref = self.lowerExpr(dd.value);
|
||||
self.force_block_value = saved_fbv;
|
||||
const ty = self.builder.getRefType(ref);
|
||||
|
||||
// Get tuple field info
|
||||
if (ty.isBuiltin()) return;
|
||||
const ti = self.module.types.get(ty);
|
||||
if (ti != .tuple) return;
|
||||
const tuple = ti.tuple;
|
||||
if (dd.names.len > tuple.fields.len) return;
|
||||
|
||||
// Extract each field and bind to a new variable
|
||||
for (dd.names, 0..) |name, i| {
|
||||
if (std.mem.eql(u8, name, "_")) continue; // discard
|
||||
const field_ty = tuple.fields[i];
|
||||
const field_val = self.builder.emit(.{ .tuple_get = .{
|
||||
.base = ref,
|
||||
.field_index = @intCast(i),
|
||||
.base_type = ty,
|
||||
} }, field_ty);
|
||||
const slot = self.builder.alloca(field_ty);
|
||||
self.builder.store(slot, field_val);
|
||||
if (self.scope) |scope| {
|
||||
scope.put(name, .{ .ref = slot, .ty = field_ty, .is_alloca = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Comptime lowering ────────────────────────────────────────────
|
||||
|
||||
/// Lower a `#run expr` that appears as a top-level constant binding:
|
||||
@@ -7767,7 +7795,7 @@ pub const Lowering = struct {
|
||||
.chained_comparison => .bool,
|
||||
// Statements don't produce values
|
||||
.assignment, .var_decl, .const_decl, .fn_decl, .return_stmt,
|
||||
.defer_stmt, .push_stmt, .multi_assign,
|
||||
.defer_stmt, .push_stmt, .multi_assign, .destructure_decl,
|
||||
=> .void,
|
||||
else => .s64,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user