DEV Community

Cover image for The Day My Language Started Compiling Itself
Javier Leandro Arancibia
Javier Leandro Arancibia

Posted on Originally published at blog.intrane.fr

The Day My Language Started Compiling Itself

Update (v0.85.0): it went further — the entire toolchain now self-hosts, not just the compiler. encode, build, and run are written in machin too, so machin rebuilds its own toolchain from source, byte-for-byte identical — a complete bootstrap. selfhost/

A year ago I built a programming language. This year it crossed the line that separates a toy from a real compiler: it started compiling itself.

watch machin compile itself

(That GIF is the real thing — machin compiling its own compiler, then that binary reproducing its own source byte-for-byte.)

That sentence sounds like a party trick. It isn't. It's one of the oldest and hardest proofs in systems engineering — and reaching it, with AI as my pair, is the clearest evidence I can offer of how I actually build software.

First, the backstory

machin is a language I designed for a specific user: the AI agent writing the code, not the human reading it. Zero type annotations, one canonical declaration per line, every design choice measured in tokens — then compiled straight through C to a single native binary. Script-like to write, C-class to run. (I wrote about why in an earlier post.)

For a year it grew the way real tools grow — by being used. Web servers, database drivers, a WebSocket client, crypto, even games. But a language is only as trustworthy as its compiler, and machin's compiler was written in Go. So I asked the question every language eventually has to answer:

Could machin compile itself?

What "compiles itself" actually means

Every serious compiler faces a rite of passage called the bootstrap. You rewrite the compiler in its own language, and then you use the original to compile the new one. If the language is real — expressive enough, correct enough, fast enough — the new compiler works. If it isn't, you find out fast.

The gold standard is the fixpoint:

  1. The original compiler builds the self-hosted one.
  2. That self-hosted compiler compiles its own source into a fresh native binary.
  3. That fresh binary compiles the same source again — and the output is byte-for-byte identical.

When those bytes match, you have proof that isn't a matter of opinion. The compiler has reproduced itself exactly. It stands on its own.

Machin now does this. The whole pipeline — lexer, parser, type checker, and C code generator, about 4,000 lines — is written in machin, and it emits the same machine code as the original compiler down to the byte.

How it was actually built (this is the part that matters)

I don't ship "it works on my machine." I ship proof. So every single stage was built against a byte-diff oracle: the original compiler and the new one were run on the same input and their output compared, character for character, across the entire ecosystem of real programs I'd already written. A stage wasn't "done" until that diff was empty — not on a test case, but on every program in the corpus.

That discipline paid for itself immediately. Building the compiler in its own language stress-tested the language harder than a year of app-building had, and it flushed out three genuine bugs in the original compiler that had been hiding in plain sight — a string-comparison that compared memory addresses instead of contents, a quadratic slowdown in string handling, an escaping edge case in code generation. Each was found because the self-hosted compiler and the reference disagreed by a byte, and I refused to wave it away.

Then the honest numbers. The self-hosted compiler doesn't just work — on the full parse-typecheck-codegen of its own source, it runs at about 0.9× the original's speed. Slightly faster than the compiler that built it. (It didn't start there — the first version was 7× slower, and closing that gap meant finding the real bottleneck instead of the obvious-looking one. It was string building, not the "slow lookups" everyone assumes.)

Why I'm telling you this

Because this is what I mean when I say I build with AI.

Not "I prompted a chatbot and shipped whatever came out." The opposite. AI was the engine, but the engineering — the oracles, the byte-level verification, the refusal to accept a passing test over a passing proof, the honesty about what's fast and what isn't — that's the part that makes the output trustworthy. AI without that rigor produces plausible code. AI with it produces a compiler that compiles itself, byte-for-byte, and you can go check the bytes.

That combination — senior engineering judgment as the guardrail, AI as the multiplier — is exactly what I bring to the systems I build for clients at Intrane. Most teams get one or the other: rigor without speed, or speed without rigor. The interesting work lives where they meet.

A language that compiles itself is a hard, verifiable, slightly obsessive proof that they can meet. If that's the kind of engineer you want on your hardest problem, let's talk.


machin is open source (MIT) — the self-hosting compiler lives in selfhost/, and you can reproduce the fixpoint yourself.

Top comments (0)