Expand description
CK machine — explicit-continuation iterative evaluator.
§Overview
This is narju’s sole evaluator. It walks an Exp tree by alternating
between two modes:
-
Mode::Eval { env, exp }— about to evaluateexpunderenv.step_evaldispatches onexpand either produces aValimmediately (terminals) or pushes aContonto the kont stack and switches to a sub-expression. -
Mode::Apply { val }— just producedval. Pop aContfrom the kont stack;step_applyresumes the paused operation, either producing another val or switching back toMode::Eval.
Every operand evaluation, every reify scope, every η-expansion lives on the heap kont rather than the Rust stack. The Rust stack depth is O(1) regardless of program size or staging tower depth. (The name is Felleisen’s: C for the control string, K for the continuation stack. Environments ride inside both, so strictly this is a CEK machine with E folded into C and K.)
§Where staging happens
The machine does not distinguish “normal” from “staging” evaluation.
Staged operations are just the arms of each dispatch that fire when
an operand is Val::Code: instead of computing, they call
EvalCtx::reflectc, which appends the operation to the innermost
open block in the EvalCtx and hands back a fresh residual
variable. Reify scopes (Class S below) delimit those blocks and fold
them into ANF Let-chains. All state involved lives in the EvalCtx;
ScopeSnapshot saves and restores it around each scope — except
cells and I/O, which are effects and survive.
§Layout of this file
In source order: Mode; the operator-kind enums (BinOpKind,
UnOpKind); Cont, the continuation alphabet itself; the
resume-descriptor enums (ForceMode, ForceCodeResume,
ReifyResume); Machine and its run loop with
unwind_to_catch; step_eval; step_apply; the shared dispatch
helpers (dispatch_unop, dispatch_binop); and ScopeSnapshot
at the end.
§Continuation taxonomy
-
Class T (tail).
Letbody,Ifchosen-branch (Cst),Appclosure body. Resumes aMode::Evaldirectly — no kont frame. -
Class O (operand). Binary/unary primitives push a cont holding the unevaluated sibling (binary) or the op-kind (unary), then evaluate the first/only operand. Dispatch happens on resume in
step_apply. -
Class S (staged). Reify scopes (
If-Code,LiftRef-Code,Run-Code, run-now,Evalms) pushCont::ForceCode { resume: ReifyDrain { saved, then } }orCont::ReifyVExit { saved, resume }, save aScopeSnapshot, and evaluate the staged body under a fresh block. On completion the kont drainsctx.blockinto a Let-chain and dispatches aReifyResumeto describe what surrounding staged construction is being assembled.Lift’s
Cloarm η-expansion is implemented as a nestedForceCode→LiftCloFinishpair that grows the kont rather than the Rust stack. -
Class C (error).
CatchpushesCont::CatchExit { saved }and evaluates the body. The Machine’s run loop catchesErrresults fromstep_eval/step_applyand walks the kont viaunwind_to_catch, restoring state from each popped cont until it finds aCatchExit(or runs out, in which case the original error propagates).
Structs§
- Machine
- The CK machine’s execution state.
- Scope
Snapshot - A snapshot of the staging-related fields of
EvalCtx. Used to save and restore the staging context at scope boundaries (reify, reifyc, reifyv, run_now, Catch).
Enums§
- BinOp
Kind - Binary primitive operators that share the same shape:
- Cont
- An entry on the kont stack — represents pending work to resume when the
current sub-evaluation produces a
Val. - Force
Code Resume - Discriminator for what to do with the Exp produced by a
ForceCodecontinuation. Different callers want to assemble different surrounding constructions from the forced Exp. - Force
Mode - How
Cont::ForceCodetreats a non-Codevalue. - Mode
- The CK machine alternates between two modes:
- Reify
Resume - Discriminator for what shape of staged Exp to assemble when a reify scope completes. Each reify scope in the recursive code corresponds to one of these — the resume action knows what surrounding Exp the reified body slots into.
- UnOp
Kind - Unary primitive operators that share the same shape: