Cheatsheet

Quick reference for writing tape code. Tape is a compiled language with dual targets (VM interpreter + native x86-64), three strictness profiles, and a built-in component model.

Comments

tape
// Line comment

/* Block comment */

/* Block comments nest:
   /* inner comment */
   still inside outer
*/

Profiles

tape
@profile(t0);  // freestanding: no GC, no heap, kernel code
@profile(t1);  // typed application: explicit memory, exe/DLL
@profile(t2);  // scripting: optional types, GC available (default)
  • t0 can only import t0
  • t1 can import t1, t0
  • t2 can import t2, t1, t0

Variables & Constants

tape
let x: i64 = 42;          // immutable
var y: i64 = 0;           // mutable
let z = 42;               // type inferred
var name: string;          // zero-initialized

const MAX: i64 = 1024;    // compile-time constant

Types

TypeDescription
i8 i16 i32 i64Signed integers
u8 u16 u32 u64Unsigned integers
f32 f64Floats
boolBoolean
stringUTF-8 owned string (t1/t2)
[]const u8Byte slice (t0 strings)
*TMutable pointer
*const TImmutable pointer
*!TNon-null pointer
?TOptional
[]T []const TSlices
[N]TFixed-size array
fn(T) -> RFunction pointer
anyDynamic type (t2 only)

Functions

tape
fn add(a: i64, b: i64) -> i64 {
    return a + b;
}

fn greet(name: string, loud: bool = false) { }  // default params

// Named arguments — skip middle defaults:
fn create_window(title: string, width: i64 = 800, height: i64 = 600, vsync: bool = true) -> Window { }
create_window("App", height: 400);              // skip width, keep default
create_window("App", vsync: false);             // skip width and height
create_window("App", height: 400, width: 1024); // named, any order

pub fn exported() -> i64 { return 42; }         // visible to importers

// Methods
struct Vec2 { x: f64; y: f64; }
fn Vec2.length(*self) -> f64 {
    return math.sqrt(self.x * self.x + self.y * self.y);
}
fn Vec2.scale(self, factor: f64) -> Vec2 {       // by value
    return Vec2 { x: self.x * factor; y: self.y * factor; };
}

Operator Overloading

tape
fn Vec2.op_add(self, other: Vec2) -> Vec2 { ... }
fn Vec2.op_sub(self, other: Vec2) -> Vec2 { ... }
fn Vec2.op_mul(self, other: Vec2) -> Vec2 { ... }
fn Vec2.op_neg(self) -> Vec2 { ... }
fn Vec2.op_eq(self, other: Vec2) -> bool { ... }   // != auto-derived
fn Vec2.op_lt(self, other: Vec2) -> bool { ... }

Structs

tape
struct Point { x: f64; y: f64; }
let p = Point { x: 1.0; y: 2.0; };

@packed
struct Header { magic: u32; len: u16; flags: u8; }

@align(16)
struct SimdVec { data: [4]f32; }

@opaque
struct Handle { id: u64; }  // fields hidden outside module

Enums

tape
enum Direction : u8 { North = 0; East = 1; South = 2; West = 3; }

enum HttpErr : u16 {
    NotFound = 404: "not found";
    ServerError = 500: "internal server error";
}
let msg = HttpErr.desc(HttpErr.NotFound);  // "not found"

Tagged Unions

tape
tagged Shape {
    Circle { radius: f64 }
    Rect { width: f64; height: f64 }
    Point;
}

fn area(s: Shape) -> f64 {
    match (s) {
        Shape.Circle { radius } => { return 3.14159 * radius * radius; }
        Shape.Rect { width; height } => { return width * height; }
        Shape.Point => { return 0.0; }
    }
}

Untagged Unions (t0/t1)

tape
union Register { i: i64; f: f64; bytes: [8]u8; }

Control Flow

tape
if (x > 0) { } else if (x == 0) { } else { }

while (i < 10) { i = i + 1; }

for (i in 0..10) { }          // exclusive range
for (i in 0..=9) { }          // inclusive range
for (item in items) { }       // slice/array iteration
for (val in iterator) { }     // anything with .next() -> ?T

match (value) {
    Pattern => { }
    _ => { }                       // wildcard catch-all
}

// Match works with both tagged unions and enums:
match (dir) {
    Direction.North => { }
    Direction.East => { }
    _ => { }
}

break;
continue;

Optionals

tape
let maybe: ?i64 = null;
let found: ?i64 = 42;

if (maybe != null) { io.print_i64(maybe!); }  // unwrap with !
let val = maybe or { 0 };                      // default value

Error Handling

tape
enum ParseErr : u8 { BadInput = 1: "invalid input"; }

fn parse(s: string) -> i64 or ParseErr {
    if (bad) { return ParseErr.BadInput; }
    return 42;
}

// Propagate to caller:
let val = parse(input) or return;

// Handle inline:
let val = parse(input) or {
    io.println(ParseErr.desc(err));
    return 1;
};

Defer

tape
let buf = mem.alloc(4096);
defer mem.free(buf, 4096);          // runs at scope exit
errdefer mem.free(buf, 4096);       // runs only if error returned

Imports & Modules

tape
import io from "io";                           // stdlib
import utils from "./utils.tape";              // relative
import { println, read_line } from "io";       // selective (no prefix needed)
import { Vec3, make_vec } from "./veclib";     // selective

io.println("qualified");     // module prefix
println("unqualified");      // selective import

Visibility

tape
pub fn api() -> i64 { return 42; }
fn internal() { }

pub {
    fn increment() { }
    fn decrement() { }
    var count: i64 = 0;
}

Operators

tape
+ - * / %                    // arithmetic
& | ^ ~ << >>               // bitwise
== != < <= > >=             // comparison
&& || !                     // logical
+= -= *= /= %= &= |= ^= <<= >>=  // compound assignment
|>                          // pipe (left value → first arg of right fn)
as                          // type cast
is                          // type/constraint check
..                          // range

Precedence (high to low): postfix (. [] () !) → cast (as is) → unary (- ! & * ~) → mul → add → shift → bitwise → comparison → logical → pipe → assignment.

Prefix operators bind tighter than as/is:

tape
&x as *u8      // (&x) as *u8 — not &(x as *u8)
*ptr as i64    // (*ptr) as i64

Pipe Operator

tape
let result = data |> parse() |> validate() |> transform();
// equivalent to: transform(validate(parse(data)))

Strings

tape
let msg = "Hello, {name}!";           // interpolation
let escaped = "line1\nline2\ttab";    // escape sequences: \n \t \r \\ \" \0 \xHH
let braces = "\{literal\}";           // \{ and \} for literal braces
let raw: []const u8 = "kernel msg";   // t0: byte slice

// Triple-quoted — multi-line, can contain ", escapes + interpolation active:
let html = """
<div class="main">
    <p>{greeting}</p>
</div>
""";

// Raw strings — no escapes, no interpolation:
let json = r"""{"key": "value", "count": 42}""";

Components

tape
component Button {
    prop label: string;              // input from parent
    prop size: i64 = 48;            // with default
    var count: i64 = 0;             // mutable reactive state
    state hovered: bool = false;    // interaction state (for #style)
    event on_click();               // event declaration
    slot content;                   // child content slot

    fn handle_pointer(ev: *ui.PointerEvent) {
        if (ev.kind == ui.PointerKind.Up) {
            fire on_click();         // fire event
        }
    }

    view {
        widgets.Panel { bg: #336699;
            widgets.Label { text: label; }
        }
    }
}

// Instantiation:
Button { label: "Save"; on_click: save_file; }

Events

tape
event on_click();                    // zero-arg
event on_value(val: i64);           // typed

fire on_click();                     // call bound handler
fire on_value(42);                   // with argument

// Parent binds:
Button { label: "Go"; on_click: my_handler; }

Slots

tape
component Card {
    slot header;
    slot content;
    view {
        ui.Column { header; content; }
    }
}

Card {
    slot header { widgets.Label { text: "Title"; } };
    slot content { MyForm {} };
}

Dispatch (vtable methods)

tape
component Panel {
    @tape { ui.drawable(); }
    fn paint(ctx: *u8, x: i32, y: i32, w: i32, h: i32) { }
    fn measure(w: i32, h: i32) -> ui.Size { }
}

// Constraint type:
type Drawable = *component[@dispatch fn paint(...); @dispatch fn measure(...)];
fn render(widget: Drawable) { widget.paint(ctx, 0, 0, 100, 100); }

Regions

tape
#code           // default: standard tape logic
#view           // component declarations with view trees
#style          // CSS-like component styling
#test           // inline test cases (only during `tape test`)
#resource       // embedded assets (icon, image, font, sound, binary)
#localization   // translatable strings (@t("..."))
#bytecode       // inline assembly (t0 only)

#test

tape
#test
test "math works" {
    @assert(2 + 2 == 4);
}

test "function works" {
    let result = my_fn(10);
    @assert(result == 42);
}

Metaprogramming (@tape)

tape
// Compile-time function:
@tape fn gen_vec(T: type) {
    @emit struct Vec_${T} { data: *${T}; len: i64; cap: i64; }
    @emit fn vec_${T}_push(v: *Vec_${T}, item: ${T}) { }
}
@tape { gen_vec(i64); }

// Compile-time constants:
@tape const TABLE: [256]u32 = { /* computed at compile time */ };
@tape const SHADER: []const u8 = @embed("blur.glsl");

// Reflection:
@tape fn print_info(T: type) {
    var info = @typeof(T);
    comptime for (field in info.fields) {
        @println("  {field.name}: size={field.size}");
    }
}

// Comptime match:
comptime match(T) {
    i64, i32 => { @emit const DEFAULT = 0; }
    f64      => { @emit const DEFAULT = 0.0; }
    _        => { @compile_error("unsupported"); }
}

// Intrinsics:
@sizeof(T)  @alignof(T)  @typeof(T)  @assert(cond)
@has_field(T, "name")  @has_method(T, "name")
@embed("path")  @compile_error("msg")

refactor() Blocks

Virtual module boundary — compiler validates, tape refactor materializes:

tape
import io from "io";
import math from "math";

fn main() { io.println("{distance(3.0, 4.0)}"); }

refactor("./geom.tape") {
    fn distance(x: f64, y: f64) -> f64 {
        return math.sqrt(x*x + y*y);
    }
}

After tape refactor main.tape:

  • geom.tape created with pub { fn distance(...) { } } + only needed imports
  • main.tape rewritten with import { distance } from "./geom.tape";

C FFI

tape
@link("kernel32");
extern fn ExitProcess(code: u32);

@link("mylib");
extern("actual_name") fn tape_name(x: i64) -> i64;

@export
pub fn callable_from_c() -> i32 { return 0; }

Platform-Specific Code

tape
@tape {
    if (TARGET == "win64") {
        @emit fn platform_init() { /* windows */ }
    } else if (TARGET == "uusi") {
        @emit fn platform_init() { /* uusi kernel */ }
    }
}

Memory (t0/t1)

tape
import mem from "mem";

let buf: *u8 = mem.alloc(4096);
defer mem.free(buf, 4096);

mem.copy(dst, src, count);
mem.zero(ptr, count);
mem.set(ptr, 0xFF, count);

Ownership rules:

  • Managed types (string, components) freed at scope exit
  • Assignment is deep copy for managed types
  • Function params are borrowed (caller retains ownership)
  • Return transfers ownership to caller
  • Raw pointers (*T) are unmanaged — you handle lifetime

Concurrency (threads)

tape
thread ImageProcessor {
    @pool(1, 4);                         // min 1, max 4 threads

    fn resize(img: Image, w: i64, h: i64) -> Image { }
}

// Non-blocking call with callback:
ImageProcessor.resize(photo, 800, 600) -> on_done;
fn on_done(result: Image) { display.set(result); }

// Blocking call (from another thread):
let result = ImageProcessor.resize(photo, 800, 600);

CLI

bash
tape build app.tape -o app.exe           # compile to native
tape build app.tape -o app --target uusi # cross-compile
tape run script.tape                     # interpret via VM
tape check app.tape                      # typecheck only
tape test                                # run #test regions
tape refactor app.tape                   # materialize refactor blocks
tape refactor app.tape --dry-run         # preview
tape repl                                # interactive REPL

Key Design Rules

  • No generics — use @tape fn gen(T: type) + @emit instead
  • No closures — use function pointers + typed events
  • No exceptions — use T or E error returns
  • No async/await — use thread declarations
  • No inheritance — use composition (slots, events, dispatch constraints)
  • No GC in t0/t1 — explicit memory
  • No glob imports (import *) — always list symbols explicitly
  • pub {} groups exports; no “default public” for modules
  • Every feature must work in both VM and native backends