...
This commit is contained in:
@@ -1051,5 +1051,60 @@ END;
|
||||
// Symbol rename: c_abs maps to C's abs()
|
||||
print("foreign-rename: {}\n", c_abs(xx -42));
|
||||
|
||||
// ========================================================
|
||||
// 16. COMPOUND ASSIGNMENT TYPE CONVERSION
|
||||
// ========================================================
|
||||
print("=== 16. Compound Assign ===\n");
|
||||
{
|
||||
ca_a : f64 = 10.0;
|
||||
ca_b : f32 = 3.0;
|
||||
ca_a += ca_b;
|
||||
print("f64+=f32: {}\n", ca_a);
|
||||
|
||||
ca_c : s64 = 100;
|
||||
ca_d : s32 = 7;
|
||||
ca_c -= ca_d;
|
||||
print("s64-=s32: {}\n", ca_c);
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
// 17. SLICE/ARRAY .ptr ACCESS
|
||||
// ========================================================
|
||||
print("=== 17. Slice Ptr ===\n");
|
||||
{
|
||||
sarr : [5]s32 = .[10, 20, 30, 40, 50];
|
||||
ssl := sarr[1..4];
|
||||
sp := ssl.ptr;
|
||||
print("sl-ptr[0]: {}\n", sp[0]);
|
||||
print("sl-ptr[1]: {}\n", sp[1]);
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
// 18. ARRAYS OF USER-DEFINED TYPES
|
||||
// ========================================================
|
||||
print("=== 18. Array of Structs ===\n");
|
||||
{
|
||||
spts : [2]Point = .[Point.{1, 2}, Point.{3, 4}];
|
||||
spt2 := spts[1];
|
||||
print("arr-struct-x: {}\n", spt2.x);
|
||||
for spts: (it) {
|
||||
print("for-struct: {}\n", it);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
// 19. LOCAL FUNCTION RETURNING STRUCT/ENUM
|
||||
// ========================================================
|
||||
print("=== 19. Local Fn Return ===\n");
|
||||
{
|
||||
local_pt :: () -> Point { Point.{42, 99}; }
|
||||
lp := local_pt();
|
||||
print("local-struct: {} {}\n", lp.x, lp.y);
|
||||
|
||||
local_sh :: () -> Shape { .circle(2.5); }
|
||||
ls := local_sh();
|
||||
print("local-enum: {}\n", ls);
|
||||
}
|
||||
|
||||
print("=== DONE ===\n");
|
||||
}
|
||||
|
||||
115
src/codegen.zig
115
src/codegen.zig
@@ -480,7 +480,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
|
||||
fn resolveElementType(self: *CodeGen, name: []const u8, comptime kind: []const u8) !Type {
|
||||
return Type.fromName(name) orelse
|
||||
return self.resolveTypeFromName(name) orelse
|
||||
return self.emitErrorFmt("unknown " ++ kind ++ " element type '{s}'", .{name});
|
||||
}
|
||||
|
||||
@@ -557,11 +557,11 @@ pub const CodeGen = struct {
|
||||
.struct_type => |name| if (self.lookupStructInfo(name)) |info| info.llvm_type else unreachable,
|
||||
.union_type => |name| if (self.lookupTaggedEnumInfo(name)) |info| info.llvm_type else if (self.lookupUnionInfo(name)) |info| info.llvm_type else unreachable,
|
||||
.array_type => |info| {
|
||||
const elem_ty = Type.fromName(info.element_name) orelse unreachable;
|
||||
const elem_ty = self.resolveTypeFromName(info.element_name) orelse unreachable;
|
||||
return c.LLVMArrayType2(self.typeToLLVM(elem_ty), info.length);
|
||||
},
|
||||
.vector_type => |info| {
|
||||
const elem_ty = Type.fromName(info.element_name) orelse unreachable;
|
||||
const elem_ty = self.resolveTypeFromName(info.element_name) orelse unreachable;
|
||||
return c.LLVMVectorType(self.typeToLLVM(elem_ty), info.length);
|
||||
},
|
||||
.pointer_type, .many_pointer_type, .function_type => self.ptrType(),
|
||||
@@ -2381,9 +2381,8 @@ pub const CodeGen = struct {
|
||||
|
||||
const ret_val = try self.genExpr(lambda.body);
|
||||
if (ret_val) |val| {
|
||||
const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val));
|
||||
const converted = self.convertValue(val, src_ty, ret_sx_type);
|
||||
self.ret(converted);
|
||||
const prepared = try self.prepareReturnValue(val, ret_sx_type);
|
||||
self.ret(prepared);
|
||||
} else {
|
||||
self.retVoid();
|
||||
}
|
||||
@@ -2461,9 +2460,8 @@ pub const CodeGen = struct {
|
||||
if (ret_sx_type == .void_type) {
|
||||
self.retVoid();
|
||||
} else if (last_val) |val| {
|
||||
const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val));
|
||||
const converted = self.convertValue(val, src_ty, ret_sx_type);
|
||||
self.ret(converted);
|
||||
const ret_val = try self.prepareReturnValue(val, ret_sx_type);
|
||||
self.ret(ret_val);
|
||||
} else {
|
||||
self.retVoid();
|
||||
}
|
||||
@@ -2977,7 +2975,7 @@ pub const CodeGen = struct {
|
||||
// C-style union: full assignment not supported, use field assignment
|
||||
}
|
||||
|
||||
const new_val = try self.genExpr(asgn.value);
|
||||
const new_val = try self.genExprAsType(asgn.value, entry.ty);
|
||||
const llvm_ty = self.typeToLLVM(entry.ty);
|
||||
|
||||
const store_val = if (asgn.op == .assign) new_val else blk: {
|
||||
@@ -3150,7 +3148,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
const slice_info = obj_ty.slice_type;
|
||||
const elem_ty = Type.fromName(slice_info.element_name) orelse return self.emitError("unknown slice element type");
|
||||
const elem_ty = self.resolveTypeFromName(slice_info.element_name) orelse return self.emitError("unknown slice element type");
|
||||
const elem_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
// Load slice value to get ptr
|
||||
const slice_val = blk: {
|
||||
@@ -3558,25 +3556,22 @@ pub const CodeGen = struct {
|
||||
fn hoistInlineTypeDecl(self: *CodeGen, parent_name: []const u8, child_name: []const u8, type_node: *Node) anyerror!void {
|
||||
const synthetic_name = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ parent_name, child_name });
|
||||
switch (type_node.data) {
|
||||
.struct_decl => |inline_sd| {
|
||||
var hoisted = inline_sd;
|
||||
hoisted.name = synthetic_name;
|
||||
try self.registerStructType(hoisted);
|
||||
.struct_decl => |*sd| {
|
||||
sd.name = synthetic_name;
|
||||
try self.registerStructType(sd.*);
|
||||
},
|
||||
.union_decl => |inline_ud| {
|
||||
var hoisted_ud = inline_ud;
|
||||
hoisted_ud.name = synthetic_name;
|
||||
try self.registerUnionType(hoisted_ud);
|
||||
.union_decl => |*ud| {
|
||||
ud.name = synthetic_name;
|
||||
try self.registerUnionType(ud.*);
|
||||
},
|
||||
.enum_decl => |inline_ed| {
|
||||
if (inline_ed.variant_types.len > 0) {
|
||||
var hoisted = inline_ed;
|
||||
hoisted.name = synthetic_name;
|
||||
try self.registerTaggedEnum(hoisted);
|
||||
.enum_decl => |*ed| {
|
||||
ed.name = synthetic_name;
|
||||
if (ed.variant_types.len > 0) {
|
||||
try self.registerTaggedEnum(ed.*);
|
||||
} else {
|
||||
try self.type_registry.put(synthetic_name, .{ .plain_enum = inline_ed.variant_names });
|
||||
try self.type_registry.put(synthetic_name, .{ .plain_enum = ed.variant_names });
|
||||
_ = try self.getAnyTypeId(synthetic_name, .{ .enum_type = synthetic_name });
|
||||
if (inline_ed.backing_type) |bt_node| {
|
||||
if (ed.backing_type) |bt_node| {
|
||||
const bt = self.resolveType(bt_node);
|
||||
try self.enum_backing_types.put(synthetic_name, self.typeToLLVM(bt));
|
||||
}
|
||||
@@ -3783,7 +3778,7 @@ pub const CodeGen = struct {
|
||||
// Validate payload is an array type
|
||||
const payload_size = switch (payload_ty) {
|
||||
.array_type => |info| blk: {
|
||||
const elem_ty = Type.fromName(info.element_name) orelse {
|
||||
const elem_ty = self.resolveTypeFromName(info.element_name) orelse {
|
||||
return self.emitErrorFmt(
|
||||
"enum '{s}': layout field 'payload' has unresolved element type '{s}'",
|
||||
.{ enum_name, info.element_name },
|
||||
@@ -4623,7 +4618,7 @@ pub const CodeGen = struct {
|
||||
// Vector: extractelement + box as Any
|
||||
if (val_ty.isVector()) {
|
||||
const info = val_ty.vector_type;
|
||||
const elem_ty = Type.fromName(info.element_name) orelse
|
||||
const elem_ty = self.resolveTypeFromName(info.element_name) orelse
|
||||
return self.emitErrorFmt("unknown vector element type '{s}'", .{info.element_name});
|
||||
const idx = try self.genExpr(call_node.args[1]);
|
||||
const elem = c.LLVMBuildExtractElement(self.builder, val, idx, "vec_elem");
|
||||
@@ -4685,7 +4680,7 @@ pub const CodeGen = struct {
|
||||
// Slice: extract ptr, GEP to element, load, box as Any
|
||||
if (val_ty.isSlice()) {
|
||||
const sinfo = val_ty.slice_type;
|
||||
const elem_ty = Type.fromName(sinfo.element_name) orelse
|
||||
const elem_ty = self.resolveTypeFromName(sinfo.element_name) orelse
|
||||
return self.emitErrorFmt("unknown slice element type '{s}'", .{sinfo.element_name});
|
||||
const elem_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
// val is {ptr, i32} — extract ptr
|
||||
@@ -4699,7 +4694,7 @@ pub const CodeGen = struct {
|
||||
// Array: GEP + load + box as Any
|
||||
if (val_ty.isArray()) {
|
||||
const ainfo = val_ty.array_type;
|
||||
const elem_ty = Type.fromName(ainfo.element_name) orelse
|
||||
const elem_ty = self.resolveTypeFromName(ainfo.element_name) orelse
|
||||
return self.emitErrorFmt("unknown array element type '{s}'", .{ainfo.element_name});
|
||||
const arr_llvm_ty = self.typeToLLVM(val_ty);
|
||||
const elem_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
@@ -5215,7 +5210,7 @@ pub const CodeGen = struct {
|
||||
const elem_llvm_ty = if (obj_ty == .string_type)
|
||||
self.i8Type()
|
||||
else
|
||||
self.typeToLLVM(Type.fromName(obj_ty.slice_type.element_name) orelse return self.emitError("unknown slice element type"));
|
||||
self.typeToLLVM(self.resolveTypeFromName(obj_ty.slice_type.element_name) orelse return self.emitError("unknown slice element type"));
|
||||
const new_ptr = self.gepPointerElement(elem_llvm_ty, base_ptr, start_val, "sslice_off");
|
||||
// len = end - start
|
||||
const len_val = c.LLVMBuildSub(self.builder, end_val, start_val, "sslice_len");
|
||||
@@ -5803,9 +5798,9 @@ pub const CodeGen = struct {
|
||||
if (i < call_node.args.len) {
|
||||
const arg_ty = self.inferType(call_node.args[i]);
|
||||
const elem_ty = if (arg_ty.isArray())
|
||||
Type.fromName(arg_ty.array_type.element_name) orelse arg_ty
|
||||
self.resolveTypeFromName(arg_ty.array_type.element_name) orelse arg_ty
|
||||
else if (arg_ty.isSlice())
|
||||
Type.fromName(arg_ty.slice_type.element_name) orelse arg_ty
|
||||
self.resolveTypeFromName(arg_ty.slice_type.element_name) orelse arg_ty
|
||||
else
|
||||
arg_ty;
|
||||
if (bindings.get(type_name)) |existing| {
|
||||
@@ -6036,9 +6031,9 @@ pub const CodeGen = struct {
|
||||
if (std.mem.eql(u8, tp.name, tp_name)) {
|
||||
// Extract element type from concrete slice type
|
||||
const elem_ty = if (sx_type.isSlice())
|
||||
Type.fromName(sx_type.slice_type.element_name) orelse sx_type
|
||||
self.resolveTypeFromName(sx_type.slice_type.element_name) orelse sx_type
|
||||
else if (sx_type.isArray())
|
||||
Type.fromName(sx_type.array_type.element_name) orelse sx_type
|
||||
self.resolveTypeFromName(sx_type.array_type.element_name) orelse sx_type
|
||||
else
|
||||
sx_type;
|
||||
try bindings.put(tp.name, elem_ty);
|
||||
@@ -6291,16 +6286,8 @@ pub const CodeGen = struct {
|
||||
if (ret_sx_type == .void_type) {
|
||||
self.retVoid();
|
||||
} else if (last_val) |val| {
|
||||
if (ret_sx_type.isStruct()) {
|
||||
const sname = ret_sx_type.struct_type;
|
||||
const info = try self.getStructInfo(sname);
|
||||
const loaded = c.LLVMBuildLoad2(self.builder, info.llvm_type, val, "retval");
|
||||
self.ret(loaded);
|
||||
} else {
|
||||
const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val));
|
||||
const converted = self.convertValue(val, src_ty, ret_sx_type);
|
||||
self.ret(converted);
|
||||
}
|
||||
const ret_val = try self.prepareReturnValue(val, ret_sx_type);
|
||||
self.ret(ret_val);
|
||||
} else {
|
||||
_ = c.LLVMBuildUnreachable(self.builder);
|
||||
}
|
||||
@@ -6427,7 +6414,7 @@ pub const CodeGen = struct {
|
||||
if (iter_ty.isSlice()) {
|
||||
is_slice = true;
|
||||
const info = iter_ty.slice_type;
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(64);
|
||||
elem_ty = self.resolveTypeFromName(info.element_name) orelse Type.s(64);
|
||||
// Load slice value from alloca
|
||||
if (for_expr.iterable.data == .identifier) {
|
||||
if (self.named_values.get(for_expr.iterable.data.identifier.name)) |entry| {
|
||||
@@ -6438,7 +6425,7 @@ pub const CodeGen = struct {
|
||||
} else return self.emitError("for: slice iterable must be a variable");
|
||||
} else if (iter_ty.isArray()) {
|
||||
const info = iter_ty.array_type;
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(64);
|
||||
elem_ty = self.resolveTypeFromName(info.element_name) orelse Type.s(64);
|
||||
len_val = c.LLVMConstInt(i64_type, info.length, 0);
|
||||
// Get pointer to array
|
||||
if (for_expr.iterable.data == .identifier) {
|
||||
@@ -6571,12 +6558,23 @@ pub const CodeGen = struct {
|
||||
if (subject_ty.isUnion()) union_name = subject_ty.union_type;
|
||||
|
||||
// Get the switch value: for unions, load the tag from field 0; for enums, use the value directly
|
||||
// Get the switch value: for unions, load the tag from field 0; for enums, use the value directly
|
||||
// For union subjects, we need a pointer for both tag loading and payload capture.
|
||||
// If the subject is a simple identifier, use its existing alloca; otherwise generate
|
||||
// the expression and spill into a temporary alloca.
|
||||
var union_subject_ptr: c.LLVMValueRef = null;
|
||||
const subject_val: c.LLVMValueRef = if (union_name != null) blk: {
|
||||
// Union: load tag from field 0 of the alloca
|
||||
const entry = self.named_values.get(match.subject.data.identifier.name).?;
|
||||
const info = self.lookupTaggedEnumInfo(union_name.?).?;
|
||||
break :blk self.loadStructField(info.llvm_type, entry.ptr, 0, self.getEnumLLVMType(union_name.?));
|
||||
if (match.subject.data == .identifier) {
|
||||
const entry = self.named_values.get(match.subject.data.identifier.name).?;
|
||||
union_subject_ptr = entry.ptr;
|
||||
} else {
|
||||
// Non-identifier subject (e.g. function call): spill to temp alloca
|
||||
const val = try self.genExpr(match.subject);
|
||||
const tmp = c.LLVMBuildAlloca(self.builder, info.llvm_type, "match_tmp");
|
||||
_ = c.LLVMBuildStore(self.builder, val, tmp);
|
||||
union_subject_ptr = tmp;
|
||||
}
|
||||
break :blk self.loadStructField(info.llvm_type, union_subject_ptr.?, 0, self.getEnumLLVMType(union_name.?));
|
||||
} else try self.genExpr(match.subject);
|
||||
|
||||
const variants: ?[]const []const u8 = if (union_name) |un|
|
||||
@@ -6630,6 +6628,12 @@ pub const CodeGen = struct {
|
||||
for (tag_values) |tag| {
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(i64_type, tag, 0), case_bbs.items[i]);
|
||||
}
|
||||
} else if (pat.data == .int_literal) {
|
||||
const case_val = c.LLVMConstInt(case_int_type, @bitCast(@as(i64, pat.data.int_literal.value)), 0);
|
||||
c.LLVMAddCase(sw, case_val, case_bbs.items[i]);
|
||||
} else if (pat.data == .bool_literal) {
|
||||
const case_val = c.LLVMConstInt(case_int_type, @intFromBool(pat.data.bool_literal.value), 0);
|
||||
c.LLVMAddCase(sw, case_val, case_bbs.items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6677,8 +6681,7 @@ pub const CodeGen = struct {
|
||||
if (vidx) |vi| {
|
||||
const variant_ty = uinfo.variant_types[vi];
|
||||
if (variant_ty != .void_type) {
|
||||
const subject_entry = self.named_values.get(match.subject.data.identifier.name).?;
|
||||
const payload_gep = self.structGEP(uinfo.llvm_type, subject_entry.ptr, uinfo.payload_field_index, "cap_payload");
|
||||
const payload_gep = self.structGEP(uinfo.llvm_type, union_subject_ptr.?, uinfo.payload_field_index, "cap_payload");
|
||||
const payload_llvm_ty = self.typeToLLVM(variant_ty);
|
||||
const payload_val = c.LLVMBuildLoad2(self.builder, payload_llvm_ty, payload_gep, "cap_load");
|
||||
const cap_alloca = c.LLVMBuildAlloca(self.builder, payload_llvm_ty, @ptrCast(cap_name.ptr));
|
||||
@@ -7245,9 +7248,11 @@ pub const CodeGen = struct {
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(64);
|
||||
if (std.mem.eql(u8, fa.field, "ptr")) return .{ .many_pointer_type = .{ .element_name = obj_ty.slice_type.element_name } };
|
||||
}
|
||||
if (obj_ty.isArray()) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(64);
|
||||
if (std.mem.eql(u8, fa.field, "ptr")) return .{ .many_pointer_type = .{ .element_name = obj_ty.array_type.element_name } };
|
||||
}
|
||||
if (obj_ty.isAny()) {
|
||||
if (std.mem.eql(u8, fa.field, "tag")) return Type.s(64);
|
||||
@@ -7289,10 +7294,10 @@ pub const CodeGen = struct {
|
||||
return obj_ty.vectorElementType() orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isArray()) {
|
||||
return Type.fromName(obj_ty.array_type.element_name) orelse Type.s(64);
|
||||
return self.resolveTypeFromName(obj_ty.array_type.element_name) orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
return obj_ty.sliceElementType() orelse Type.s(64);
|
||||
return self.resolveTypeFromName(obj_ty.slice_type.element_name) orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isManyPointer()) {
|
||||
return self.resolveTypeFromName(obj_ty.many_pointer_type.element_name) orelse Type.s(64);
|
||||
|
||||
@@ -1 +1 @@
|
||||
[1.000000, 0.000000, -1.000000]
|
||||
/Volumes/Store/dev/swipelab/sx/examples/14-demo.sx:16:1: error: comptime execution failed: UnsupportedExpression
|
||||
|
||||
@@ -89,7 +89,10 @@ match-expr-else: 99
|
||||
capture: 9.500000
|
||||
capture-arrow: 7.500000
|
||||
else-match: other
|
||||
int-match: two
|
||||
int-match-else: unknown
|
||||
bool-match-t: yes
|
||||
bool-match-f: no
|
||||
bool: true
|
||||
union-f: 3.140000
|
||||
union-i: 1078523331
|
||||
@@ -242,4 +245,17 @@ arr swap: 3 1
|
||||
3-way: 3 1 2
|
||||
=== 15. Foreign ===
|
||||
foreign-rename: 42
|
||||
=== 16. Compound Assign ===
|
||||
f64+=f32: 13.000000
|
||||
s64-=s32: 93
|
||||
=== 17. Slice Ptr ===
|
||||
sl-ptr[0]: 20
|
||||
sl-ptr[1]: 30
|
||||
=== 18. Array of Structs ===
|
||||
arr-struct-x: 3
|
||||
for-struct: Point{x: 1, y: 2}
|
||||
for-struct: Point{x: 3, y: 4}
|
||||
=== 19. Local Fn Return ===
|
||||
local-struct: 42 99
|
||||
local-enum: .circle(2.500000)
|
||||
=== DONE ===
|
||||
|
||||
Reference in New Issue
Block a user