diff --git a/src/backend/llvm/ops.zig b/src/backend/llvm/ops.zig index b1c223ab..1c5fc7cf 100644 --- a/src/backend/llvm/ops.zig +++ b/src/backend/llvm/ops.zig @@ -1459,11 +1459,6 @@ pub const Ops = struct { } } - pub fn emitCompilerCall(self: Ops, instruction: *const Inst) void { - // Compiler hooks are comptime-only; if one reaches emission, produce undef - self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(instruction.ty))); - } - pub fn emitCallClosure(self: Ops, instruction: *const Inst, call_op: CallIndirect) void { // Closure: { fn_ptr, env }. // diff --git a/src/ir/compiler_hooks.zig b/src/ir/compiler_hooks.zig index 82f65d78..b8bba39b 100644 --- a/src/ir/compiler_hooks.zig +++ b/src/ir/compiler_hooks.zig @@ -1,13 +1,12 @@ 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; const inst = @import("inst.zig"); const FuncId = inst.FuncId; // ── BuildConfig ───────────────────────────────────────────────────────── -// Mutable build configuration accumulated by #run blocks via #compiler methods. +// Mutable build configuration accumulated by the sx-driven build pipeline +// (`default_pipeline` / an `on_build` callback) running on the comptime VM, +// which reads/writes these fields via the `abi(.compiler)` primitives. /// `(src_dir, dest_in_bundle)` pair recorded by /// `BuildOptions.add_asset_dir(src, dest)`. The sx bundler walks the @@ -144,440 +143,3 @@ pub const BuildHooks = struct { ) anyerror!void, }; -// ── 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.add_framework", &hookAddFramework) catch {}; - self.hooks.put("BuildOptions.add_asset_dir", &hookAddAssetDir) catch {}; - self.hooks.put("BuildOptions.asset_dir_count", &hookAssetDirCount) catch {}; - self.hooks.put("BuildOptions.asset_dir_src_at", &hookAssetDirSrcAt) catch {}; - self.hooks.put("BuildOptions.asset_dir_dest_at", &hookAssetDirDestAt) catch {}; - self.hooks.put("BuildOptions.set_output_path", &hookSetOutputPath) catch {}; - self.hooks.put("BuildOptions.set_wasm_shell", &hookSetWasmShell) catch {}; - self.hooks.put("BuildOptions.set_post_link_callback", &hookSetPostLinkCallback) catch {}; - self.hooks.put("BuildOptions.set_post_link_module", &hookSetPostLinkModule) catch {}; - self.hooks.put("BuildOptions.binary_path", &hookGetBinaryPath) catch {}; - // Bundling setters - self.hooks.put("BuildOptions.set_bundle_path", &hookSetBundlePath) catch {}; - self.hooks.put("BuildOptions.set_bundle_id", &hookSetBundleId) catch {}; - self.hooks.put("BuildOptions.set_codesign_identity", &hookSetCodesignIdentity) catch {}; - self.hooks.put("BuildOptions.set_provisioning_profile", &hookSetProvisioningProfile) catch {}; - // Bundling accessors - self.hooks.put("BuildOptions.bundle_path", &hookGetBundlePath) catch {}; - self.hooks.put("BuildOptions.bundle_id", &hookGetBundleId) catch {}; - self.hooks.put("BuildOptions.codesign_identity", &hookGetCodesignIdentity) catch {}; - self.hooks.put("BuildOptions.provisioning_profile", &hookGetProvisioningProfile) catch {}; - // Target accessors — mirror TargetConfig.is{MacOS,IOS,IOSDevice,IOSSimulator,Android}() - self.hooks.put("BuildOptions.target_triple", &hookGetTargetTriple) catch {}; - self.hooks.put("BuildOptions.is_macos", &hookIsMacOS) catch {}; - self.hooks.put("BuildOptions.is_ios", &hookIsIOS) catch {}; - self.hooks.put("BuildOptions.is_ios_device", &hookIsIOSDevice) catch {}; - self.hooks.put("BuildOptions.is_ios_simulator", &hookIsIOSSimulator) catch {}; - self.hooks.put("BuildOptions.is_android", &hookIsAndroid) catch {}; - // Android-specific setters + accessors - self.hooks.put("BuildOptions.set_manifest_path", &hookSetManifestPath) catch {}; - self.hooks.put("BuildOptions.manifest_path", &hookGetManifestPath) catch {}; - self.hooks.put("BuildOptions.set_keystore_path", &hookSetKeystorePath) catch {}; - self.hooks.put("BuildOptions.keystore_path", &hookGetKeystorePath) catch {}; - // #jni_main class emissions, exposed by index so bundle.sx can iterate. - self.hooks.put("BuildOptions.jni_main_count", &hookJniMainCount) catch {}; - self.hooks.put("BuildOptions.jni_main_runtime_path_at", &hookJniMainRuntimePathAt) catch {}; - self.hooks.put("BuildOptions.jni_main_java_source_at", &hookJniMainJavaSourceAt) catch {}; - // Framework list accessors (for `.app/Frameworks/` embedding) - self.hooks.put("BuildOptions.framework_count", &hookFrameworkCount) catch {}; - self.hooks.put("BuildOptions.framework_at", &hookFrameworkAt) catch {}; - self.hooks.put("BuildOptions.framework_path_count", &hookFrameworkPathCount) catch {}; - self.hooks.put("BuildOptions.framework_path_at", &hookFrameworkPathAt) 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 hookAddFramework( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - // args: [self (BuildOptions value), framework_name] - if (args.len < 2) return .void_val; - const str_val = args[1]; - if (str_val.asString(interp)) |s| { - bc.frameworks.append(alloc, alloc.dupe(u8, s) catch return error.CannotEvalComptime) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookAddAssetDir( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - // args: [self (BuildOptions value), src_path, dest_path_in_bundle] - if (args.len < 3) return .void_val; - const src = args[1].asString(interp) orelse return error.TypeError; - const dest = args[2].asString(interp) orelse return error.TypeError; - const src_dup = alloc.dupe(u8, src) catch return error.CannotEvalComptime; - const dest_dup = alloc.dupe(u8, dest) catch return error.CannotEvalComptime; - bc.asset_dirs.append(alloc, .{ .src = src_dup, .dest = dest_dup }) catch return error.CannotEvalComptime; - return .void_val; -} - -fn hookAssetDirCount(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .int = @intCast(bc.asset_dirs.items.len) }; -} - -fn hookAssetDirSrcAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx = args[1].asInt() orelse return error.TypeError; - if (idx < 0 or @as(usize, @intCast(idx)) >= bc.asset_dirs.items.len) return Value{ .string = "" }; - return Value{ .string = bc.asset_dirs.items[@intCast(idx)].src }; -} - -fn hookAssetDirDestAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx = args[1].asInt() orelse return error.TypeError; - if (idx < 0 or @as(usize, @intCast(idx)) >= bc.asset_dirs.items.len) return Value{ .string = "" }; - return Value{ .string = bc.asset_dirs.items[@intCast(idx)].dest }; -} - -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; -} - -fn hookSetWasmShell( - 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.wasm_shell_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookSetPostLinkCallback( - _: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - _: Allocator, -) HookError!Value { - // args: [self (BuildOptions value), fn_value]. We accept a function - // value (.func_ref) and stash the FuncId so `main.zig` can re-enter - // the interpreter after linking. - if (args.len < 2) return .void_val; - switch (args[1]) { - .func_ref => |id| bc.post_link_callback_fn = id, - else => return error.TypeError, - } - return .void_val; -} - -fn hookSetPostLinkModule( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.post_link_module = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -/// Read the linked-binary path that main.zig populated right before -/// invoking the post-link callback. Returns the fat-string aggregate -/// the interpreter normally hands out for sx `string` values. -fn hookGetBinaryPath( - interp: *const Interpreter, - _: []const Value, - bc: *BuildConfig, - _: Allocator, -) HookError!Value { - _ = interp; - const path = bc.binary_path orelse ""; - return Value{ .string = path }; -} - -// ── Bundling setters & accessors ───────────────────────────────────── -// Same pattern as set_output_path: take a string arg, dupe into the -// long-lived allocator, store on BuildConfig. The companion accessor -// reads back the same field; empty string when unset. - -fn hookSetBundlePath( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.bundle_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookSetBundleId( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.bundle_id = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookSetCodesignIdentity( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.codesign_identity = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookSetProvisioningProfile( - interp: *const Interpreter, - args: []const Value, - bc: *BuildConfig, - alloc: Allocator, -) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.provisioning_profile = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookGetBundlePath(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.bundle_path orelse "" }; -} - -fn hookGetBundleId(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.bundle_id orelse "" }; -} - -fn hookGetCodesignIdentity(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.codesign_identity orelse "" }; -} - -fn hookGetProvisioningProfile(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.provisioning_profile orelse "" }; -} - -// ── Target accessors ────────────────────────────────────────────────── -// These look at the target_triple that main.zig populates and answer -// the same questions TargetConfig's helpers do for Zig callers. - -fn tripleContains(triple: ?[]const u8, needle: []const u8) bool { - const t = triple orelse return false; - return std.mem.indexOf(u8, t, needle) != null; -} - -fn isIOSTriple(triple: ?[]const u8) bool { - return tripleContains(triple, "apple-ios"); -} - -fn hookGetTargetTriple(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.target_triple orelse "" }; -} - -fn hookIsMacOS(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (isIOSTriple(bc.target_triple)) return Value{ .boolean = false }; - const t = bc.target_triple orelse ""; - const is_mac = std.mem.indexOf(u8, t, "apple-macosx") != null or - std.mem.indexOf(u8, t, "apple-macos") != null or - std.mem.indexOf(u8, t, "apple-darwin") != null; - return Value{ .boolean = is_mac }; -} - -fn hookIsIOS(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .boolean = isIOSTriple(bc.target_triple) }; -} - -fn hookIsIOSDevice(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - const ios = isIOSTriple(bc.target_triple); - const sim = tripleContains(bc.target_triple, "simulator"); - return Value{ .boolean = ios and !sim }; -} - -fn hookIsIOSSimulator(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - const ios = isIOSTriple(bc.target_triple); - const sim = tripleContains(bc.target_triple, "simulator"); - return Value{ .boolean = ios and sim }; -} - -fn hookIsAndroid(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .boolean = tripleContains(bc.target_triple, "android") }; -} - -// ── Android-specific bundling setters + accessors ───────────────────── - -fn hookSetManifestPath(interp: *const Interpreter, args: []const Value, bc: *BuildConfig, alloc: Allocator) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.manifest_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookGetManifestPath(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.manifest_path orelse "" }; -} - -fn hookSetKeystorePath(interp: *const Interpreter, args: []const Value, bc: *BuildConfig, alloc: Allocator) HookError!Value { - if (args.len < 2) return .void_val; - if (args[1].asString(interp)) |s| { - bc.keystore_path = alloc.dupe(u8, s) catch return error.CannotEvalComptime; - } - return .void_val; -} - -fn hookGetKeystorePath(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .string = bc.keystore_path orelse "" }; -} - -// ── #jni_main emission accessors ────────────────────────────────────── -// The Android bundler walks these as `0..jni_main_count()` and reads -// each entry's `(runtime_path, java_source)` pair so it can write a -// `.java` file per decl, compile via javac, and produce classes.dex -// via d8 before zipping into the APK. - -fn hookJniMainCount(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return Value{ .int = @intCast(bc.jni_main_runtime_paths.len) }; -} - -fn hookJniMainRuntimePathAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx = args[1].asInt() orelse return error.TypeError; - if (idx < 0 or @as(usize, @intCast(idx)) >= bc.jni_main_runtime_paths.len) return Value{ .string = "" }; - return Value{ .string = bc.jni_main_runtime_paths[@intCast(idx)] }; -} - -fn hookJniMainJavaSourceAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx = args[1].asInt() orelse return error.TypeError; - if (idx < 0 or @as(usize, @intCast(idx)) >= bc.jni_main_java_sources.len) return Value{ .string = "" }; - return Value{ .string = bc.jni_main_java_sources[@intCast(idx)] }; -} - -// ── Framework list accessors ────────────────────────────────────────── -// The Apple .app bundler in `library/modules/platform/bundle.sx` walks -// the framework list to recursively copy each `.framework` -// directory from the user's -F search paths into `/Frameworks/`. -// Slice-of-string returns aren't natively expressible as a Value, so we -// expose count + indexed lookups instead. - -fn intValue(n: i64) Value { - return Value{ .int = n }; -} - -fn hookFrameworkCount(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return intValue(@intCast(bc.target_frameworks.len)); -} - -fn hookFrameworkAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx_i64 = args[1].asInt() orelse return error.TypeError; - if (idx_i64 < 0 or @as(usize, @intCast(idx_i64)) >= bc.target_frameworks.len) { - return Value{ .string = "" }; - } - return Value{ .string = bc.target_frameworks[@intCast(idx_i64)] }; -} - -fn hookFrameworkPathCount(_: *const Interpreter, _: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - return intValue(@intCast(bc.target_framework_paths.len)); -} - -fn hookFrameworkPathAt(_: *const Interpreter, args: []const Value, bc: *BuildConfig, _: Allocator) HookError!Value { - if (args.len < 2) return Value{ .string = "" }; - const idx_i64 = args[1].asInt() orelse return error.TypeError; - if (idx_i64 < 0 or @as(usize, @intCast(idx_i64)) >= bc.target_framework_paths.len) { - return Value{ .string = "" }; - } - return Value{ .string = bc.target_framework_paths[@intCast(idx_i64)] }; -} diff --git a/src/ir/comptime_vm.test.zig b/src/ir/comptime_vm.test.zig index 5c88999b..d0fbcdaa 100644 --- a/src/ir/comptime_vm.test.zig +++ b/src/ir/comptime_vm.test.zig @@ -1314,12 +1314,12 @@ test "comptime_vm tryEval: pure function → Value; unsupported → null" { const v = vm.tryEval(alloc, &module, ok_id, null, null) orelse return error.VmShouldHaveHandledIt; try std.testing.expectEqual(@as(i64, 42), v.int); - // fn bad() { compiler_call() } → an unported op → tryEval yields null (caller - // falls back to legacy). (box_any/unbox_any are now VM-native; compiler_call is - // still unported until Phase 4D.) + // fn bad() { vec_splat(...) } → an unported op → tryEval yields null. The VM + // bails loudly on any op it does not model (never a silent default); vec_splat + // is a stable example of one. var fb2 = Fb.init(alloc, &.{}, .void); const c0 = fb2.block(&.{}); - _ = fb2.add(c0, inst(.{ .compiler_call = .{ .name = 0, .args = &.{} } }, .void)); + _ = fb2.add(c0, inst(.{ .vec_splat = .{ .operand = ref(0) } }, .void)); _ = fb2.add(c0, inst(.ret_void, .void)); const bad_id = module.addFunction(fb2.func); @@ -1341,18 +1341,18 @@ test "comptime_vm exec: division by zero and unsupported op bail loudly" { try std.testing.expectEqual(@as(i64, 4), toI64(try v.run(&fb.func, &.{ fromI64(12), fromI64(3) }))); try std.testing.expectError(error.DivisionByZero, v.run(&fb.func, &.{ fromI64(12), fromI64(0) })); } - // A not-yet-ported op (compiler_call) → Unsupported with the op name in `detail`. + // A not-yet-ported op (vec_splat) → Unsupported with the op name in `detail`. { var fb = Fb.init(std.testing.allocator, &.{}, .void); defer fb.deinit(); const b0 = fb.block(&.{}); - _ = fb.add(b0, inst(.{ .compiler_call = .{ .name = 0, .args = &.{} } }, .void)); + _ = fb.add(b0, inst(.{ .vec_splat = .{ .operand = ref(0) } }, .void)); _ = fb.add(b0, inst(.ret_void, .void)); var v = vm.Vm.init(std.testing.allocator); defer v.deinit(); try std.testing.expectError(error.Unsupported, v.run(&fb.func, &.{})); - try std.testing.expectEqualStrings("compiler_call", v.detail.?); + try std.testing.expectEqualStrings("vec_splat", v.detail.?); } } diff --git a/src/ir/emit_llvm.zig b/src/ir/emit_llvm.zig index 749468fb..3c38940b 100644 --- a/src/ir/emit_llvm.zig +++ b/src/ir/emit_llvm.zig @@ -1632,7 +1632,6 @@ pub const LLVMEmitter = struct { // ── Call extensions ─────────────────────────────────────── .call_builtin => |bi| self.ops().emitCallBuiltin(instruction, bi), - .compiler_call => self.ops().emitCompilerCall(instruction), .call_closure => |call_op| self.ops().emitCallClosure(instruction, call_op), // ── Tuple ops ──────────────────────────────────────────── diff --git a/src/ir/inst.zig b/src/ir/inst.zig index b1f41b2a..5816b9cd 100644 --- a/src/ir/inst.zig +++ b/src/ir/inst.zig @@ -207,7 +207,6 @@ pub const Op = union(enum) { call_indirect: CallIndirect, call_closure: CallIndirect, call_builtin: BuiltinCall, - compiler_call: CompilerCall, /// `#objc_call(ReturnT)(recv, sel, args...)` — dispatched through /// `objc_msgSend`. emit_llvm.zig synthesizes a per-call-site LLVM @@ -473,11 +472,6 @@ pub const BuiltinId = enum(u16) { type_info, }; -pub const CompilerCall = struct { - name: u32, // StringPool id for qualified name (e.g. "BuildOptions.add_link_flag") - args: []const Ref, -}; - pub const ClosureCreate = struct { func: FuncId, // trampoline function env: Ref, // allocated env pointer (or Ref.none for no captures) diff --git a/src/ir/interp.zig b/src/ir/interp.zig index 5cd0475e..12d46c45 100644 --- a/src/ir/interp.zig +++ b/src/ir/interp.zig @@ -200,9 +200,6 @@ pub const Interpreter = struct { // Mutable build configuration — set by LLVMEmitter, written by #run blocks build_config: ?*BuildConfig = null, - // Compiler hook registry for #compiler methods - hooks: compiler_hooks.Registry, - // First op tag that bailed with InterpError, captured the first // time the interpreter unwinds so callers can surface "op=foo at // :" alongside the bare error name. Static so it @@ -234,15 +231,12 @@ pub const Interpreter = struct { } pub fn init(module: *const Module, alloc: Allocator) Interpreter { - var hooks = compiler_hooks.Registry.init(alloc); - hooks.registerDefaults(); return .{ .module = module, .alloc = alloc, .output = std.ArrayList(u8).empty, .heap = std.ArrayList([]u8).empty, .global_values = std.AutoHashMap(u32, Value).init(alloc), - .hooks = hooks, }; } @@ -268,7 +262,6 @@ pub const Interpreter = struct { self.output.deinit(self.alloc); self.call_chain.deinit(self.alloc); self.global_values.deinit(); - self.hooks.deinit(); } /// Write `val` to the raw host address `addr` using exactly the @@ -1126,31 +1119,6 @@ pub const Interpreter = struct { return self.execBuiltin(bi, frame, instruction.ty); }, - // ── Compiler hook calls (#compiler methods) ──────── - .compiler_call => |cc| { - const name = self.module.types.getString(@enumFromInt(cc.name)); - if (self.hooks.get(name)) |hook| { - // Resolve args from Ref to Value - var resolved_args = std.ArrayList(Value).empty; - defer resolved_args.deinit(self.alloc); - for (cc.args) |arg| { - resolved_args.append(self.alloc, frame.getRef(arg)) catch return error.CannotEvalComptime; - } - if (self.build_config) |bc| { - const result = hook(self, resolved_args.items, bc, self.alloc) catch return bailDetail("#compiler hook returned an error (see hook impl)"); - return .{ .value = result }; - } - return .{ .value = .void_val }; - } - if (last_bail_detail == null) { - // Capture which hook name failed so the host diag - // surfaces "compiler_call: unknown hook 'X'" instead - // of a bare CannotEvalComptime. - last_bail_detail = "#compiler hook not registered (likely a target-specific BuildOptions setter)"; - } - return error.CannotEvalComptime; - }, - // ── Struct GEP (field pointer) ───────────────────── .struct_gep => |fa| { const base = frame.getRef(fa.base); diff --git a/src/ir/lower/call.zig b/src/ir/lower/call.zig index eafacae9..6af51f1f 100644 --- a/src/ir/lower/call.zig +++ b/src/ir/lower/call.zig @@ -494,14 +494,6 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { return self.lowerGenericCall(fd, func_name, c, args.items); } } - // Check for #compiler free functions - if (self.program_index.fn_ast_map.get(func_name)) |fd_check| { - if (fd_check.body.data == .compiler_expr) { - const ret_ty = if (fd_check.return_type) |rt| type_bridge.resolveAstType(rt, &self.module.types, &self.program_index.type_alias_map, &self.program_index.module_const_map) else TypeId.void; - return self.builder.compilerCall(func_name, args.items, ret_ty); - } - } - // Look up declared/extern function — try lazy lowering if not yet lowered { // First attempt: function may already be declared (from scanDecls) @@ -907,17 +899,6 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { // Try direct qualified name: StructName.method const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ sname, fa.field }) catch fa.field; - // Generic #compiler method dispatch - if (self.program_index.fn_ast_map.get(qualified)) |method_fd| { - if (method_fd.body.data == .compiler_expr) { - const ret_ty = if (method_fd.return_type) |rt| - type_bridge.resolveAstType(rt, &self.module.types, &self.program_index.type_alias_map, &self.program_index.module_const_map) - else - .void; - return self.builder.compilerCall(qualified, method_args.items, ret_ty); - } - } - // Generic-struct instance method: select the body via the // instance's STAMPED author (CP-4), so the dispatched method is // the one authored alongside this instance's layout — never the diff --git a/src/ir/module.zig b/src/ir/module.zig index 8d643010..478dffe5 100644 --- a/src/ir/module.zig +++ b/src/ir/module.zig @@ -570,12 +570,6 @@ pub const Builder = struct { return self.emit(.{ .call_builtin = .{ .builtin = builtin, .args = owned } }, ret_ty); } - pub fn compilerCall(self: *Builder, name: []const u8, args: []const Ref, ret_ty: TypeId) Ref { - const name_id = self.module.types.strings.intern(self.module.alloc, name); - const owned = self.module.slice_arena.allocator().dupe(Ref, args) catch unreachable; - return self.emit(.{ .compiler_call = .{ .name = @intFromEnum(name_id), .args = owned } }, ret_ty); - } - // ── Closure ───────────────────────────────────────────────────── pub fn closureCreate(self: *Builder, func_id: FuncId, env: Ref, ty: TypeId) Ref { diff --git a/src/ir/print.zig b/src/ir/print.zig index 483d4dba..95b617bc 100644 --- a/src/ir/print.zig +++ b/src/ir/print.zig @@ -336,13 +336,6 @@ fn printInst(instruction: *const Inst, ref_idx: u32, tt: *const TypeTable, write a.clobbers.len, }); }, - .compiler_call => |cc| { - const name = tt.getString(@enumFromInt(cc.name)); - try writer.print("compiler_call \"{s}\"(", .{name}); - try writeArgs(cc.args, writer); - try writer.writeAll(") : "); - }, - // ── Closure ───────────────────────────────────────────── .closure_create => |cc| { try writer.print("closure_create @{d}", .{cc.func.index()});