Meadows Compiler

A compiled programming language I built from scratch - custom syntax, recursive-descent parser, and LLVM IR codegen all the way to native executables.

I wanted to understand how programming languages actually work - not just “a compiler turns code into machine code” but every single step: how raw text becomes tokens, how tokens become a tree, and how that tree becomes something a CPU can run. So I built one.

Meadows is a compiled language with a C-style syntax. You write .ms files, run the compiler, and get a native binary. No interpreter, no VM - real machine code via LLVM IR.

The pipeline

Source (.ms) → Lexer → Parser → AST → CodeGen → LLVM IR → clang++ → Binary

Each stage is its own module. The lexer tokenises raw source with line/column tracking for error messages. The parser is a hand-written recursive descent parser with 11 levels of operator precedence. The AST covers 11 statement types and 11 expression types. The codegen walks the AST and emits LLVM IR, which clang++ then compiles to a native executable. The Catch2 test suite covers the full parse → codegen pipeline end-to-end, including security edge cases like integer overflow and out-of-bounds access.

What the language looks like

func factorial(n) {
    if (n <= 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

let result = factorial(5);
print result;

Variables, functions, conditionals, loops, arrays, objects, string escapes - the full set of things you reach for without thinking when you write in any language. Implementing every one of them yourself changes how you see the languages you use every day.

LSP support

The compiler also ships an LSP server with completions and diagnostics for .ms files. Implementing the protocol at the compiler stage means editor integration isn’t an afterthought — the same symbol table the codegen uses drives the completion candidates.

WebAssembly path

LLVM dependencies don’t cross-compile to WebAssembly cleanly via Emscripten, so I made the native LLVM codegen conditional and built a separate WebAssembly code path. The parser and AST run in the browser today; the native backend is skipped when building for the web. The full pipeline in a browser tab is still in progress.

Key decisions

Future directions

Built with