Map: core / evaluator
core/src/evaluator/ runs the CBPV IR as a trampolined machine
(evaluator.rs). Evaluation is entered only through framed turn doors; the
machine’s own verbs are crate-private. Two reach outside the module:
eval_top_level(comp, shell)(pub(crate)) — the turn-evaluation verb a tool call, a REPL turn, or a script line settles through. Hosts never call it: they enter through the framedShell::run_turndoor (core/src/driver.rs, over the turn spine incore/src/turn.rs), the sole way into evaluation — itsTurncarries aProgramof source text or a registered hook (unify-turn-evaluation, host-seam-transport-parametric). The post-runMobileis installed on the parent shell on every outcome (Ok / Error / Exit), because a top-level turn is a resume point.evaluate(comp, shell)— a bare tail-absorbed run with no mobile contract, for callers already inside a session (module load, prelude bootstrap, capability profiles, REPL plugin / config loading).
apply(callee, args, shell) is pub(crate): it reduces a Value (closure or
thunk) applied to arguments, absorbing tail signals through the trampoline. A
host reaches it only through the turn door’s hook-program arm or the
in-frame builtin wrapper, so an unframed reduction is unconstructable.
The result surface is Settled<Value> carrying Escape / BodyResult; tail
calls funnel through absorb_tail into the trampoline
(completion-escape-refactor). The escape-propagation
guarantees (try does not swallow exit, grant does not bypass tail calls) are
regression-tested (escape-propagation-bugs).
A same-thread thunk body — forcing a block or applying a lambda — evaluates in
place on the caller’s Shell, sharing turn, session, and local state by
identity and swapping in only a mobile rescoped to the closure’s captured
environment plus a fresh frame
(same-thread-body-shares-the-session).
Block and lambda meet at one in-place routine, Shell::with_thunk_body, which
the kind parameterises: a Block enters with the caller’s $? and folds only
last_status back; a Lambda enters with a fresh $? and folds back
{last_status, cwd}. The Value-level force/block split stays intact
(force-eliminates-blocks); only
their shared store-threading is made literal. The Shell lifetime regions this
shares belong to shell-state.
Internals:
trampoline.rs— loops onControl::Tailfor O(1) tail-call space and hostsapply; theValue::Thunkarm delegates to the block contracteval_block, andapply_lambda_frameruns a lambda body in place viawith_thunk_body.comp.rs— theCompstep functions;val.rs— the side-effect-freeVallayer (eval_val);expr.rs—PrimOpevaluation and value indexing;call.rs— the application step (invoke).scope.rs— dynamic frames implementing scoping and the five control operators. Thewithinform installs command handlers: a per-name handler and every alias must be a unary lambda{ |args| ... }, the catch-all a binary lambda{ |name args| ... }; the calling convention is fixed by the surface form and validated at the install boundary byvalidate_handler_arity, never sniffed from the runtime value (handlers-and-aliases-are-lambdas). The handler-stack mechanics live in handler-dispatch.case.rs,pattern.rs— matching:assign_patterndestructures aValueagainst a compiledIrPattern(wildcard, name, list with optional...rest, map with pre-elaborated defaults), installing bindings into the current scope. Without a...resttail a list pattern must cover the value exactly — a longer list errors rather than silently dropping its extra elements. A mismatch is a located runtime error with anexpected … got …message and a shape hint, propagating like any other failure and so catchable bytry. ItsNameand...restarms — andcomp.rs’seval_letrecgroup reinstall and its own pushed fixpoint pre-install — route every scope write throughShell::install_scope_binding(types/shell/scope.rs), the single fused chokepoint that also stamps the [[map/core/shell-state|binding-lease ledger]] when the write lands at session scope (agent-binding-reaping); a pushed fixpoint or block frame makes the predicate false with no special case needed at either call site.capture.rs—with_capturefor output capture;redirect.rs— the RAII redirect-frame install/unwind (within_redirect_frame) that wraps anExecor scope carrying> filesyntax, distinct from the external-command fd machinery in runtime’scommand/redirect.rs.- The command/pipeline machinery — external-command dispatch,
pipeline planning and execution, and the in-process-vs-sandboxed-child
dispatch choice — lives in runtime, which the machine
reaches at
pipeline::run_pipeline,command_call::run_call, and thecommandredirect guards, and which re-enters the machine only through the verbs above; the boundary verbs themselves always evaluate their body in process, OS confinement being per-child inbuild_command(evaluator-runtime-split). audit.rs— execution-tree recording.
Hot loops poll a cancellation flag cooperatively (hot-path-cancellation).