http server

This commit is contained in:
agra
2026-02-17 16:57:12 +02:00
parent 66034b4fec
commit 4fd87309d9
17 changed files with 437 additions and 113 deletions

View File

@@ -186,6 +186,10 @@ pub const CodeGen = struct {
foreign_libraries: std.ArrayList([]const u8),
// Set of foreign function names (for ABI lowering at call sites)
foreign_fns: std.StringHashMap(void),
// Named library constants: sx name → lib filename (e.g. "libc" → "c")
library_constants: std.StringHashMap([]const u8),
// Foreign function rename map: sx name → C symbol name (e.g. "write_fd" → "write")
foreign_name_map: std.StringHashMap([]const u8),
// Global mutable variables (from top-level var_decl, e.g. function pointers loaded at runtime)
global_mutable_vars: std.StringHashMap(NamedValue),
// Declared return types for non-generic functions (preserves signedness lost by LLVM round-trip)
@@ -394,6 +398,8 @@ pub const CodeGen = struct {
.deferred_fn_bodies = std.ArrayList(DeferredFn).empty,
.foreign_libraries = std.ArrayList([]const u8).empty,
.foreign_fns = std.StringHashMap(void).init(allocator),
.library_constants = std.StringHashMap([]const u8).init(allocator),
.foreign_name_map = std.StringHashMap([]const u8).init(allocator),
.global_mutable_vars = std.StringHashMap(NamedValue).init(allocator),
.function_return_types = std.StringHashMap(Type).init(allocator),
.target_config = target_config,
@@ -426,6 +432,8 @@ pub const CodeGen = struct {
self.deferred_fn_bodies.deinit(self.allocator);
self.foreign_libraries.deinit(self.allocator);
self.foreign_fns.deinit();
self.library_constants.deinit();
self.foreign_name_map.deinit();
c.LLVMDisposeBuilder(self.builder);
if (self.target_machine) |tm| c.LLVMDisposeTargetMachine(tm);
if (self.module_owned) {
@@ -1038,6 +1046,27 @@ pub const CodeGen = struct {
// Initialize built-in function declarations (printf, etc.)
self.builtins = Builtins.init(self.module, self.context);
// Pre-scan: collect named library constants (handles forward references)
for (root.data.root.decls) |decl| {
switch (decl.data) {
.library_decl => |ld| {
try self.library_constants.put(ld.name, ld.lib_name);
},
.namespace_decl => |ns| {
for (ns.decls) |nd| {
switch (nd.data) {
.library_decl => |nld| {
const qualified = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns.name, nld.name });
try self.library_constants.put(qualified, nld.lib_name);
},
else => {},
}
}
},
else => {},
}
}
// Pass 1: Register all declarations (signatures only, no bodies)
for (root.data.root.decls) |decl| {
switch (decl.data) {
@@ -1904,11 +1933,34 @@ pub const CodeGen = struct {
fn registerFnDecl(self: *CodeGen, fd: ast.FnDecl, llvm_name: []const u8) !void {
const is_foreign = fd.body.data == .foreign_expr;
// For foreign functions: resolve C symbol name (rename) and validate library ref
const actual_llvm_name = if (is_foreign) blk: {
const fe = fd.body.data.foreign_expr;
// Validate library reference
if (fe.library_ref) |lib_ref| {
if (!self.library_constants.contains(lib_ref)) {
return self.emitErrorFmt("unknown library '{s}' in #foreign", .{lib_ref});
}
}
// Use C symbol name if provided, otherwise use the sx name
const c_name = fe.c_name orelse llvm_name;
// Track rename mapping for call resolution
if (fe.c_name != null and !std.mem.eql(u8, c_name, llvm_name)) {
try self.foreign_name_map.put(llvm_name, c_name);
}
break :blk c_name;
} else llvm_name;
const fn_type = try self.buildFnType(fd.params, fd.return_type, fd.name, is_foreign);
const name_z = try self.allocator.dupeZ(u8, llvm_name);
const name_z = try self.allocator.dupeZ(u8, actual_llvm_name);
_ = c.LLVMAddFunction(self.module, name_z.ptr, fn_type);
// Track foreign functions for ABI lowering at call sites
if (is_foreign) try self.foreign_fns.put(llvm_name, {});
// Track foreign functions for ABI lowering at call sites (use sx name for call-site lookup)
if (is_foreign) {
try self.foreign_fns.put(llvm_name, {});
// Also track under the C name for direct lookups
if (!std.mem.eql(u8, actual_llvm_name, llvm_name)) {
try self.foreign_fns.put(actual_llvm_name, {});
}
}
// Track resolved parameter types for accurate call-site conversion
var param_types = std.ArrayList(Type).empty;
for (fd.params) |param| {
@@ -1949,10 +2001,17 @@ pub const CodeGen = struct {
}
const qualified = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns.name, fd.name });
if (fd.body.data == .foreign_expr) {
// External C function in namespace — register LLVM declaration with C name only
// External C function in namespace — register LLVM declaration
try self.registerFnDecl(fd, fd.name);
// Also track qualified name as foreign for ABI lowering at call sites
try self.foreign_fns.put(qualified, {});
// Track qualified rename mapping if C name differs
const fe = fd.body.data.foreign_expr;
if (fe.c_name) |c_name| {
if (!std.mem.eql(u8, c_name, fd.name)) {
try self.foreign_name_map.put(qualified, c_name);
}
}
// Store param types under qualified name so call-site type resolution works
var param_types = std.ArrayList(Type).empty;
for (fd.params) |param| {
@@ -2054,8 +2113,16 @@ pub const CodeGen = struct {
if (expr.data == .call) {
if (self.resolveCalleeName(expr.data.call)) |callee_name| {
var cnbuf: [256]u8 = undefined;
const callee_fn = c.LLVMGetNamedFunction(self.module, self.nameToCStr(callee_name, &cnbuf)) orelse return Type.s(64);
const fn_type = c.LLVMGlobalGetValueType(callee_fn);
var callee_fn = c.LLVMGetNamedFunction(self.module, self.nameToCStr(callee_name, &cnbuf));
// Foreign rename fallback
if (callee_fn == null) {
if (self.foreign_name_map.get(callee_name)) |c_name| {
var rbuf: [256]u8 = undefined;
callee_fn = c.LLVMGetNamedFunction(self.module, self.nameToCStr(c_name, &rbuf));
}
}
const resolved_fn = callee_fn orelse return Type.s(64);
const fn_type = c.LLVMGlobalGetValueType(resolved_fn);
const ret_llvm = c.LLVMGetReturnType(fn_type);
return self.llvmTypeToSxType(ret_llvm);
}
@@ -3160,6 +3227,13 @@ pub const CodeGen = struct {
fn_val = c.LLVMGetNamedFunction(self.module, self.nameToCStr(qualified, &qbuf));
}
}
// Foreign rename fallback: sx name → C symbol name
if (fn_val == null) {
if (self.foreign_name_map.get(ident.name)) |c_name| {
var rbuf: [256]u8 = undefined;
fn_val = c.LLVMGetNamedFunction(self.module, self.nameToCStr(c_name, &rbuf));
}
}
if (fn_val != null) return fn_val.?;
}
return self.emitErrorFmt("undefined identifier '{s}'", .{ident.name});
@@ -5386,6 +5460,13 @@ pub const CodeGen = struct {
callee_fn = c.LLVMGetNamedFunction(self.module, self.nameToCStr(qualified2, &qbuf));
}
}
// Foreign rename fallback: sx name → C symbol name (e.g. "write_fd" → "write")
if (callee_fn == null) {
if (self.foreign_name_map.get(callee_name)) |c_name| {
var rbuf: [256]u8 = undefined;
callee_fn = c.LLVMGetNamedFunction(self.module, self.nameToCStr(c_name, &rbuf));
}
}
// Function pointer indirect call: callee is a variable with function_type
if (callee_fn == null) {
if (self.lookupValue(callee_name)) |v| {
@@ -6795,7 +6876,7 @@ pub const CodeGen = struct {
fn dispatchBuiltin(self: *CodeGen, name: []const u8, call_node: ast.Call) !c.LLVMValueRef {
// Extract base name (strip namespace prefix)
const base = baseName(name);
if (std.mem.eql(u8, base, "write")) return self.genWriteCall(call_node.args);
if (std.mem.eql(u8, base, "out")) return self.genOutCall(call_node.args);
if (std.mem.eql(u8, base, "sqrt")) return self.genMathIntrinsic(call_node, "sqrt");
if (std.mem.eql(u8, base, "sin")) return self.genMathIntrinsic(call_node, "sin");
if (std.mem.eql(u8, base, "cos")) return self.genMathIntrinsic(call_node, "cos");
@@ -6816,8 +6897,8 @@ pub const CodeGen = struct {
return self.emitErrorFmt("unknown builtin function '{s}'", .{name});
}
fn genWriteCall(self: *CodeGen, args: []const *Node) !c.LLVMValueRef {
if (args.len != 1) return self.emitError("write expects exactly 1 argument");
fn genOutCall(self: *CodeGen, args: []const *Node) !c.LLVMValueRef {
if (args.len != 1) return self.emitError("out expects exactly 1 argument");
const builtins = try self.requireBuiltins();
const val = try self.genExpr(args[0]);
// Extract ptr and len from string slice
@@ -7311,7 +7392,7 @@ pub const CodeGen = struct {
}
defer _ = c.LLVMOrcDisposeLLJIT(jit);
// Add process symbols so JIT can find libc (printf, write, etc.)
// Add process symbols so JIT can find libc (printf, etc.)
const jd = c.LLVMOrcLLJITGetMainJITDylib(jit);
const prefix = c.LLVMOrcLLJITGetGlobalPrefix(jit);
var gen: c.LLVMOrcDefinitionGeneratorRef = null;