A compiler written in Rust from completely scratch, featuring custom SSA IR, bytecode, type inference,
polymorph solver, register machine, and an extremely flexible pipeline for insane meta-programming.
Every single piece of user code can execute at compile time and communicate with the compiler with NO exceptions.
A generic memory pool for storing lists of any type T.
Uses a handle-based API for indirection, power-of-two capacity rounding,
and interprets raw memory slots as u32 length headers.
INVALID_HANDLE : u32 : 0xFFFFFFFF;
// A lightweight handle into a ValuePool — just a u32 index.
// Parameterized on T for type safety at compile time.
EntityList :: struct (T: Type) {
handle: u32;
}
// A memory pool for storing lists of T.
// Layout per allocation: [length_as_T, elem0, elem1, ..., padding to next power of 2]
ValuePool :: struct (T: Type) {
data: [..] T;
}
// Allocate a new list inside the pool, returns a typed handle.
alloc_list :: (pool: *ValuePool($T), elements: [] T) -> EntityList(T) {
#if size_of(T) < size_of(u32) {
#run panic("size_of(T) in ValuePool(T) must be >= 4 bytes!");
}
count := elements.len as u32;
needed := 1 + count;
capacity := next_power_of_two(needed);
// The handle points just past the length slot
element_start := (pool.data.len + 1) as u32;
array_ensure_capacity(*pool.data, pool.data.len + capacity as _);
// Write the element count by reinterpreting the next T slot as *u32
length_ptr := *pool.data[pool.data.len] as *u32;
length_ptr.* = count;
pool.data.len += 1;
for elements array_add(*pool.data, it);
// Pad to power-of-two boundary
zero: T;
for 0..capacity - needed array_add(*pool.data, zero);
list: EntityList(T);
list.handle = element_start;
return list;
}
// Retrieve a slice view into the pool — zero-copy, no allocation.
get_list :: (pool: *ValuePool($T), list: EntityList(T)) -> [] T {
if list.handle == INVALID_HANDLE {
result: [] T;
return result;
}
length_ptr := *pool.data[list.handle - 1] as *u32;
result: [] T;
result.data = *pool.data[list.handle] as *T;
result.len = length_ptr.* as _;
return result;
}
main :: () {
pool: ValuePool(u32);
defer free_pool(*pool);
list := alloc_list(*pool, u32.[10, 20, 30, 40, 50]);
values := get_list(*pool, list);
for values print(" %\n", it);
}
#import "std.rok";
A full Asteroids game written in rok using Raylib — entities, particles, collisions, audio, and a game loop, all in rok's syntax.
Below are the most interesting excerpts.
Structs & constants — typed, zero-init, enum tiers:
Asteroid_Tier :: enum {
LARGE :: 0;
MED :: 1;
SMALL :: 2;
}
Player :: struct {
pos := #run vec2(SCREEN_W / 2.0, SCREEN_H / 2.0);
vel: Vector2;
angle := 0.0;
alive := true;
}
Asteroid :: struct {
pos: Vector2;
vel: Vector2;
radius: f32;
tier: Asteroid_Tier;
seed: u64;
}
ExplosionParticle :: struct {
pos: Vector2;
vel: Vector2;
life: f32;
max_life: f32;
size: f32;
}
COLOR_BG :: Color.{ r = 12, g = 12, b = 22 };
COLOR_PLAYER :: Color.{ r = 220, g = 230, b = 255 };
COLOR_THRUST :: Color.{ r = 255, g = 180, b = 60 };
COLOR_GAMEOVER :: Color.{ r = 255, g = 80, b = 80 };
Explosion emitter — per-tier particle burst with randomized speed, life, and size:
emit_explosion :: (particles: *[..] ExplosionParticle, pos: Vector2, tier: Asteroid_Tier, rng: *u64) {
count: i32;
life: f32;
speed: f32;
if tier == .LARGE { count = 45; life = 1.1; speed = 280.0; }
else if tier == .MED { count = 28; life = 0.85; speed = 200.0; }
else { count = 16; life = 0.6; speed = 140.0; }
for i: 0..count {
angle := rand_range(rng, 0.0, PI * 2.0);
spd := rand_range(rng, speed * 0.25, speed);
life_j := rand_range(rng, life * 0.6, life);
size := rand_range(rng, 2.5, 6.5);
array_add(particles, .{
pos = pos,
vel = vec2(cosf(angle) * spd, sinf(angle) * spd),
life = life_j,
max_life = life_j,
size = size
});
}
}
Explosion draw — fire-to-white color animation driven by life / max_life:
draw_explosion_particles :: (particles: *[..] ExplosionParticle) {
for * particles {
frac := it.life / it.max_life;
alpha := (frac * 255.0) as u8;
r: u8 = 255;
g: u8 = 0;
b: u8 = 0;
if frac > 0.7 {
t := (frac - 0.7) / 0.3;
g = (255.0 * t) as u8;
b = (240.0 * t) as u8;
} else if frac > 0.4 {
t := (frac - 0.4) / 0.3;
g = (220.0 * t + 80.0 * (1.0 - t)) as u8;
} else {
t := frac / 0.4;
g = (80.0 * t) as u8;
}
color := Color.{ r = r, g = g, b = b, a = alpha };
DrawCircleV(it.pos, it.size * frac, color);
if frac > 0.5 {
glow_alpha := ((frac - 0.5) * 2.0 * 100.0) as u8;
glow_color := .{ r = 255, g = 200, b = 80, a = glow_alpha };
DrawCircleV(it.pos, it.size * frac * 2.2, glow_color);
}
}
}
Main loop — defer EndDrawing(), smooth thrust audio fade, and twinkling stars:
while !WindowShouldClose() {
dt := GetFrameTime();
time := GetTime() as f32;
// Smooth thrust audio volume interpolation
speed := THRUST_FADE_OUT;
if thrusting_and_alive speed = THRUST_FADE_IN;
thrust_volume += (thrust_target_vol - thrust_volume) * speed * dt;
SetSoundVolume(thrust_sound, thrust_volume);
if thrust_volume < 0.01 && IsSoundPlaying(thrust_sound) {
StopSound(thrust_sound);
}
update_player(*player, dt);
update_bullets(*bullets, dt);
update_asteroids(*asteroids, dt);
update_thrust_particles(*thrust_particles, dt);
update_explosion_particles(*explosions, dt);
update_stars(*stars, dt);
points := check_bullet_asteroid(*bullets, *asteroids, *explosions, *state.rng_state);
if points > 0 state.score += points;
BeginDrawing();
defer EndDrawing();
ClearBackground(COLOR_BG);
draw_stars(*stars, time); // twinkle via sinf(time + phase)
draw_asteroid_trails(*asteroid_trails);
draw_explosion_particles(*explosions);
draw_thrust_particles(*thrust_particles);
draw_asteroids(*asteroids);
draw_bullets(*bullets);
draw_player(*player);
draw_hud(*state);
}
#import "std.rok";
#import "math.rok";
#import "raylib.rok";
#import "dynamic_array.rok";
Demonstrates Dynamic arrays with automatic growth, insertion, and removal operations.
String builders with type-aware formatting and printf-style syntax.
All powered by compile-time generics that specialize for each type.
// Compile-time polymorphic functions work on any type T
array_add :: (arr: *[..] $T, value: T) {
new_len := arr.len + 1;
array_ensure_capacity(arr, new_len);
ptr: *T = arr.data + (arr.len * size_of(T));
ptr.* = value;
arr.len = new_len;
}
// Safe removal returns both value and success status
array_remove :: (arr: *[..] $T, index: u64) -> T, bool {
ret : T;
if index >= arr.len return ret, false;
size :: size_of(T);
ptr : *T = arr.data + (index * size);
ret = ptr.*;
count := arr.len - index - 1;
if count > 0 memmove(ptr, ptr + size, count * size);
arr.len -= 1;
return ret, true;
}
String_Builder :: struct {
inner: [..] u8;
}
sb_append :: (sb: *String_Builder, n: i32) { sb_append_integer(sb, n); }
sb_append :: (sb: *String_Builder, n: f64) { sb_append_float(sb, n); }
sb_append :: (sb: *String_Builder, s: string) { sb_append_string(sb, s); }
// Printf-style formatting with variadic Any
sb_print :: (sb: *String_Builder, fmt: string, args: ..Any) {
i := 0;
arg_index := 0;
while i < fmt.len {
if fmt[i] == '%' && i + 1 < fmt.len && fmt[i + 1] != '%' {
if arg_index < args.len {
sb_append_any(sb, args[arg_index]);
arg_index += 1;
}
i += 1;
} else {
sb_append_byte(sb, fmt[i]);
i += 1;
}
}
}
main :: () {
sb: String_Builder;
defer sb_free(*sb);
sb_append(*sb, "Temperature: ");
sb_append(*sb, 98.6);
sb_print(*sb, "User % scored % points\n", "Alice", 1337);
print("%", sb_to_string(*sb));
}
#import "std.rok";
A meta-program that runs at compile-time, registers and manages build options to compile the raylib demo from above.
#run {
opts : Build_Options;
opts.do_output = false;
array_add(*opts.build_files, "examples/triangle.rok");
array_add(*opts.link_libs, "raylib");
array_add(*opts.link_libs, "m");
ok := set_build_options(*opts);
if !ok panic("couldn't set build options!! exiting..\n");
};
#import "std.rok";