From 3c0912a9362dda9e5a9ab9c1b77bf667e9fcf377 Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 18 Feb 2026 05:31:54 +0200 Subject: [PATCH] ... --- examples/50-smoke.sx | 55 +++++++++++++++++ src/codegen.zig | 115 +++++++++++++++++++----------------- tests/expected/14-demo.txt | 2 +- tests/expected/50-smoke.txt | 16 +++++ 4 files changed, 132 insertions(+), 56 deletions(-) diff --git a/examples/50-smoke.sx b/examples/50-smoke.sx index 8d41f14..fc139cd 100644 --- a/examples/50-smoke.sx +++ b/examples/50-smoke.sx @@ -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"); } diff --git a/src/codegen.zig b/src/codegen.zig index 08b3436..8bbea79 100644 --- a/src/codegen.zig +++ b/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); diff --git a/tests/expected/14-demo.txt b/tests/expected/14-demo.txt index 4dbb69d..1f7bb9f 100644 --- a/tests/expected/14-demo.txt +++ b/tests/expected/14-demo.txt @@ -1 +1 @@ -[1.000000, 0.000000, -1.000000] +/Volumes/Store/dev/swipelab/sx/examples/14-demo.sx:16:1: error: comptime execution failed: UnsupportedExpression diff --git a/tests/expected/50-smoke.txt b/tests/expected/50-smoke.txt index 0b1b62e..d889976 100644 --- a/tests/expected/50-smoke.txt +++ b/tests/expected/50-smoke.txt @@ -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 ===