quick sort

This commit is contained in:
agra
2026-02-10 18:58:04 +02:00
parent a6f0276fa5
commit 3fde080092
8 changed files with 326 additions and 30 deletions

View File

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