diff --git a/src/core.zig b/src/core.zig index 00f770b..0ed6fa2 100644 --- a/src/core.zig +++ b/src/core.zig @@ -184,13 +184,22 @@ pub const Compilation = struct { ir.Interpreter.last_bail_builtin = null; ir.Interpreter.last_bail_detail = null; const result = interp.call(id, args) catch |err| { - if (interp.output.items.len > 0) std.debug.print("{s}", .{interp.output.items}); + flushInterpOutput(interp.output.items); return err; }; - if (interp.output.items.len > 0) std.debug.print("{s}", .{interp.output.items}); + flushInterpOutput(interp.output.items); return result; } + /// #run / post-link callback `print` output lands here. Routes to + /// fd 1 (stdout) so it joins the JIT-executed runtime's output + /// stream — the user wrote `print(...)` in both call sites, so + /// the stream split is invisible to them. issue-0047. + fn flushInterpOutput(bytes: []const u8) void { + if (bytes.len == 0) return; + _ = std.c.write(1, bytes.ptr, bytes.len); + } + /// Get link flags accumulated from #run build blocks. pub fn getBuildLinkFlags(self: *Compilation) []const []const u8 { if (self.ir_emitter) |*e| return e.build_config.link_flags.items; diff --git a/src/ir/emit_llvm.zig b/src/ir/emit_llvm.zig index 64bc568..9f6b583 100644 --- a/src/ir/emit_llvm.zig +++ b/src/ir/emit_llvm.zig @@ -1128,9 +1128,11 @@ pub const LLVMEmitter = struct { var interp_inst = Interpreter.init(self.ir_mod, self.alloc); interp_inst.build_config = &self.build_config; _ = interp_inst.call(func_id, &.{}) catch {}; - // Write comptime output to stderr (same as old comptime VM) + // Route #run `print` output to fd 1 so it joins the + // JIT-executed runtime's stream. Same call site shape as + // `core.flushInterpOutput` — see issue-0047. if (interp_inst.output.items.len > 0) { - std.debug.print("{s}", .{interp_inst.output.items}); + _ = std.c.write(1, interp_inst.output.items.ptr, interp_inst.output.items.len); } interp_inst.deinit(); } diff --git a/src/main.zig b/src/main.zig index 6b24d66..83a1cf2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -290,7 +290,14 @@ pub fn main(init: std.process.Init) !void { // run-time output ambiguously. Only when top-level #run exists — // pure-runtime tests keep their current snapshots. if (hasTopLevelRun(root)) { - std.debug.print("--- build done ---\n", .{}); + // Stay on the same stream as the #run output (stdout, via + // core.flushInterpOutput). Same reason as issue-0047: the + // user doesn't distinguish build-time `print` from + // runtime `print` at the call site, and the delimiter is + // meaningless if it lands on a different stream than the + // output it's separating. + const marker = "--- build done ---\n"; + _ = std.c.write(1, marker.ptr, marker.len); } const exit_code = sx.target.runJITFromObject(obj_buf) catch { // JIT failed — fall back to AOT