quick sort
This commit is contained in:
162
src/codegen.zig
162
src/codegen.zig
@@ -81,6 +81,8 @@ pub const CodeGen = struct {
|
||||
// Cache of auto-generated to_string functions for complex types
|
||||
// Variadic function info: maps function name to variadic metadata
|
||||
variadic_functions: std.StringHashMap(VariadicInfo),
|
||||
// Maps function name to resolved sx parameter types (for accurate type conversion at call sites)
|
||||
fn_param_types: std.StringHashMap([]const Type),
|
||||
// Enriched Any type entries: maps type name to tag + category + sx type
|
||||
any_type_entries: std.StringHashMap(AnyTypeEntry),
|
||||
// Current match arm type entries (set during category match arm body generation)
|
||||
@@ -173,6 +175,7 @@ pub const CodeGen = struct {
|
||||
.namespaces = std.StringHashMap(void).init(allocator),
|
||||
.builtin_functions = std.StringHashMap(void).init(allocator),
|
||||
.variadic_functions = std.StringHashMap(VariadicInfo).init(allocator),
|
||||
.fn_param_types = std.StringHashMap([]const Type).init(allocator),
|
||||
.any_type_id_map = std.StringHashMap(u64).init(allocator),
|
||||
.any_type_entries = std.StringHashMap(AnyTypeEntry).init(allocator),
|
||||
};
|
||||
@@ -689,6 +692,13 @@ pub const CodeGen = struct {
|
||||
const elem_name = elem_type.displayName(self.allocator) catch unreachable;
|
||||
return .{ .array_type = .{ .element_name = elem_name, .length = length } };
|
||||
}
|
||||
// Slice type: []T
|
||||
if (tn.data == .slice_type_expr) {
|
||||
const ste = tn.data.slice_type_expr;
|
||||
const elem_type = self.resolveType(ste.element_type);
|
||||
const elem_name = elem_type.displayName(self.allocator) catch unreachable;
|
||||
return .{ .slice_type = .{ .element_name = elem_name } };
|
||||
}
|
||||
// Parameterized type: Vector(N, T) or generic struct instantiation
|
||||
if (tn.data == .parameterized_type_expr) {
|
||||
const pte = tn.data.parameterized_type_expr;
|
||||
@@ -1088,6 +1098,18 @@ pub const CodeGen = struct {
|
||||
const fn_type = try self.buildFnType(fd.params, fd.return_type, fd.name);
|
||||
const name_z = try self.allocator.dupeZ(u8, llvm_name);
|
||||
_ = c.LLVMAddFunction(self.module, name_z.ptr, fn_type);
|
||||
// Track resolved parameter types for accurate call-site conversion
|
||||
var param_types = std.ArrayList(Type).empty;
|
||||
for (fd.params) |param| {
|
||||
if (param.is_comptime) continue;
|
||||
if (param.is_variadic) {
|
||||
const elem_name = if (param.type_expr.data == .type_expr) param.type_expr.data.type_expr.name else "s32";
|
||||
try param_types.append(self.allocator, .{ .slice_type = .{ .element_name = elem_name } });
|
||||
} else {
|
||||
try param_types.append(self.allocator, self.resolveType(param.type_expr));
|
||||
}
|
||||
}
|
||||
try self.fn_param_types.put(llvm_name, try param_types.toOwnedSlice(self.allocator));
|
||||
// Track variadic function info for call site packing
|
||||
for (fd.params, 0..) |param, i| {
|
||||
if (param.is_variadic) {
|
||||
@@ -2039,7 +2061,28 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
return self.emitError("index assignment requires a string or array target");
|
||||
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_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
// Load slice value to get ptr
|
||||
const slice_val = blk: {
|
||||
if (ie.object.data == .identifier) {
|
||||
if (self.named_values.get(ie.object.data.identifier.name)) |entry| {
|
||||
break :blk c.LLVMBuildLoad2(self.builder, self.getStringStructType(), entry.ptr, "slice_load");
|
||||
}
|
||||
}
|
||||
break :blk try self.genExpr(ie.object);
|
||||
};
|
||||
const ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_ptr");
|
||||
const idx = try self.genExpr(ie.index);
|
||||
const val = try self.genExpr(asgn.value);
|
||||
var gep_indices = [_]c.LLVMValueRef{idx};
|
||||
const gep_ptr = c.LLVMBuildGEP2(self.builder, elem_llvm_ty, ptr, &gep_indices, 1, "sliceidx");
|
||||
_ = c.LLVMBuildStore(self.builder, val, gep_ptr);
|
||||
return null;
|
||||
}
|
||||
return self.emitError("index assignment requires a string, array, or slice target");
|
||||
}
|
||||
|
||||
fn unescapeString(allocator: std.mem.Allocator, raw: []const u8) ![]u8 {
|
||||
@@ -2165,11 +2208,12 @@ pub const CodeGen = struct {
|
||||
return self.genUnionLiteral(ul, null);
|
||||
},
|
||||
.array_literal => |al| {
|
||||
// Typed array/vector literal: Type.[elems]
|
||||
// Typed array/vector/slice literal: Type.[elems]
|
||||
if (al.type_expr) |te| {
|
||||
const ty = self.resolveType(te);
|
||||
if (ty.isVector()) return self.genVectorLiteral(al, ty);
|
||||
if (ty.isArray()) return self.genArrayLiteral(al, ty);
|
||||
if (ty.isSlice()) return self.genSliceLiteral(al, ty);
|
||||
}
|
||||
// If current return type is vector, build as vector SSA value
|
||||
if (self.current_return_type.isVector()) {
|
||||
@@ -2527,6 +2571,40 @@ pub const CodeGen = struct {
|
||||
return alloca;
|
||||
}
|
||||
|
||||
fn genSliceLiteral(self: *CodeGen, al: ast.ArrayLiteral, slice_ty: Type) !c.LLVMValueRef {
|
||||
const elem_name = slice_ty.slice_type.element_name;
|
||||
const elem_sx_ty = Type.fromName(elem_name) orelse return self.emitErrorFmt("unknown slice element type '{s}'", .{elem_name});
|
||||
const n: u32 = @intCast(al.elements.len);
|
||||
|
||||
// Create backing array [N]elem on the stack
|
||||
const arr_ty: Type = .{ .array_type = .{ .element_name = elem_name, .length = n } };
|
||||
const llvm_arr_ty = self.typeToLLVM(arr_ty);
|
||||
const arr_alloca = c.LLVMBuildAlloca(self.builder, llvm_arr_ty, "slice_backing");
|
||||
|
||||
// Fill elements
|
||||
for (0..n) |i| {
|
||||
const val = try self.genExprAsType(al.elements[i], elem_sx_ty);
|
||||
var indices = [_]c.LLVMValueRef{
|
||||
c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0),
|
||||
c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), @intCast(i), 0),
|
||||
};
|
||||
const gep = c.LLVMBuildGEP2(self.builder, llvm_arr_ty, arr_alloca, &indices, 2, "slice_elem");
|
||||
_ = c.LLVMBuildStore(self.builder, val, gep);
|
||||
}
|
||||
|
||||
// Build slice {ptr, len}
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i32_ty, 0, 0);
|
||||
var gep_indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const elem_ptr = c.LLVMBuildGEP2(self.builder, llvm_arr_ty, arr_alloca, &gep_indices, 2, "slice_data");
|
||||
const slice_llvm_ty = self.getStringStructType();
|
||||
var slice_val = c.LLVMGetUndef(slice_llvm_ty);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, elem_ptr, 0, "slice_ptr");
|
||||
const len_val = c.LLVMConstInt(i32_ty, n, 0);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, len_val, 1, "slice_len");
|
||||
return slice_val;
|
||||
}
|
||||
|
||||
fn genVectorLiteral(self: *CodeGen, al: ast.ArrayLiteral, vec_ty: Type) !c.LLVMValueRef {
|
||||
const vec_info = vec_ty.vector_type;
|
||||
const elem_sx_ty = Type.fromName(vec_info.element_name) orelse return self.emitErrorFmt("unknown vector element type '{s}'", .{vec_info.element_name});
|
||||
@@ -2646,6 +2724,41 @@ pub const CodeGen = struct {
|
||||
return self.genVectorLiteral(node.data.array_literal, target_ty);
|
||||
}
|
||||
|
||||
// Array literal with target slice type: build stack-backed slice
|
||||
if (node.data == .array_literal and target_ty.isSlice()) {
|
||||
return self.genSliceLiteral(node.data.array_literal, target_ty);
|
||||
}
|
||||
|
||||
// Array to slice coercion: [N]T → []T
|
||||
if (target_ty.isSlice()) {
|
||||
const src_ty = self.inferType(node);
|
||||
if (src_ty.isArray()) {
|
||||
const arr_info = src_ty.array_type;
|
||||
// Get the alloca pointer for the array (not the loaded value)
|
||||
const arr_alloca = blk: {
|
||||
if (node.data == .identifier) {
|
||||
if (self.named_values.get(node.data.identifier.name)) |entry| {
|
||||
break :blk entry.ptr;
|
||||
}
|
||||
}
|
||||
// Fallback: generate the expression and hope it returns a pointer
|
||||
break :blk try self.genExpr(node);
|
||||
};
|
||||
// GEP to get pointer to first element
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i32_ty, 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const elem_ptr = c.LLVMBuildGEP2(self.builder, self.typeToLLVM(src_ty), arr_alloca, &indices, 2, "arr_data");
|
||||
// Build slice struct {ptr, len}
|
||||
const slice_ty = self.getStringStructType();
|
||||
var slice_val = c.LLVMGetUndef(slice_ty);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, elem_ptr, 0, "slice_ptr");
|
||||
const len_val = c.LLVMConstInt(i32_ty, arr_info.length, 0);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, len_val, 1, "slice_len");
|
||||
return slice_val;
|
||||
}
|
||||
}
|
||||
|
||||
const val = try self.genExpr(node);
|
||||
const src_ty = self.inferType(node);
|
||||
|
||||
@@ -3672,10 +3785,20 @@ pub const CodeGen = struct {
|
||||
try arg_vals.append(self.allocator, slice_val);
|
||||
}
|
||||
} else {
|
||||
// Normal (non-variadic) call
|
||||
// Normal (non-variadic) call — use stored sx param types when available
|
||||
const stored_param_types = self.fn_param_types.get(callee_name) orelse blk: {
|
||||
if (self.current_namespace) |ns| {
|
||||
const qualified = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns, callee_name });
|
||||
break :blk self.fn_param_types.get(qualified);
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
for (call_node.args, 0..) |arg, i| {
|
||||
if (i < num_params) {
|
||||
const param_ty = self.llvmTypeToSxType(param_llvm_types[i]);
|
||||
const param_ty = if (stored_param_types != null and i < stored_param_types.?.len)
|
||||
stored_param_types.?[i]
|
||||
else
|
||||
self.llvmTypeToSxType(param_llvm_types[i]);
|
||||
try arg_vals.append(self.allocator, try self.genExprAsType(arg, param_ty));
|
||||
} else {
|
||||
try arg_vals.append(self.allocator, try self.genExpr(arg));
|
||||
@@ -3754,6 +3877,7 @@ pub const CodeGen = struct {
|
||||
var bindings = std.StringHashMap(Type).init(self.allocator);
|
||||
for (fd.params, 0..) |param, i| {
|
||||
if (param.is_comptime) continue;
|
||||
// Direct type param: (a: $T) or (a: T)
|
||||
if (param.type_expr.data == .type_expr) {
|
||||
const type_name = param.type_expr.data.type_expr.name;
|
||||
// Check if this type name is a type parameter
|
||||
@@ -3772,6 +3896,32 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Slice type param: (items: []$T) — infer T from array or slice element type
|
||||
if (param.type_expr.data == .slice_type_expr) {
|
||||
const elem_node = param.type_expr.data.slice_type_expr.element_type;
|
||||
if (elem_node.data == .type_expr) {
|
||||
const type_name = elem_node.data.type_expr.name;
|
||||
for (fd.type_params) |tp| {
|
||||
if (std.mem.eql(u8, tp.name, type_name)) {
|
||||
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
|
||||
else if (arg_ty.isSlice())
|
||||
Type.fromName(arg_ty.slice_type.element_name) orelse arg_ty
|
||||
else
|
||||
arg_ty;
|
||||
if (bindings.get(type_name)) |existing| {
|
||||
try bindings.put(type_name, Type.widen(existing, elem_ty));
|
||||
} else {
|
||||
try bindings.put(type_name, elem_ty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_comptime_values) {
|
||||
@@ -3802,13 +3952,15 @@ pub const CodeGen = struct {
|
||||
const args_slice = try arg_vals.toOwnedSlice(self.allocator);
|
||||
|
||||
const fn_type = c.LLVMGlobalGetValueType(callee_fn);
|
||||
const ret_ty = c.LLVMGetReturnType(fn_type);
|
||||
const call_name: [*c]const u8 = if (ret_ty == c.LLVMVoidTypeInContext(self.context)) "" else "calltmp";
|
||||
return c.LLVMBuildCall2(
|
||||
self.builder,
|
||||
fn_type,
|
||||
callee_fn,
|
||||
if (args_slice.len > 0) args_slice.ptr else null,
|
||||
@intCast(args_slice.len),
|
||||
"calltmp",
|
||||
call_name,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user