This site describes solve-engine as it is on main: 2.43.0, which npm does not have yet. npm installs 2.40.0, so a page may show an answer that version does not give yet.
ThreeTierEvaluator
Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:180
Orchestrates three-tier evaluation over a persistent DocumentModel.
── Tier assignment ───────────────────────────────────────────────── | Tier | Condition | Action | |───────|────────────────────────────────────|───────────────────────────────| | 1 | Dirty, in or above the viewport | Full pipeline: lex→parse→compile→execute | | 2 | Visible + Cached (scroll into view)| Execute from cached bytecode | | 3 | Dirty, below the viewport | Compile-only; execute only variable defs | | Skip | Clean, empty, or non-evaluable | No action |
── Evaluation order ───────────────────────────────────────────────── Lines are always processed in ascending document order (line 1 → end) so that variable assignments flow correctly through the shared VM. Tier 2 relies on this: by the time a clean cached line is reached, the VM already contains all variables from preceding Tier-1 lines.
── Thread safety ────────────────────────────────────────────────────
Tier 1 (visible+dirty) compilation runs synchronously on the main thread
for immediate rendering. Tier 3 (invisible+dirty) compilation can be
dispatched to a Web Worker via dispatchBackgroundCompiles(). Worker-
compiled bytecode is stored in the DocumentModel and validated via
isBytecodeValid() to ensure the line text hasn’t changed between
dispatch and response.
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new ThreeTierEvaluator( doc, engine, checkpointer?): ThreeTierEvaluator;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:283
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
doc | DocumentModel | The persistent document model. |
engine | EvaluatorHost | The expression engine (shared VM is accessed via engine.getVM()). |
checkpointer? | VMCheckpointer | Optional VM state checkpointer. If provided, the evaluator will create checkpoints after variable-definition lines and support fast VM restoration via restoreTo(). If omitted, checkpointing is disabled. |
Returns
Section titled “Returns”ThreeTierEvaluator
Methods
Section titled “Methods”applyTransaction()
Section titled “applyTransaction()”applyTransaction(changes): { edited: number[]; inserted: number[]; removed: number[];};Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:831
Apply incremental line-level changes to the document model.
Phase 5.2f: Replaces the O(N) setDocument() + full re-evaluation
with O(changed) incremental updates. Key benefits:
- Unchanged lines retain their persistent lineIds → bytecode survives
- Only changed + DAG-downstream lines are marked dirty → Tier 1 re-evaluation
- Clean lines in viewport use Tier 2 (cached bytecode execution)
- Clean lines outside viewport are skipped entirely
The DAG is fully cleared after propagation: shifted lines would have
stale entries keyed by old line numbers, so the DAG is rebuilt from
scratch during the subsequent evaluate() call.
Caller should follow up with evaluate(viewport) to re-evaluate
dirty lines from line 1 and rebuild the DAG + checkpoints.
A transaction in which every change replaces as many lines as it
deletes (a keystroke inside a line, sent as delete-one-insert-one) moves
no line, and is applied in place through DocumentModel.editLine
instead: the lines keep their ids, nothing is renumbered or cleared, and
the ids of the lines whose text changed come back in edited, with
inserted and removed empty. A transaction with any change that alters
the line count takes the structural path for all of it (#713).
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
changes | LineChange[] | Line-level changes to apply. Must be non-overlapping. |
Returns
Section titled “Returns”{ edited: number[]; inserted: number[]; removed: number[];}Metadata about the applied changes.
edited
Section titled “edited”edited: number[];inserted
Section titled “inserted”inserted: number[];removed
Section titled “removed”removed: number[];backgroundCompile()
Section titled “backgroundCompile()”backgroundCompile(viewport): EvalLineResult[];Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:501
Background-compile invisible dirty lines beyond the viewport (Tier 3 only).
Compiles expressions to discover reads/writes for the dependency graph without executing display-only expressions. Variable definitions are executed to maintain VM state for future Tier-2 executions.
This is intended to be called after evaluate() so visible lines are rendered first, then background work fills in the dependency graph.
Phase 5.2h: This synchronous method is retained for environments
without Worker support. Prefer dispatchBackgroundCompiles() which
offloads compilation to a Web Worker with Transferable bytecode.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
viewport | ViewportRange |
Returns
Section titled “Returns”dispatchBackgroundCompiles()
Section titled “dispatchBackgroundCompiles()”dispatchBackgroundCompiles(viewport): void;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:554
Dispatch background compilation to a Web Worker (Phase 5.2h).
Collects invisible dirty lines beyond the viewport that need compilation, sends them to the compilation worker, and asynchronously stores the transferred bytecode in the DocumentModel when the worker responds.
This is the non-blocking alternative to backgroundCompile(). The worker
compiles expressions with Transferable ArrayBuffers (zero-copy postMessage),
so bytecode appears on the main thread without serialization overhead.
Lines that already have cached bytecode (from a previous worker pass or synchronous compile) are skipped, only truly uncompiled dirty lines are sent to the worker.
Usage: Call after evaluate() so visible lines render first, then
this fills the bytecode cache for future Tier-2 scrolls.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
viewport | ViewportRange | The current visible range. Lines beyond viewport.endLine that are dirty and don’t have bytecode are dispatched. |
Returns
Section titled “Returns”void
dispose()
Section titled “dispose()”dispose(): void;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:650
Retire this evaluator: the call a host makes when the document it serves is closed or replaced by another.
It stops the background compilation worker, if one was started, and
drops the evaluator’s subscription to the shared global :name store.
Until then the store holds a reference to the evaluator, so one that is
never retired stays reachable (and keeps marking its lines dirty) after
the host has let go of it.
It also detaches the evaluator from the engine, where the engine still
points at it: the engine’s document model and its async batcher’s
checkpoint chain are cleared if they are this evaluator’s own. Left in
place, the engine went on answering from the retired document, so a
later evaluateLine("line 1 * 2") read a line of a note the host had
closed rather than refusing for want of a document. An engine an evaluator
built since has taken over is left alone.
terminateWorker is the first half of this and keeps working as
it did. dispose is safe to make more than once. The document model and
the engine themselves are left intact: the host owns both, and may build
a new evaluator over them.
Returns
Section titled “Returns”void
evaluate()
Section titled “evaluate()”evaluate(viewport, signal?): EvalResult;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:362
Evaluate all lines needed to render the given viewport.
Processes lines from 1 to viewport.endLine in document order.
Dirty lines in the viewport, and above it, get the Tier-1 full
pipeline; clean cached lines in it get Tier-2 bytecode execution; clean
lines above it are skipped. Each line that runs reads the VM as a pass
from line 1 leaves it at that line (see runAt). Lines after the viewport
are not visited; backgroundCompile gives them Tier-3 compile-only.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
viewport | ViewportRange |
signal? | AbortSignal |
Returns
Section titled “Returns”Results for all processed lines, including tier metadata.
evaluateAll()
Section titled “evaluateAll()”evaluateAll(signal?): EvalResult;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:688
Evaluate all dirty lines in the document, regardless of viewport. Used for full re-evaluation after plugin register/unregister.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
signal? | AbortSignal |
Returns
Section titled “Returns”getCheckpointer()
Section titled “getCheckpointer()”getCheckpointer(): VMCheckpointer | null;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:2419
Get the VM checkpointer, or null if checkpointing is disabled.
Returns
Section titled “Returns”VMCheckpointer | null
getDoc()
Section titled “getDoc()”getDoc(): DocumentModel;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:680
Get the DocumentModel (read-only access for decoration building).
Returns
Section titled “Returns”getPageManager()
Section titled “getPageManager()”getPageManager(): PageManager;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:2427
Get the PageManager (Phase 5.2g). Exposed for testing.
Returns
Section titled “Returns”PageManager
restoreTo()
Section titled “restoreTo()”restoreTo(lineNumber): void;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:2410
Restore the VM to the state at or just after the given line number.
Finds the nearest checkpoint at or before lineNumber and replays
all variable definitions from the checkpoint chain into the VM.
After calling this, the VM is ready to evaluate lines starting at
lineNumber + 1 without re-evaluating all preceding lines.
Usage: Phase 5.2e’s setViewport() calls restoreTo(viewport.startLine - 1)
before evaluating only the newly visible lines. This is the key to
O(visible lines) scrolling.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
lineNumber | number | The line number to restore to. Variables defined at lines ≤ this number will be available in the VM. |
Returns
Section titled “Returns”void
setViewport()
Section titled “setViewport()”setViewport(viewport, signal?): EvalResult;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:723
Zero-allocation viewport evaluation, the Phase 5.2e “holy grail.”
Key insight: When the user scrolls (viewport-only change, no edits), we don’t need to re-evaluate from line 1. Instead:
- Restore the VM to just before the viewport via the nearest checkpoint.
- Evaluate ONLY the visible lines (Tier 2 for clean cached, Tier 1 for dirty).
- Lines before the viewport are completely skipped, their state lives in the VM checkpointer’s prototypal chain.
Correctness guard: If any variable-definition line before the viewport
is dirty (e.g., the user edited a variable def that hasn’t been
re-evaluated yet), we clear stale checkpoints and fall back to evaluate()
which processes from line 1 and rebuilds fresh checkpoints. This
guarantees that stale checkpoints are never used as restoration targets.
Only variable-def lines matter here, VMCheckpointer.snapshot() only
records state for lines that write a variable, so a dirty plain-expression
line before the viewport has no checkpoint to invalidate (see
DocumentModel.hasAnyDirtyVariableDefLineBefore()).
Performance: O(visible lines) instead of O(document length). Target: < 1ms for a typical ~30-line viewport, independent of document size.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
viewport | ViewportRange | The visible line range. |
signal? | AbortSignal | - |
Returns
Section titled “Returns”Results for visible lines only. Lines before the viewport are
not included in lines[] or resultMap.
terminateWorker()
Section titled “terminateWorker()”terminateWorker(): void;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:616
Terminate the compilation worker if active, and unsubscribe from sharedGlobalVariableStore. Call this when the evaluator is no longer needed to clean up resources, every call site that retires a ThreeTierEvaluator (document switch, pane destroy()) already calls this unconditionally, so folding the global-store unsubscribe in here needs no new call sites anywhere.
Returns
Section titled “Returns”void