The Mica dragon

The dragon has represented Mica from the beginning. As of this release it carries a second meaning: Dragon is the name of the compiler’s backend engine — and it now flies for more languages than one.

Every compiler description says the same thing: there is a frontend, an intermediate representation, and a backend. Ours said it too. For three years it was true the way a diagram is true — the layers existed, the arrows pointed the right way, and nothing enforced any of it except habit and care.

As of this release, it is true the way a wall is true.

What changed

The Mica compiler’s repository is now four modules, and its top level reads as the architecture itself:

  • foundation — errors, tokens, the platform model, the type system.
  • spectra — the intermediate language: the contract every frontend writes.
  • dragon — the backend engine: control-flow analysis, SSA, storage placement, register allocation, and the emitters for both architectures, behind one documented entry.
  • mica — the language you know, now formally just the first customer of the other three.

The walls are not documentation. The lower modules cannot import the frontend — their module definitions do not name it, so the build itself refuses the dependency — and a gate in the test ladder pins every one of the 243 internal import edges, with zero pointing upward.

If you use Mica, nothing changes: one binary, the same command line, the same packages. The breakup is invisible at install time, which is exactly the point — it is architecture, not product surface.

The proof is a second language

A backend that claims to serve “any frontend” has to be tested by a frontend that is not its own. We chose the most honest one available: PL/0, the tiny teaching language from Niklaus Wirth’s Compilerbau — constants, variables, nested procedures, if, while, one type, and the single idea that matters: reaching a variable declared some levels out.

We ported Wirth’s compiler to Go, keeping his procedure decomposition and his stack machine — and then gave it a second back end that emits Spectra and hands the result to Dragon. The same parse now takes two roads: one into Wirth’s interpreter from 1976, one into the same code generator, register allocator, and emitter that compile Mica itself.

The two roads must agree, output byte for byte, program for program — nested procedures, recursion, every comparison. Wirth’s machine is the oracle; Dragon has to match it. It does.

$ pl0 -native square.pl0     # native code through Mica's backend
$ pl0 square.pl0             # Wirth's stack machine, 1976

Same numbers, every time. That equality is now part of our test suite.

What a frontend actually owes the backend

The most valuable thing PL/0 produced was not the binary — it was the list. Until a second producer existed, the intermediate language’s validity rules were satisfied by habit inside one code generator, which means they were written down nowhere. PL/0 hit every one of them, and each collision became a documented rule and an executable check: the backend now validates a unit before compiling it and answers violations as a numbered repair list in plain sentences, instead of failing somewhere deep inside.

A frontend developer targeting Dragon today gets what an SDK owes them: a written contract, a validator that speaks it, and a complete worked example small enough to read in one sitting.

What comes next

PL/0 ships as a preview of the Dragon SDK — the worked example of a foreign frontend, professionally commented, meant to be read. A C-shaped stress of the same interface comes later, and behind it stands a larger ambition we will talk about when it is ready.

The breakup ships with 6.12.5, alongside the project model and the run mode. Three years is a long time to carry a diagram. It is a good feeling to have walls.