✓
Passing This code compiles and runs correctly.
Code
// PIN: `std/fmt:fmt.blk @"path"` — the BARE file-source form, the file twin
// of the inline `{` block (620_007). The template text lives in an external
// file read at compile time; `: f` binds the formatted result and the inline
// `|>` continues it — the same grammar as the block-close `}: f |> …`.
// The emitted backend carries `source from file 'banner.txt'`.
import std/fmt
import std/io
const {
name: "World"
count: 42
}
std/fmt:fmt.blk @"banner.txt": f |> std/io:print.ln("{{ f:s }}")
Supporting Files
Hello, {{ name:s }}! The answer is {{ count:d }}.Actual
Hello, World! The answer is 42.
Expected output
✓ Zig✓ C#Hello, World! The answer is 42.
Emitted Zig source
// Access compiler flags via the per-user compiler_env module
const CompilerEnv = @import("compiler_env").CompilerEnv;
pub const panic = if (@import("builtin").mode == .Debug)
@import("std").debug.FullPanic(@import("std").debug.defaultPanic)
else
@import("std").debug.simple_panic;
const __koru_bare = struct {
extern fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
extern fn free(ptr: ?*anyopaque) void;
fn bareAlloc(_: *anyopaque, len: usize, alignment: @import("std").mem.Alignment, _: usize) ?[*]u8 {
var p: ?*anyopaque = null;
const a = @max(alignment.toByteUnits(), @sizeOf(usize));
if (posix_memalign(&p, a, len) != 0) return null;
return @ptrCast(p);
}
fn bareResize(_: *anyopaque, _: []u8, _: @import("std").mem.Alignment, _: usize, _: usize) bool { return false; }
fn bareRemap(_: *anyopaque, _: []u8, _: @import("std").mem.Alignment, _: usize, _: usize) ?[*]u8 { return null; }
fn bareFree(_: *anyopaque, memory: []u8, _: @import("std").mem.Alignment, _: usize) void { free(@ptrCast(memory.ptr)); }
const vtable = @import("std").mem.Allocator.VTable{ .alloc = bareAlloc, .resize = bareResize, .remap = bareRemap, .free = bareFree };
const allocator = @import("std").mem.Allocator{ .ptr = undefined, .vtable = &vtable };
};
const __koru_backing = if (@import("builtin").link_libc) @import("std").heap.c_allocator else if (@import("builtin").os.tag == .freestanding and !@import("builtin").cpu.arch.isWasm()) __koru_bare.allocator else @import("std").heap.page_allocator;
var __koru_leak_count: @import("std").atomic.Value(usize) = .init(0);
fn __koru_alloc(ctx: *anyopaque, len: usize, alignment: @import("std").mem.Alignment, ret_addr: usize) ?[*]u8 {
_ = ctx;
const r = __koru_backing.rawAlloc(len, alignment, ret_addr);
if (comptime @import("builtin").mode == .Debug) {
if (r != null) _ = __koru_leak_count.fetchAdd(1, .monotonic);
}
return r;
}
fn __koru_resize(ctx: *anyopaque, memory: []u8, alignment: @import("std").mem.Alignment, new_len: usize, ret_addr: usize) bool {
_ = ctx;
return __koru_backing.rawResize(memory, alignment, new_len, ret_addr);
}
fn __koru_remap(ctx: *anyopaque, memory: []u8, alignment: @import("std").mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 {
_ = ctx;
return __koru_backing.rawRemap(memory, alignment, new_len, ret_addr);
}
fn __koru_free(ctx: *anyopaque, memory: []u8, alignment: @import("std").mem.Alignment, ret_addr: usize) void {
_ = ctx;
__koru_backing.rawFree(memory, alignment, ret_addr);
if (comptime @import("builtin").mode == .Debug) {
_ = __koru_leak_count.fetchSub(1, .monotonic);
}
}
const __koru_vtable = @import("std").mem.Allocator.VTable{ .alloc = __koru_alloc, .resize = __koru_resize, .remap = __koru_remap, .free = __koru_free };
pub fn koru_allocator() @import("std").mem.Allocator {
return .{ .ptr = undefined, .vtable = &__koru_vtable };
}
pub inline fn __koru_intcast(comptime T: type, x: anytype) T {
if (comptime (@import("builtin").mode == .Debug or @import("builtin").mode == .ReleaseSafe))
return @as(T, @intCast(x));
const dst = @typeInfo(T);
const src = @typeInfo(@TypeOf(x));
if (comptime (dst == .int and src == .int and dst.int.bits == src.int.bits and dst.int.signedness != src.int.signedness))
return @as(T, @bitCast(x));
return @as(T, @intCast(x));
}
pub fn koru_leak_check() void {
if (comptime @import("builtin").mode != .Debug) return;
if (__koru_leak_count.load(.acquire) == 0) return;
if (comptime @import("builtin").target.os.tag == .freestanding) {
if (comptime @import("builtin").cpu.arch == .wasm32 or @import("builtin").cpu.arch == .wasm64) {
@panic("KORU LEAK CHECK FAILED: the produced program leaked");
} else {
const __klc = struct { extern var stdout: ?*anyopaque; extern fn fputs(__s: [*:0]const u8, __st: ?*anyopaque) c_int; };
var __lb: [128]u8 = undefined;
const __lm = "KORU LEAK CHECK FAILED: allocations still outstanding at end of run: ";
@memcpy(__lb[0..__lm.len], __lm);
var __ln: usize = __lm.len;
var __lv = __koru_leak_count.load(.acquire);
var __ld: [20]u8 = undefined;
var __lk: usize = 0;
while (__lv > 0) : (__lk += 1) { __ld[__lk] = @intCast('0' + __lv % 10); __lv /= 10; }
for (0..__lk) |__li| { __lb[__ln] = __ld[__lk - 1 - __li]; __ln += 1; }
__lb[__ln] = '\n'; __ln += 1; __lb[__ln] = 0;
_ = __klc.fputs(@as([*:0]const u8, @ptrCast(&__lb)), __klc.stdout);
@trap();
}
} else {
@import("std").debug.print("KORU LEAK CHECK FAILED: the produced program leaked (trace above)\n", .{});
@import("std").process.exit(1);
}
}
pub const main_module = struct {
//@koru:inline_stmt
const name = "World";
const count = 42;
// >>> FLOW: tests/regression/600_STDLIB/620_FMT/620_008_fmt_blk_file_source_bare/input.k:15 ~std.fmt:fmt.blk_impl()
pub fn flow0() void {
const f = __koru_inline_0__: {
const __fmt_alloc = koru_allocator();
const __fmt_text = @import("std").fmt.allocPrint(__fmt_alloc, "Hello, {s}! The answer is {d}.", .{name, count}) catch unreachable;
break :__koru_inline_0__ __fmt_text;
};
(struct { fn __kout(__fd: i32, __b: []const u8) void { if (@import("builtin").os.tag == .freestanding) { const __kc = struct { extern var stdout: ?*anyopaque; extern var stderr: ?*anyopaque; extern fn fputs(__s: [*:0]const u8, __st: ?*anyopaque) c_int; }; var __kt: [4096]u8 = undefined; for (0..(__b.len + __kt.len - 2) / (__kt.len - 1)) |__ki| { const __kn = @min(__kt.len - 1, __b.len - __ki * (__kt.len - 1)); @memcpy(__kt[0..__kn], __b[__ki * (__kt.len - 1)..][0..__kn]); __kt[__kn] = 0; @import("std").mem.doNotOptimizeAway(__kc.fputs(@as([*:0]const u8, @ptrCast(&__kt)), if (__fd == 2) __kc.stderr else __kc.stdout)); } } else { @import("std").mem.doNotOptimizeAway(@import("std").posix.write(__fd, __b) catch @as(usize, 0)); } } fn __kw(comptime __f: []const u8, __a: anytype) void { var __kb: [65536]u8 = undefined; const __ks = @import("std").fmt.bufPrint(&__kb, __f, __a) catch __kb[0..0]; __kout(1, __ks); } }).__kw("{s}\n", .{f});
_ = koru_std.koru_io.free_event.handler(.{ .content = f });
}
pub fn koru_start_flow() void {
const result_0 = koru_koru.start_event.handler(.{ });
const result_0_done = result_0.done;
_ = &result_0_done;
}
pub fn koru_end_flow() void {
const result_0 = koru_koru.end_event.handler(.{ });
const result_0_done = result_0.done;
_ = &result_0_done;
}
};
pub const koru_std = struct {
pub const koru_io = struct {
const std = @import("std");
const codegen_utils_io = @import("codegen_utils");
var readln_buf: [8192]u8 = undefined;
fn __appendFmtLiteralByte(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, byte: u8) void {
if (byte == '{' or byte == '}') buf.append(allocator, byte) catch unreachable;
buf.append(allocator, byte) catch unreachable;
}
const KORU_OUT_UNESCAPED: []const u8 =
"fn __kout(__fd: i32, __b: []const u8) void { " ++
"if (@import(\"builtin\").os.tag == .freestanding) { " ++
"const __kc = struct { extern var stdout: ?*anyopaque; extern var stderr: ?*anyopaque; " ++
"extern fn fputs(__s: [*:0]const u8, __st: ?*anyopaque) c_int; }; " ++
"var __kt: [4096]u8 = undefined; " ++
"for (0..(__b.len + __kt.len - 2) / (__kt.len - 1)) |__ki| { const __kn = @min(__kt.len - 1, __b.len - __ki * (__kt.len - 1)); " ++
"@memcpy(__kt[0..__kn], __b[__ki * (__kt.len - 1)..][0..__kn]); __kt[__kn] = 0; " ++
"@import(\"std\").mem.doNotOptimizeAway(__kc.fputs(@as([*:0]const u8, @ptrCast(&__kt)), " ++
"if (__fd == 2) __kc.stderr else __kc.stdout)); } " ++
"} else { @import(\"std\").mem.doNotOptimizeAway(@import(\"std\").posix.write(__fd, __b) catch @as(usize, 0)); } } ";
fn __doubleBraces(comptime s: []const u8) []const u8 {
comptime {
var out: []const u8 = "";
for (s) |c| {
out = out ++ switch (c) {
'{' => "{{",
'}' => "}}",
else => &[_]u8{c},
};
}
return out;
}
}
const KORU_OUT_FN: []const u8 = __doubleBraces(KORU_OUT_UNESCAPED);
fn __printInterpolate(
expr: []const u8,
item: anytype,
rep: anytype,
allocator: std.mem.Allocator,
comptime with_newline: bool,
comptime label: []const u8,
to_fd: u8,
) @import("ast").SiteResult {
const ast = @import("ast");
const isZigKeyword = struct {
fn check(word: []const u8) bool {
const keywords = [_][]const u8{
"error", "type", "async", "await", "suspend", "resume",
"try", "catch", "if", "else", "switch", "while",
"for", "break", "continue", "return", "defer", "errdefer",
"test", "pub", "export", "extern", "packed", "inline",
"noinline", "comptime", "nosuspend", "volatile", "allowzero",
"align", "linksection", "callconv", "noalias",
"struct", "enum", "union", "opaque", "fn", "const",
"var", "anyframe", "anytype", "anyerror", "unreachable",
"undef", "null", "true", "false", "and", "or",
"orelse", "threadlocal",
};
for (keywords) |kw| {
if (std.mem.eql(u8, word, kw)) return true;
}
const primitives = [_][]const u8{
"bool", "void", "noreturn", "anyopaque",
"usize", "isize", "f16", "f32",
"f64", "f80", "f128", "undefined",
"comptime_int", "comptime_float", "c_char",
"c_short", "c_ushort", "c_int", "c_uint",
"c_long", "c_ulong", "c_longlong",
"c_ulonglong", "c_longdouble",
};
for (primitives) |p| {
if (std.mem.eql(u8, word, p)) return true;
}
if (word.len >= 2 and (word[0] == 'u' or word[0] == 'i')) {
var all_digits = true;
for (word[1..]) |c| {
if (c < '0' or c > '9') all_digits = false;
}
if (all_digits) return true;
}
return false;
}
}.check;
const appendEscapedPath = struct {
fn append(buf: *std.ArrayList(u8), alloc: std.mem.Allocator, path: []const u8) void {
var start: usize = 0;
var pos: usize = 0;
var is_first = true;
while (pos <= path.len) {
if (pos == path.len or path[pos] == '.') {
const segment = path[start..pos];
if (!is_first) {
buf.append(alloc, '.') catch unreachable;
if (isZigKeyword(segment)) {
buf.appendSlice(alloc, "@\"") catch unreachable;
buf.appendSlice(alloc, segment) catch unreachable;
buf.append(alloc, '"') catch unreachable;
} else {
buf.appendSlice(alloc, segment) catch unreachable;
}
} else if (isZigKeyword(segment)) {
buf.appendSlice(alloc, "@\"") catch unreachable;
buf.appendSlice(alloc, segment) catch unreachable;
buf.append(alloc, '"') catch unreachable;
} else {
buf.appendSlice(alloc, segment) catch unreachable;
}
is_first = false;
start = pos + 1;
}
pos += 1;
}
}
}.append;
const flow = if (item.* == .flow)
&item.flow
else
return .{};
var format_buf = std.ArrayList(u8).initCapacity(allocator, 128) catch unreachable;
var args_buf = std.ArrayList(u8).initCapacity(allocator, 64) catch unreachable;
var i: usize = 0;
var first_arg = true;
var missing_spec: ?[]const u8 = null;
var function_call_expr: ?[]const u8 = null;
var keyed_placeholder: ?[]const u8 = null;
const expr_parser = @import("expression_parser");
const is_string_literal = expr.len > 0 and expr[0] == '"';
const start: usize = if (is_string_literal) 1 else 0;
const end: usize = if (is_string_literal and expr[expr.len - 1] == '"') expr.len - 1 else expr.len;
const raw_content = expr[start..end];
const content = if (!is_string_literal and raw_content.len > 0) blk: {
const has_format_spec = std.mem.indexOf(u8, raw_content, ":") != null;
const suffix = if (has_format_spec) " }}" else ":s }}";
var wrapped = std.ArrayList(u8).initCapacity(allocator, raw_content.len + 8) catch unreachable;
wrapped.appendSlice(allocator, "{{ ") catch unreachable;
wrapped.appendSlice(allocator, raw_content) catch unreachable;
wrapped.appendSlice(allocator, suffix) catch unreachable;
break :blk wrapped.items;
} else raw_content;
while (i < content.len) {
if (i + 1 < content.len and content[i] == '{' and content[i + 1] == '%') {
const tag_start = i + 2;
var ws_start = tag_start;
while (ws_start < content.len and (content[ws_start] == ' ' or content[ws_start] == '\t')) : (ws_start += 1) {}
if (ws_start + 3 <= content.len and std.mem.eql(u8, content[ws_start..ws_start + 3], "if ")) {
const var_start = ws_start + 3;
var var_pos = var_start;
while (var_pos < content.len and (content[var_pos] == ' ' or content[var_pos] == '\t')) : (var_pos += 1) {}
var var_end = var_pos;
while (var_end < content.len and content[var_end] != ' ' and content[var_end] != '\t' and content[var_end] != '%') : (var_end += 1) {}
const cond_var = content[var_pos..var_end];
var tag_end = var_end;
while (tag_end + 1 < content.len and !(content[tag_end] == '%' and content[tag_end + 1] == '}')) : (tag_end += 1) {}
if (tag_end + 1 < content.len) {
const body_start = tag_end + 2;
const endif_marker = "{% endif %}";
if (std.mem.indexOf(u8, content[body_start..], endif_marker)) |endif_offset| {
const body_end = body_start + endif_offset;
const body_content = content[body_start..body_end];
format_buf.appendSlice(allocator, "{s}") catch unreachable;
if (!first_arg) {
args_buf.appendSlice(allocator, ", ") catch unreachable;
}
args_buf.appendSlice(allocator, "if (") catch unreachable;
appendEscapedPath(&args_buf, allocator, cond_var);
args_buf.appendSlice(allocator, ") \"") catch unreachable;
for (body_content) |c| {
switch (c) {
'"' => args_buf.appendSlice(allocator, "\\\"") catch unreachable,
'\\' => args_buf.appendSlice(allocator, "\\\\") catch unreachable,
'\n' => args_buf.appendSlice(allocator, "\\n") catch unreachable,
'\r' => args_buf.appendSlice(allocator, "\\r") catch unreachable,
'\t' => args_buf.appendSlice(allocator, "\\t") catch unreachable,
else => args_buf.append(allocator, c) catch unreachable,
}
}
args_buf.appendSlice(allocator, "\" else \"\"") catch unreachable;
first_arg = false;
i = body_end + endif_marker.len;
continue;
}
}
}
__appendFmtLiteralByte(&format_buf, allocator, content[i]);
i += 1;
}
else if (i + 1 < content.len and content[i] == '{' and content[i + 1] == '{') {
const placeholder_start = i + 2;
var ws_start = placeholder_start;
while (ws_start < content.len and (content[ws_start] == ' ' or content[ws_start] == '\t')) : (ws_start += 1) {}
var j = ws_start;
while (j + 1 < content.len and !(content[j] == '}' and content[j + 1] == '}')) : (j += 1) {}
if (j + 1 < content.len) {
var ws_end = j;
while (ws_end > ws_start and (content[ws_end - 1] == ' ' or content[ws_end - 1] == '\t')) : (ws_end -= 1) {}
const placeholder = content[ws_start..ws_end];
var var_name: []const u8 = placeholder;
var format_spec: []const u8 = "any";
var has_spec = false;
if (keyed_placeholder == null and codegen_utils_io.colonInsideBrackets(placeholder)) {
keyed_placeholder = placeholder;
}
if (std.mem.indexOf(u8, placeholder, ":")) |colon_pos| {
var_name = placeholder[0..colon_pos];
format_spec = placeholder[colon_pos + 1..];
has_spec = true;
}
if (function_call_expr == null) {
var parser = expr_parser.ExpressionParser.init(allocator, var_name);
defer parser.deinit();
if (parser.parse()) |parsed_expr| {
if (expr_parser.containsUserFunctionCall(parsed_expr)) {
function_call_expr = var_name;
}
} else |_| {
}
}
if (!has_spec and missing_spec == null) {
missing_spec = placeholder;
... [truncated - 47KB total]Emitted C# source
static class main_module {
public static void __koru_stdout_write(object s) => global::System.Console.Out.Write(s);
public static void __koru_stderr_write(object s) => global::System.Console.Error.Write(s);
// The mutable handle carrier — `*String`-style resources are
// `new __KoruBox { data = … }` because C# anonymous types are
// read-only: `s.data = …` (std/string append/clear, handle
// mutation generally) needs a settable member. `object`, not
// `dynamic`: the field is storage — every `x.data` read reaches
// it through a dynamic-typed handle (`*T` Input fields, the
// `dynamic` borrow locals below), so the member itself only
// needs to hold the value, and `object` keeps the DLR out of
// the store/load path.
public class __KoruBox { public object data; }
// Textification for `{{ … }}` operands: C# bool ToStrings as
// `True` where Koru prints `true`, and the operand's static type
// is unknown at this boundary — a `(x) is bool` inline test would
// be a compile error on statically-typed operands instead. Generic
// on purpose: `dynamic` boxed every value-type operand — measured
// ~1s/10M elements on 012_threat_scanner — while T specializes to
// the operand's own ToString() with no box.
public static string __koru_str<T>(T v) => v is bool b ? (b ? "true" : "false") : v?.ToString();
public static readonly dynamic name = "World";
public static readonly dynamic count = 42;
public static class std_io_free_event {
public struct Input {
public string content;
}
public static object handler(Input __koru_input) {
var content = __koru_input.content;
// The host owns memory — a Koru string is a managed C# string and the
// GC settles the `allocated!` debt. Empty by construction.
return default;
}
}
public static class std_declarations_const_event {
public struct Input {
public dynamic source;
}
public static object handler(Input __koru_input) {
var source = __koru_input.source;
throw new global::System.Exception("const: |template| proc is inlined at call sites and must never be called");
}
}
public static class koru_start_event {
public struct Input {
}
public struct Output {
public string tag;
public object done;
}
public static Output handler(Input __koru_input) => new Output { tag = "done" };
}
public static class koru_end_event {
public struct Input {
}
public struct Output {
public string tag;
public object done;
}
public static Output handler(Input __koru_input) => new Output { tag = "done" };
}
public static void flow0() {
var f = $"Hello, {__koru_str(name)}! The answer is {(count)}.";
__koru_stdout_write("" + __koru_str(f) + "\n");
{
var __koru_p_content = (string)(f);
// The host owns memory — a Koru string is a managed C# string and the
// GC settles the `allocated!` debt. Empty by construction.
}
}
public static void flow1() {
main_module.koru_start_event.handler(new koru_start_event.Input { });
}
public static void flow2() {
main_module.koru_end_event.handler(new koru_end_event.Input { });
}
}
static class Program {
static void Main() {
main_module.flow1();
main_module.flow0();
main_module.flow2();
}
}
Flows
flow ~const click a branch to expand · @labels scroll to their anchor
const (source: name: "World"
count: 42)
flow ~fmt.blk click a branch to expand · @labels scroll to their anchor
fmt.blk (source: Hello, {{ name:s }}! The answer is {{ count:d }}.)
Test Configuration
MUST_RUN LANGUAGES: zig cs