DayZ Nerd Squad
.b Bench .b · .bench
hello.b
fn main() {
    print("Hello, Bench!");
}
Lex Parse Typecheck Codegen
compiled · 0 errors

The language everything else gets built on.

A real, from-scratch programming language: its own grammar, its own type system, its own compiler, now bootstrapping itself. Every future project starts here.

Real code, not a mockup

Everything below actually runs

Six real programs, copied verbatim from the language's own repo: control flow, a genuine generic type system (Option/Result), traits with dynamic dispatch, real OS-thread concurrency, and Bench's own lexer, written in Bench.

01Hello, Bench
examples/hello.b
fn main() {
    print("Hello, Bench!");
}

This is the entire grammar in miniature: a function, a statement, a call. Every heavier feature below, structs, generics, traits, threads, is built from exactly these same pieces, not a separate "advanced mode."

02Control flow
examples/fib.b
fn fib(n: int) -> int {
    if n < 2 {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}

fn main() {
    let i = 0;
    while i < 10 {
        print(fib(i));
        i = i + 1;
    }
}

fib(9) really recurses through fib(8) and fib(7), each splitting the same way down to the base case, real stack frames and real function calls, the same cost model you’d expect from any compiled language, not a toy expression evaluator.

03Real generics: Option & Result
examples/generics.b
fn safe_div(a: int, b: int) -> Option<int> {
    if b == 0 {
        return Option::None;
    }
    return Option::Some(a / b);
}

fn checked_sqrt(n: float) -> Result<float, string> {
    if n < 0.0 {
        return Result::Err("negative input");
    }
    return Result::Ok(n);
}

fn main() {
    match checked_sqrt(4.0) {
        Result::Ok(v) => { print(v); }
        Result::Err(e) => { print(e); }
    }
}

Option<int> and Result<float, string> aren’t special-cased into the compiler; they’re ordinary generic enums, the exact mechanism a Wrapper<T> you write yourself would use. Option::None has no argument to infer a type from, so the checker reads safe_div’s own declared return type as the hint instead.

04Traits & dynamic dispatch
examples/traits.b
trait Show {
    fn show(self) -> string;
}

struct Point { x: int, y: int }
struct Circle { radius: float }

impl Show for Point {
    fn show(self) -> string { return "a point"; }
}
impl Show for Circle {
    fn show(self) -> string { return "a circle"; }
}

// describe<T> only knows T is bounded by Show, not which concrete
// type it is, yet it can still call .show() on it.
fn describe<T: Show>(item: T) -> string {
    return item.show();
}

describe<T: Show> accepts any type at all, as long as it implements Show; the function body has no idea whether it’s holding a Point or a Circle. Which show() actually runs is resolved dynamically, at the call site, based on what’s really there at runtime.

05Real OS-thread concurrency
examples/native_spawn_channel.b
fn producer(c: Channel<int>) -> int {
    let i = 0;
    while i < 5 {
        c.send(i * i);
        i = i + 1;
    }
    return 0;
}

fn main() {
    let c: Channel<int> = Channel::new();
    let t = spawn(producer, c);
    // .recv() genuinely blocks until the producer, running
    // concurrently on its own OS thread, sends the next value.
    let i = 0;
    while i < 5 {
        print(c.recv());
        i = i + 1;
    }
    print(t.join());
}

spawn() puts producer on a genuinely separate OS thread; main keeps running immediately, and c.recv() really blocks until a value shows up. Not cooperative or green-thread concurrency: verified by literally timing it, three concurrent workers finish in the time of the slowest ONE, not the sum of all three.

06Bench’s own lexer, written in Bench
examples/self_hosted_lexer.b
fn lex(source: string) -> Array<string> {
    let tokens: Array<string> = Array::new(0, "");
    let i = 0;
    let n = source.len();
    while i < n {
        let c = source.char_at(i);
        if is_space(c) {
            i = i + 1;
        } else if is_digit(c) {
            let word = "";
            while i < n && is_digit(source.char_at(i)) {
                word = word + source.char_at(i);
                i = i + 1;
            }
            tokens.push(word);
        } else if is_alpha(c) {
            let word = "";
            while i < n && (is_alpha(source.char_at(i)) || is_digit(source.char_at(i))) {
                word = word + source.char_at(i);
                i = i + 1;
            }
            tokens.push(word);
        } else {
            tokens.push(c);
            i = i + 1;
        }
    }
    return tokens;
}

This is Bench, lexing Bench: real .b source text goes in, a stream of real tokens comes out, numbers, identifiers, strings, two-character operators like -> and ==. Its own output already feeds a self-hosted parser, which feeds a self-hosted typechecker, which feeds self-hosted codegen: a real, working compiler pipeline written in the language it compiles, not a roadmap item.

The real flex

Self-hosted codegen doesn’t just claim to work.

It transpiles Bench source to real Rust, then actually invokes rustc on that output and runs the result. Every single time. If the round-trip doesn’t compile and run correctly, the test fails, on the spot. That’s not a demo. That’s proof, checked by a machine, not asserted in a README.

How powerful is it, today

A real engine, not a toy

Full static types, generics, traits, move semantics, a Cranelift-based native backend (JIT and ahead-of-time compilation), real OS-thread concurrency, and C interop, all shipped. Now bootstrapping: its own lexer, parser, typechecker, and code generator are already written in Bench itself.

0Days: first commit to self-hosting
0Commits
0Self-hosted compiler pieces
0Example programs

$ benchc

Interpreted, natively compiled, or built to a binary

The same source file, three ways: a fast interpreted default, a Cranelift-JIT'd native run, or an ahead-of-time standalone executable. Plus a formatter and a real test runner, built on the language's own assert().

terminal
$ cargo run --bin benchc -- examples/fib.b  # interpreted (tree-walking), the default
$ cargo run --bin benchc -- --native examples/fib.b  # Cranelift-compiled, JIT’d into memory, run immediately
$ cargo run --bin benchc -- --aot fib fib.b && ./fib  # ahead-of-time: a real standalone executable
$ cargo run --bin benchc -- --fmt examples/traits.b  # canonical formatting
$ cargo run --bin benchc -- --test examples/native_test_demo.b  # cargo-test-style output, built on assert()

Momentum

Built in 19 days. Still shipping daily.

2026-07-24Initial commit: Bench language phase 0
2026-07-31Add a self-hosted lexer for Bench, written in Bench itself
2026-08-04Add a self-hosted recursive-descent parser for Bench, written in Bench
2026-08-08Add benchc --test, a test runner built on assert()
2026-08-08Add `use "path.b";`, Bench’s first multi-file mechanism
2026-08-11Add self_hosted_codegen.b, self-hosted codegen via Rust transpilation
2026-08-12Add self_hosted_enum_codegen.b, enum/match support in self-hosted codegen

The foundation

Every future project starts as a .b file.

Bench isn't a side experiment sitting next to everything else; it's the ground floor. From here forward, new tools, new bots, new services: all of it gets built on Bench first, in the language written specifically to be fast, safe, and simple enough to build anything on.

.b

Bench

Not a concept. A real, working, self-hosting language.

Built from scratch, in the open, in under three weeks: its own grammar, its own type system, its own compiler, now writing its own successor. Still growing fast.