← RustyIC10

RustyIC10

in progress

A small Rust-like language that compiles to Stationeers' IC10 assembly.

How it works

The compiler is a classic pipeline, with one Rust crate per stage:

source ─► lexer ─► parser ─► HIR ─► MIR ─► codegen ─► IC10
                   (AST)    types,   CFG +    register
                            checks   optimizations  allocation
stage what it does
parser recursive descent with Pratt-style precedence; it recovers from broken statements, so completion still works on half-written code
HIR (high-level form) name resolution, type checks, mutability rules, device checks, constant evaluation, for unrolling
MIR (mid-level form) a control-flow graph of simple instructions on unlimited virtual registers, with each struct field in its own register; constant folding, copy propagation, dead code removal, jump threading, inlining
codegen register allocation for the whole program, then IC10 output and small local clean-ups (peephole optimizations)

Fitting in 128 lines

  • No stack spills. The compiler assigns registers for the whole program at once. A value still needed after a call never shares a register with the called function, so nothing is saved to the stack. Functions that never run at the same time share registers, and most copies between registers are removed (Briggs coalescing).
  • Inlining. Small functions, and functions called from only one place, are copied into the caller. After that, device parameters usually become constants, so an indirect dr0 turns into a plain d0.
  • Line-number jumps. Jumps go to line numbers by default. --labels makes the output easier to read, at the cost of one line per label.

The same compiler everywhere

The command-line tool, the tests and the browser playground all use the same code. The playground loads it as a plain WebAssembly module (C ABI, no wasm-bindgen). The end-to-end tests run the compiled output in an IC10 emulator.