Built to be read, then compiled
Ignis started from a plain question: what does a language look like when the type system is as strict as Rust's, the syntax reads like TypeScript, and the output is C that any toolchain can build? Not a VM, not a runtime — a compiler that hands GCC something ordinary.
The compiler is written in Rust as a Cargo workspace: a hand-written lexer and recursive-descent parser, a multi-phase analyzer that binds, resolves, typechecks and borrow-checks, two intermediate representations, and a C backend. Everything the language promises is enforced before a single line of C is emitted.
How a program becomes a binary
Five stages, each a crate in the workspace. A failure in any of them is a diagnostic, never a broken binary.
- 01
Parse
Lexer and recursive-descent parser with Pratt precedence produce the AST.
- 02
Analyze
Bind, resolve, typecheck, const-eval and lint in ordered phases.
- 03
Lower
HIR carries types and captures; monomorphization removes every generic.
- 04
Emit
LIR becomes basic blocks, then C structs, tagged unions and functions.
- 05
Link
GCC compiles the C, ar archives it, and the linker produces the executable.
Where it is going
- Shipped
- Generics, traits, pattern matching, closures, borrow checking, UTF-8 strings, HashMap and HashSet.
- Next
- Self-hosting the compiler front end, and widening the standard library past the current collection set.
- Later
- macOS and WebAssembly as compilation targets. Windows comes much later — the emitted C is portable, the toolchain assumptions around it are not.
Working on it
Ignis is early and moving. Syntax changes between versions, and the changelog is the honest record of what broke. If you want to help, the compiler crates are documented and the test suite runs from a single command.