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 constantTypes
| Type | Description |
|---|---|
i8 i16 i32 i64 | Signed integers |
u8 u16 u32 u64 | Unsigned integers |
f32 f64 | Floats |
bool | Boolean |
string | UTF-8 owned string (t1/t2) |
[]const u8 | Byte slice (t0 strings) |
*T | Mutable pointer |
*const T | Immutable pointer |
*!T | Non-null pointer |
?T | Optional |
[]T []const T | Slices |
[N]T | Fixed-size array |
fn(T) -> R | Function pointer |
any | Dynamic 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 moduleEnums
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 valueError 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 returnedImports & 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 importVisibility
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
.. // rangePrecedence (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 i64Pipe 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.tapecreated withpub { fn distance(...) { } }+ only needed importsmain.taperewritten withimport { 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 REPLKey Design Rules
- No generics — use
@tape fn gen(T: type)+@emitinstead - No closures — use function pointers + typed events
- No exceptions — use
T or Eerror 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