A small, statically-checked concatenative language in the Forth/Factor/Kitten lineage, compiled to native code with no external runtime. A craft language: built for the pleasure of writing it and writing programs in it, not as a product. See DESIGN.md for the why and ROADMAP.md for the plan.
The one bet that makes it more than a tidy Forth: in a stack language the stack
discipline already is move semantics, so linear types fall out for free. dup is the
explicit copy, and drop is the explicit destructor point (use exactly once, forgetting
is a compile error).
: gcd ( i64 i64 -- i64 )
dup 0 = if
drop
else
swap over mod gcd
end ;Phases 0 and 1 complete; Phase 2 (typed core) in progress (see ROADMAP.md). The
pipeline is implemented end to end: gcd/factorial/lerp and the newer examples
compile to native binaries and run, and cargo run -- repl gives an interactive session
where words are compiled to shared objects and dlopen'd in as you define them. Phase 2
has landed its full scalar core: a Type per stack slot, unified at branch joins; the
fixed-width integer tower (i8..i64, u8..u64) with explicit target-only conversions
(>i8..>u64); floating point (f32/f64) with IEEE arithmetic and comparison; bitwise
operators (and/or/xor/not/shl/shr); and boolean logic with the full comparison
set (= < > <= >= <>). Phase 2 has also landed structs (the type: declaration form,
inline-aggregate layout, generated constructor/accessor words) and enums/ADTs (type:
with |-separated variants, a tagged inline-aggregate representation, and
exhaustiveness-checked clause-style word definition as the eliminator, no inline match).
What remains in Phase 2 are fixed-size arrays, then the bytecode-VM exit dogfood. The
compiler is a Rust bootstrap; the language will later self-host.
Pipeline: source → lex → parse → stack-effect check → backend-neutral IR → QBE IL → native binary. Backend is QBE, invoked from PATH
alongside the system cc. WASM is a planned sibling lowering off the neutral IR.
Requires qbe and a C compiler (cc) on your PATH. Needs a reasonably modern QBE:
Debian's packaged qbe (1.2) predates the unsigned int/float conversion ops
(uwtof/ultof/stoui/dtoui) and fails with unknown keyword on those; build
from c9x.me/git/qbe.git if so.
cargo build
cargo test # unit tests + the Phase 0/1 goldens
cargo run -- run examples/gcd.sth # compile and run (prints 5)
cargo run -- build examples/gcd.sth # just compile, to examples/gcd
cargo run -- repl # interactive sessionA REPL session compiles each line to a shared object and dlopens it into the
process, with a stack that persists across lines (no prompt is printed in Phase 1;
lines below are input, other lines are the session's output):
: sq ( i64 -- i64 ) | n | n n * ;
defined sq
5 sq
stack: 25src/lexer.rs parser.rs ast.rs front end
src/check.rs stack-effect checker
src/ir.rs backend-neutral IR (Ptr[T] kept abstract)
src/backend/qbe.rs QBE IL emission
src/driver.rs pipeline orchestration
src/repl.rs REPL session: dlopen loop, generation mangling
examples/ target programs (gcd, factorial, lerp, rgb, mean, leap, ...)
tests/phase0.rs golden tests: build+run + diagnostics across the scalar core
tests/phase1.rs golden REPL sessions (define/redefine/recover)