// fmt — formatting writers. Goes through os.write to a file // descriptor. Hare's variadic call-site sugar (`fmt::println(42)` // gathering args into a `[]formattable`) isn't wired yet; until then, // callers either: // // 1. Hand-build the slice: // let args: [2]formattable; // args[0] = 42i64: formattable; // args[1] = " hi": formattable; // fmt.print(args[0:2]); // // 2. Compose a single str via strconv.i64tos / strings.concat: // fmt.println(strconv.i64tos(42, strconv.base.DEC)); // // `print(s: str)` keeps the single-string form for the common case. use os; use strconv; use strings; // formattable — tagged union of types fmt can render. Mirrors // Hare's `fmt::formattable = (...types::numeric | uintptr | str | // rune | bool | nullable *opaque | void)`, narrowed to the set ww // actually has codegen for. Slot size is 24B (8 tag + 16 str // payload). export type formattable = (i64 | str | bool | rune); // vprint — write the formatted form of each element of `args` to // `fd`. Returns total bytes written or the first negative os.write // result. fn vprint(fd: i32, args: []formattable) i64 = { let total: i64 = 0; let i: i32 = 0; for (i < args.len) { match (args[i]) { case let n: i64 => { let s: str = strconv.i64tos(n, strconv.base.DEC); let r: i64 = os.write(fd, s.ptr, s.len: u64); if (r < 0) { return r; }; total += r; }; case let s: str => { let r: i64 = os.write(fd, s.ptr, s.len: u64); if (r < 0) { return r; }; total += r; }; case let b: bool => { let s: str = "false"; if (b) { s = "true"; }; let r: i64 = os.write(fd, s.ptr, s.len: u64); if (r < 0) { return r; }; total += r; }; case let r: rune => { let buf: [4]u8; buf[0] = r: u8; let n: i64 = os.write(fd, &buf[0], 1u64); if (n < 0) { return n; }; total += n; }; }; i += 1; }; return total; }; // print(s: str) — single-string form for the common case. The // variadic-style `print(args: []formattable)` lives as `printv` // until call-site sugar lands. export fn print(s: str) i64 = { return os.write(1, s.ptr, s.len: u64); }; // printv — Hare-shaped `print(args: formattable...)` modulo the // call-site sugar. Callers pass an explicit `[]formattable` slice. export fn printv(args: []formattable) i64 = { return vprint(1, args); }; export fn println(s: str) i64 = { let n: i64 = os.write(1, s.ptr, s.len: u64); if (n < 0) { return n; }; let m: i64 = os.write(1, "\n".ptr, 1u64); if (m < 0) { return m; }; return n + m; }; // printlnv — like printv but adds a trailing newline. export fn printlnv(args: []formattable) i64 = { let n: i64 = vprint(1, args); if (n < 0) { return n; }; let m: i64 = os.write(1, "\n".ptr, 1u64); if (m < 0) { return m; }; return n + m; }; // errorln — write a message to stderr with a trailing newline. export fn errorln(s: str) i64 = { let n: i64 = os.write(2, s.ptr, s.len: u64); if (n < 0) { return n; }; let m: i64 = os.write(2, "\n".ptr, 1u64); if (m < 0) { return m; }; return n + m; }; // fprint / fprintln — same as print/println but on an arbitrary fd. // Used by the compiler to write to its -o output file. export fn fprint(fd: i32, s: str) i64 = { return os.write(fd, s.ptr, s.len: u64); }; export fn fprintln(fd: i32, s: str) i64 = { let n: i64 = os.write(fd, s.ptr, s.len: u64); if (n < 0) { return n; }; let m: i64 = os.write(fd, "\n".ptr, 1u64); if (m < 0) { return m; }; return n + m; };