Leivos Logo LeivOS Buy
Documentation · Engineering

Tape.

A small language with a dual backend 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;
}
Dual backend, one source

Interpret it or compile it to native code.

The same Tape source compiles to a linear three-address-code IR and runs through either backend. Differential tests assert both produce identical results.

VM interpreter

Compiles source to TAC bytecode and interprets it. Boots in microseconds. Used for scripting, the REPL, and inside the kernel.

Native AOT

Compiles the same TAC IR directly to x86-64 machine code. Tape ships its own ELF and PE writers — no LLVM, no Cranelift, no external linker.

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. ?T optionals make null-handling explicit. No borrow checker — ownership is move-by-default with compiler-inserted drops at scope exit.

struct Point {
  x: i32;
  y: i32;
}

fn distance_sq(a: *const Point, b: *const Point) -> i32 {
  let dx: i32 = b.x - a.x;
  let dy: i32 = b.y - a.y;
  return dx*dx + dy*dy;
}

Standard library

The standard library is enough. 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
...
many others for networking, cryptography, file formats

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
> var xs: [3]i64 = [10, 20, 30];
> xs[1] * 2
40
Build artifacts

One source. Two build modes.

.tb

Bytecode bundle

Compact bytecode-encoded TAC. Run with tape run. Distributable without source.

.exe / ELF

Native executable

Self-contained x86-64 binary. PE for Windows, ELF for Uusi. Tape's own emitters; no external 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. Tape has no closures — typed events and function pointers cover callbacks explicitly.
  • Not a generics language. Compile-time code execution (@tape ) replaces generics entirely.
  • Not a Tape-only world. Tape interoperates with C at library boundaries via platform-ABI trampolines.

For developers and integrators evaluating LeivOS: Tape example sources are available with your Pro license.

For the full language specification, design decisions, and standalone usage outside LeivOS, visit tapelang.org.

Read more

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