Tape.
A small language with three runtimes from one source. Tape is how LeivOS scripts itself, automates itself, and — in large part — how the Uusi kernel is written.
Tape is the language we built for LeivOS. It is not a general-purpose ecosystem play; it is a tool. It exists because we wanted scripting and code generation inside the operating system without dragging in someone else's runtime, and because we wanted to write large parts of the kernel in something safer than C without giving up speed.
The Uusi kernel is written in Assembly (the early boot path and a handful of CPU primitives), C (the parts that need to live close to the metal), and Tape (the rest, and increasingly more of it). Tape's freestanding profile — the kernel profile — has no allocator and no host calls, so the same compiler that builds LeivOS application scripts also produces kernel-side code.
A complete Tape file.
Tape's surface is intentionally small: functions, locals, structs, conditionals, loops, imports. No surprises.
@profile(t1);
import io from "io";
import string from "string";
fn greet(who: string) {
io.print("hello ");
io.println(who);
}
fn main() -> i32 {
greet("world");
return 0;
} Interpret it, JIT it, or compile it to native code.
The same Tape source compiles to bytecode and runs through one of three back-ends. Differential tests assert all three produce bit-for-bit identical results.
Interpreter
Bytecode dispatch in C. Boots in microseconds. Embedded everywhere — including the kernel.
JIT
On first call, a Tape function is lowered to native x86_64 machine code. Function-by-function. Falls back to the interpreter for anything outside the supported subset.
AOT
Compile-time native code generation. Tape ships its own COFF / PE writer — a Tape program can produce a self-contained 1.5 KB Windows .exe with no clang and no runtime.
Profiles
Every Tape file declares a profile at the top. Profiles gate features by trust level — smaller profiles get smaller code.
Freestanding
No allocator, no host calls. Used inside the Uusi kernel itself.
Typed userspace
Static types, native callable. The everyday profile for system glue and applications.
Dynamic / scripting
Adds the `any` type, top-level statements, and full REPL-style scripting.
Static where it pays off.
Tape has integers (i8..u64),
floats (f32, f64),
bool,
string, structs, slices, fixed arrays, pointers,
and optionals. No implicit narrowing. No silent coercions between integer and float.
Pointer constness and non-null are compile-time attributes. *const T
forbids writes; *!T forbids null. The
typechecker also rejects cross-lifetime mistakes — for instance, storing
&local in a global, or returning the address
of a stack value.
struct Point {
x: i32;
y: i32;
}
fn distance_sq(a: *const Point, b: *const Point) -> i32 {
let dx = b.x - a.x;
let dy = b.y - a.y;
return dx*dx + dy*dy;
} Standard library
The v1 standard library is small on purpose. Three modules cover the everyday cases.
- io
- print, println, print_i64, print_u64, print_f64, read_line
- string
- len, eq, concat, slice (UTF-8 boundary checked), from_i64, from_u64, parse_i64
- dyn
- type_name, to_string, print, println — dynamic value formatting
Larger libraries — net, fs, gfx — are exposed through the LeivOS UDSO surface and called from Tape via the same import syntax.
Tape REPL.
Run tape repl to evaluate Tape lines
interactively. Each line is wrapped in a fresh @profile(t2)
context, so a bare expression prints its value and a statement runs for its side effect.
A malformed line surfaces a parse error pointing at the column it failed on. The REPL keeps going.
> 1 + 2
3
> "hi"
hi
> let xs = [10, 20, 30];
> xs[1] * 2
40 One source. Three persistent artifacts.
Portable bytecode
Tiny — about 140 bytes for "hello world." Run with tape run.
COFF object
Linkable with clang against a tiny Tape runtime, so existing toolchains can consume Tape output.
Standalone PE
Self-contained Windows console binary, ~1.5 KB. Tape's own PE writer; no linker required.
What Tape is not
- Not a package-manager ecosystem. Tape ships with a small standard library and a fixed surface.
- Not a closure language. v1 has no closures and no garbage collector beyond explicit reference counting.
- Not concurrent. Threads and futures are out of v1; cooperative event loops are the supported model.
- Not a Tape-only world. Tape interoperates with C through the LeivOS UDSO ABI for the cases where that's needed.
For developers and integrators evaluating LeivOS: Tape is sources-available with your Pro
license. The grammar and value layout are documented in tree under
docs/tape_grammar.md and
docs/tape_layout.md.