Introduction
Marrow is a fast, low-level, self-hosted systems programming language. It compiles down to QBE intermediate representation, which is then assembled and linked into a native executable (or object file) using your system’s C toolchain.
Why “Marrow”?
Section titled “Why “Marrow”?”Bone marrow is the living biological matrix nested deep within bones — it’s responsible for generating the core vital cells necessary for an entire organism to function.
Marrow (the language) is built on that same idea: an ultra-lightweight, close-to-the-metal (“close-to-the-bone”) system matrix. It aims to provide a solid, expressive foundation for building software without the overhead of a modern heavy runtime.
Design philosophy
Section titled “Design philosophy”- No hidden runtime. There is no garbage collector, no implicit allocations, and no hidden control flow. If a Marrow program allocates memory, it’s because you called an allocation function from the standard library.
- Explicit memory management. The standard library ships an arena allocator (see
std/mem.mw) as the idiomatic way to manage memory in bulk, on top of rawmalloc/freebindings. - A small, predictable core language. Functions, structs, pointers, static arrays, slices, and the usual C-like control flow (
if,while,for) — nothing more exotic than that today. No generics, no traits/interfaces, no closures, no operator overloading. - QBE as a backend, not an implementation detail you need to know. Marrow generates textual QBE IL (
.ssafiles) and shells out to theqbebinary and to your system’s C compiler (cc/gcc) to turn that into a real executable. This keeps the compiler itself small while still producing reasonably optimized native code. - C-friendly by default. Calling into C libraries is a first-class use case: the
@externdecorator lets you declare a foreign function and call it directly, which is exactly how the entire standard library is implemented (malloc,printf,fopen, etc. are all thin@externwrappers).
What the language looks like
Section titled “What the language looks like”@import("std/std.mw")
@export fn main (argc: i32, argv: rawptr) -> i32 { println("Hello from Marrow !");
print("Received arg count: "); println_i64(cast(i64) argc);
ret 0;};Compilation pipeline
Section titled “Compilation pipeline”Marrow is organized into clearly separated stages:
Source Code (.mw) │ ▼┌──────────────┐│ Lexer │ --> Tokenization (identifiers, literals, operators)└──────┬───────┘ │ ▼┌──────────────┐│ Parser │ --> Abstract Syntax Tree (AST)└──────┬───────┘ │ ▼┌──────────────┐│ Imports │ --> Resolves '@import(...)' and flattens the module graph└──────┬───────┘ │ ▼┌──────────────┐│ Codegen │ --> QBE IR generation (.ssa)└──────┬───────┘ │ ▼┌──────────────┐│ QBE + cc/gcc │ --> Assembly (.s) ──> Executable / Object file└──────────────┘Each stage is implemented as its own Rust module in the compiler: lexer.rs, parser.rs, ast.rs, import.rs, codegen.rs, and error.rs for diagnostics. There is currently no separate type-checking/symbol-table pass — type resolution, scoping, and code generation all happen together inside codegen.rs.
Where to go next
Section titled “Where to go next”- Installation — install the
marrowcompiler and theqbebackend. - Hello World — write, compile and run your first program.
- Language reference — the full language guide.
- CLI reference — everything the
marrowcommand can do. - Standard Library — what ships in
std/.