Under the hood
The Recoil compiler is written in Rebol and turns
.rcl source into C, then hands that C to a target toolchain. This
page sketches the pipeline and the intermediate forms for the curious and for
contributors.
End-to-end stages
Orchestrated by compile in src/compiler.r3; the CLI
wrapper is recoil.r3.
| Stage | Role |
|---|---|
| Prepare | load modules, parse (to-ast), parse the header, alpha-rename bindings → statement AST |
| Monomorphize | instantiate generic functions/types where required |
| Borrow check | analyze — ownership / move / borrow state over the AST |
| Fact analysis | analyze-facts — flow of refined types / constraints (post-borrow) |
| AST → IR | ast-to-ir — typed, C-oriented IR blocks (ir-* tags) |
| Optimize | optimize — constant folding, dead-code elimination, expression cleanup, optional self-tail-call rewrite |
| Codegen prep | collect constants, register series/global/rule info, assemble header + C helpers, select the entry wrapper |
| Emit C | emit-c / emit-expr — IR → C source plus include/link metadata; entry shape (main, app_main, emscripten) chosen here |
| Build | write a temp .c and invoke the target toolchain (GCC-compatible, emcc, MSVC, or ESP-IDF) and link the runtime |
The AST
The parser produces a top-level block of statement nodes. Ordinary bindings
are assignment-shaped (x: make i32! 1 becomes a set
path, not an old decl form); if/either/match
are expression-capable; type definitions use make-def.
Representative statement nodes
| Tag | Shape |
|---|---|
func-def | [func-def name spec body] |
set | [set name value ...] |
return | [return value] |
while / repeat | [while cond body] / [repeat var limit body] |
go | [go body] (statement only) |
defer / defer-error | [defer body] |
make-def | [make-def name spec] (struct/enum/sum/c-struct/fsm) |
Representative expression nodes
| Tag | Shape |
|---|---|
call | [call func-name args ...] |
indirect-call | [indirect-call fn-ptr args] |
ns-call | [ns-call head selector c-name args ...] (foreign) |
make / cast | [make type payload] / [cast type value] |
path-get / path-set | field/index read & write |
enum-get | [enum-get enum-type variant] (enum/sum/FSM tag) |
The IR
IR is a normalized, more C-oriented form produced by ast-to-ir
after borrow checking and fact analysis. Tags are prefixed ir-*.
Representative statement IR
| Tag | Shape |
|---|---|
ir-func | [ir-func name spec body] |
ir-assign | [ir-assign name value type ...] |
ir-if / ir-while / ir-for | statement conditional & loops |
ir-go | [ir-go task-name captures body] |
ir-match | [ir-match subject sum-type branches] |
ir-defer / ir-defer-error | deferred cleanup |
Representative expression IR
| Tag | Shape |
|---|---|
ir-binop | [ir-binop op left right] |
ir-call / ir-indirect-call | direct & fn-ptr/closure calls |
ir-either-expr / ir-match-expr | value-position conditional & match |
ir-block-expr | expression block with prefix statements and a final value |
ir-vector-get/set, ir-struct-get/set | indexed and field access |
ir-parse / ir-rule | compiled parse expression & rule |
ir-const | [ir-const type value] |
Function spec objects
Function specs are object-based and shared across the parser, borrow checker,
and codegen. Closures and fn-ptr! values use the same model plus
capture metadata.
make object! [
name: 'function-name
params: [
{name: 'a type: 'i32! borrowed?: false}
{name: 'msg type: 'string! borrowed?: true}
]
return-spec: [i32!]
annotations: [#export]
]
Diagnostics
Every compile-time failure is both a human-readable string and a structured
object carrying a stage (parser, module,
borrow-checker, ir, codegen,
cli, build), a kind, a stable
code, and an optional location. The user-facing format
and code ranges are documented in the Reference.
Introspection
You can inspect each stage's output:
# print the parsed AST
r3 -s recoil.r3 -a file.rcl
# emit the generated C without building a binary
r3 -s recoil.r3 --transpile file.rcl
Within the compiler, compile/ir returns IR
(/optimized? selects pre- vs post-optimize). For the
per-stage source map and the full ir-* inventory, see the
repository docs:
compiler pipeline,
AST reference, and
IR reference.