This commit is contained in:
agra
2026-02-18 05:31:54 +02:00
parent ae5e6cd507
commit 3c0912a936
4 changed files with 132 additions and 56 deletions

View File

@@ -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");
}

View File

@@ -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);

View File

@@ -1 +1 @@
[1.000000, 0.000000, -1.000000]
/Volumes/Store/dev/swipelab/sx/examples/14-demo.sx:16:1: error: comptime execution failed: UnsupportedExpression

View File

@@ -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 ===