Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Tower API

lib/tower.naj evaluates to a selector function over five exports. The session uses four of them at boot; all five are available to any floor program that animates the file:

(let tower (evalms nil (trans (car (read-file 'lib/tower.naj)) nil))
(let m ((tower 'make-level) 0)
(let env ((tower 'make-env) 0)
(((((tower 'ev) m) env) '(+ 1 2))))))
;=> 3

Exports

  • ((T 'make-level) 0) — construct a meta level: a pair (menv . slot) whose environment holds a fresh set of handlers and whose slot lazily yields the level above.
  • ((T 'make-env) 0) — a fresh object-level global environment: one mutable frame holding the primitives.
  • (((T 'env-define) env) name) then applied to a value — extend a global environment’s first frame with a cell-backed binding. This is the hook lib/purple.naj uses to install the session bindings.
  • ((((T 'ev) m) env) exp) — evaluate exp in env, dispatched through meta level m, at the concrete stage.
  • (((T 'clambda-code) m) e) applied to r — the reified residual of a clambda expression e in environment r: code for a stage-polymorphic function, before any run. The clambda handler is this plus run 0; the export exists so the staging of the tower can be inspected without executing it.

Value representations

shapemeaning
number, symbol, nil, pairthemselves
('clo params body env . m)interpreted closure; m is the meta level at creation
('prim . name)primitive
('fn . fc)native function — a floor closure under the handler protocol
('cont . k)captured continuation (k a bare floor closure)

Floor values outside these shapes (Pink evaluators, nil-env, floor closures generally) apply natively to one forced argument, so curried floor code runs through the tower unchanged. Numbers, symbols, and nil in function position throw ('cannot-apply . v).

Environments

An environment is a list of frames. A runtime frame is a cell over an association list — define extends it in place; a plain list in frame position is a staging-time frame (introduced during clambda compilation, matching lms-black’s inRep environments). Bindings are (name . ('cell . c)) when mutable; the primitives are bound direct, cell-less, so staged reads of them constant-fold.

The meta frame

A level’s environment holds fifteen handlers, each an ('fn . fc) boxed in a cell so EM can set! it:

base-eval          dispatch on expression shape
eval-var           variable lookup
eval-lambda        both lambda shapes (lms-black and floor/pink)
eval-clambda       compile-at-definition (see the clambda chapter)
eval-let           both let shapes
eval-cst           cst: let over direct (cell-less) bindings; staged reads fold
eval-if            three-armed if
eval-begin         sequencing
eval-set!          assignment (throws set-immutable on cell-less bindings)
eval-define        first-frame extension
eval-quote         quotation
eval-EM            evaluate one level up (materializes it if needed)
eval-application   evaluate operator and operands, then base-apply
eval-list          evaluate a list of expressions
base-apply         apply an object value

followed by the eleven primitives, direct: + - * eq? cons car cdr number? symbol? null? pair?.

A handler installed with EM (set! …) receives three arguments — the expression, the environment, and the continuation — and usually ends by deferring to the saved original, as in the EM chapter.

The stage dictionary

Every handler threads l, a selector over nine operations: staged (0 or 1), lift, force, cread/fread (cell read, dread-preserving and forced), cset, cnew, app (dynamic apply), appk (apply a continuation). The concrete dictionary — identity lift and force, real cell operations, real application — makes ev an interpreter. make-staged-dict builds the compiling dictionary used under clambda: pure values lift, cell operations and dynamic applications emit residual code routed through the dictionary the compiled function will receive at run time. Handler dispatch itself is always concrete; only dictionary operations mark where staging residualizes.