2026-08-24 15:44:27 +02:00
2026-08-24 15:40:16 +02:00
2026-08-24 15:35:11 +02:00
2026-08-24 15:44:27 +02:00
2026-08-24 15:44:27 +02:00
2026-08-24 15:35:11 +02:00
2026-08-24 15:35:11 +02:00
2026-08-24 15:40:16 +02:00
2026-08-24 15:35:11 +02:00
2026-08-24 15:35:11 +02:00
2026-08-24 15:44:27 +02:00
2026-08-24 15:35:11 +02:00

vuurraaf/v

A complete toolchain for VuurRaaf, written in V from scratch: a compiler, an assembler, a linker, and a stack-based runtime. Everything — including the object file format and the virtual machine — lives in this repository.

.vr  --compiler-->  .vobj  --linker-->  .vbin  --vm-->  output
.vasm --assembler--> .vobj

Build

Requires V (v in your PATH).

v -o bin/vr .        # build the toolchain
./bin/vr up          # or rebuild from inside the toolchain
./bin/vr symlink     # optionally symlink bin/vr into your PATH

Note: build with v . from the project root. Building via an explicit file or path argument makes V pick tcc without the Boehm GC, a combination that miscompiles this codebase (vr up already does the right thing).

Usage

vr compile <file.vr> [-o out.vobj]          source  -> object
vr assemble <file.vasm> [-o out.vobj]       assembly -> object
vr link <a.vobj> [more.vobj ...] [-o out]   objects -> executable (.vbin)
vr run <file.vr|file.vbin>                  compile+link+run, or run a binary
vr debug <file.vr|file.vbin>                run with an instruction trace
vr test <file.vr>                           run every test_* function
vr bench <file.vr> [iterations]             benchmark main()
vr clean                                    remove .vobj/.vbin artifacts
vr up                                       rebuild bin/vr
vr symlink                                  link bin/vr into your PATH
vr config [set <key> <value>]               toolchain config (outdir, verbose)
vr info | loader | alloc | version | help

Quick start:

./bin/vr run examples/hello.vr        # run a program
./bin/vr test examples/tests.vr       # run the tests (one fails on purpose)
./bin/vr debug examples/hello.vr      # watch every bytecode instruction

# the assembler path
./bin/vr assemble examples/math.vasm -o math.vobj
./bin/vr link math.vobj -o math.vbin
./bin/vr run math.vbin

# multi-file programs (functions in one file may call functions in another)
./bin/vr compile examples/lib.vr -o lib.vobj
./bin/vr compile examples/use_lib.vr -o use_lib.vobj
./bin/vr link lib.vobj use_lib.vobj -o use_lib.vbin
./bin/vr run use_lib.vbin

The VuurRaaf language

A small, V-flavored language. Values are 64-bit integers, strings, or arrays (strings concatenate with + and compare with ==/!=; arrays are mutable and compare by identity).

fn sum(items) {
    let total = 0
    for x in items {            // iterate an array
        total = total + x
    }
    return total
}

fn main() {
    let x = 6 * 7
    assert x == 42
    let big = x > 40 and x < 50 // and / or / not, short-circuiting
    if big {
        println("x is big")
    } else {
        println("x is small")
    }

    let a = [10, 20, 30]
    a[1] = 99                    // index assignment
    push(a, 40)                  // grow in place
    println(a)                   // [10, 99, 30, 40]
    println(len(a))              // 4
    println(sum(a))              // 179

    for i in 0..5 { ... }        // 0 1 2 3 4   (exclusive ..)
    for i in 1...3 { ... }       // 1 2 3       (inclusive ...)

    for i in 0..10 {
        if i == 2 {
            continue             // skip this iteration
        }
        if i == 5 {
            break                // leave the loop early
        }
    }

    let grid = [[1, 2], [3, 4]]  // nested arrays
    println(grid[1][0])          // 3

    let i = 100
    for i in 0..3 { ... }        // loop vars are scoped to the loop
    println(i)                   // 100

    if score >= 90 {             // else-if chains
        grade = "A"
    } else if score >= 80 {
        grade = "B"
    } else {
        grade = "F"
    }

    match day {                  // match on any comparable value
        "sat" {
            println("weekend")
        }
        "sun" {
            println("weekend")
        }
        else {                   // optional fallback arm
            println("workday")
        }
    }
}
  • functions: fn name(a, b) { ... } with return expr
  • variables: let name = expr, reassignment name = expr
  • arrays: [e1, e2, ...], indexing a[i] (read and write), len(a), push(a, v); array literals may nest
  • for loops: for x in arr { } and ranges for i in 0..10 { } / for i in 0...10 { }; loop variables are scoped to the loop body
  • break / continue inside while and for loops (in for loops continue advances the loop variable / iterator first)
  • else-if chains: if a { } else if b { } else { }
  • match: match expr { v1 { } v2 { } else { } } — arms test equality on any comparable value (ints, strings, ...); the else arm is optional
  • operators: + - * / %, == != < <= > >=, and or not, unary -
  • statements: let, assignment, if/else, match, while, for, break, continue, return, assert, calls, print(...) / println(...)
  • comments: //

Assembly

.vasm files talk to the VM directly. Labels, .global exports, and the full opcode set:

; comment
.global main
main:
    push_int 42
    call helper 1        ; call <target> <argc>
    println
    halt

.global helper
helper:
    enter 0              ; reserve extra locals (args were copied in by `call`)
    load 0
    retv

Opcodes: halt push_int push_str load store pop dup add sub mul div mod neg eq ne lt le gt ge and or not jmp jz jnz call ret retv print println assert enter mkarray aget aset alen apush.

Formats

  • VROBJ (.vobj) — linker input: bytecode, exported symbols (function name -> code offset), string constants, and relocations (call sites and string references).
  • VRBIN (.vbin) — the executable: function table, string table, bytecode.

Architecture

module role
compiler/ lexer, recursive-descent parser, bytecode codegen (VROBJ)
assembler/ .vasm -> VROBJ
linker/ resolves relocations, rebases strings, emits VRBIN
vm/ stack VM: tagged values, call frames, string/array heaps
obj/ VROBJ/VRBIN binary formats
bin/ small standalone tools: tl_alloc.v, tl_loader.v

The VM is a stack machine with 64-bit tagged values using two tag bits: numbers are stored shifted left by two, string handles end in 01, array handles in 11 — so no integer ever collides with a heap handle. Arrays live in a growable heap (mkarray/aget/aset/alen/apush). Calls push a frame (return address, base pointer, argc), copy arguments into local slots, and reserve extra locals with enter n. vr debug prints every instruction with the stack contents (arrays rendered as [1, 2, ...]).

Repository layout

main.v               CLI entry point (vr <command> ...)
v.mod                module definition
compiler/ assembler/ linker/ vm/ obj/   the toolchain itself
bin/                 built binary + standalone tools
examples/            runnable examples (hello, lib, asm, tests, fib)
S
Description
<Vuurlang/v> The vuurraaf/vuurraaf-v is the one pushing to github, and this one mirrors from github, this is the always up to date one.
Readme
82 MiB
Languages
V 97.6%
JavaScript 2.3%