LeivOS Buy
Documentation · Engineering

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 small program

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;
}
Three runtimes, one source

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.

@profile
t0

Freestanding

No allocator, no host calls. Used inside the Uusi kernel itself.

@profile
t1

Typed userspace

Static types, native callable. The everyday profile for system glue and applications.

@profile
t2

Dynamic / scripting

Adds the `any` type, top-level statements, and full REPL-style scripting.

The type system

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.

Interactive

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
Build artifacts

One source. Three persistent artifacts.

.tb

Portable bytecode

Tiny — about 140 bytes for "hello world." Run with tape run.

.obj

COFF object

Linkable with clang against a tiny Tape runtime, so existing toolchains can consume Tape output.

.exe

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.

Read more

The development blog covers Tape's design and milestones in detail.