build options #compiler

This commit is contained in:
agra
2026-03-03 09:35:50 +02:00
parent aa1235c621
commit 03074472e5
16 changed files with 191 additions and 64 deletions

101
src/ir/compiler_hooks.zig Normal file
View File

@@ -0,0 +1,101 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const interp_mod = @import("interp.zig");
const Value = interp_mod.Value;
const Interpreter = interp_mod.Interpreter;
// ── BuildConfig ─────────────────────────────────────────────────────────
// Mutable build configuration accumulated by #run blocks via #compiler methods.
pub const BuildConfig = struct {
link_flags: std.ArrayList([]const u8) = .empty,
output_path: ?[]const u8 = null,
pub fn deinit(self: *BuildConfig, alloc: Allocator) void {
self.link_flags.deinit(alloc);
}
};
// ── Hook system ─────────────────────────────────────────────────────────
pub const HookError = error{
CannotEvalComptime,
TypeError,
};
/// Hook function signature. Receives the interpreter (for heap/string access),
/// resolved argument values, and the mutable build config.
pub const HookFn = *const fn (
interp: *const Interpreter,
args: []const Value,
bc: *BuildConfig,
alloc: Allocator,
) HookError!Value;
pub const Registry = struct {
hooks: std.StringHashMap(HookFn),
pub fn init(alloc: Allocator) Registry {
return .{ .hooks = std.StringHashMap(HookFn).init(alloc) };
}
pub fn deinit(self: *Registry) void {
self.hooks.deinit();
}
pub fn get(self: *const Registry, name: []const u8) ?HookFn {
return self.hooks.get(name);
}
/// Register all built-in compiler hooks.
pub fn registerDefaults(self: *Registry) void {
self.hooks.put("build_options", &hookBuildOptions) catch {};
self.hooks.put("BuildOptions.add_link_flag", &hookAddLinkFlag) catch {};
self.hooks.put("BuildOptions.set_output_path", &hookSetOutputPath) catch {};
}
};
// ── build_options() hook ────────────────────────────────────────────────
fn hookBuildOptions(
_: *const Interpreter,
_: []const Value,
_: *BuildConfig,
_: Allocator,
) HookError!Value {
// build_options() returns a sentinel value; the real work happens
// when methods like add_link_flag/set_output_path are called on it.
return .void_val;
}
// ── BuildOptions hooks ──────────────────────────────────────────────────
fn hookAddLinkFlag(
interp: *const Interpreter,
args: []const Value,
bc: *BuildConfig,
alloc: Allocator,
) HookError!Value {
// args: [self (BuildOptions value), flag_string]
if (args.len < 2) return .void_val;
const str_val = args[1];
if (str_val.asString(interp)) |s| {
bc.link_flags.append(alloc, alloc.dupe(u8, s) catch return error.CannotEvalComptime) catch return error.CannotEvalComptime;
}
return .void_val;
}
fn hookSetOutputPath(
interp: *const Interpreter,
args: []const Value,
bc: *BuildConfig,
alloc: Allocator,
) HookError!Value {
// args: [self (BuildOptions value), path_string]
if (args.len < 2) return .void_val;
const str_val = args[1];
if (str_val.asString(interp)) |s| {
bc.output_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime;
}
return .void_val;
}