ThreeTierEvaluator
Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:108
Orchestrates three-tier evaluation over a persistent DocumentModel.
── Tier assignment ───────────────────────────────────────────────── | Tier | Condition | Action | |───────|────────────────────────────────────|───────────────────────────────| | 1 | Visible + Dirty (new/changed) | Full pipeline: lex→parse→compile→execute | | 2 | Visible + Cached (scroll into view)| Execute from cached bytecode | | 3 | Invisible + Dirty | 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:130
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
doc | DocumentModel | The persistent document model. |
engine | ExpressionEngine | 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): { inserted: number[]; removed: number[];};Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:445
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.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
changes | LineChange[] | Line-level changes to apply. Must be non-overlapping. |
Returns
Section titled “Returns”{ inserted: number[]; removed: number[];}Metadata about the applied changes.
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:253
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:299
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
evaluate()
Section titled “evaluate()”evaluate(viewport, signal?): EvalResult;Defined in: packages/engine/src/engine/ThreeTierEvaluator.ts:181
Evaluate all lines needed to render the given viewport.
Processes lines from 1 to viewport.endLine in document order.
Dirty lines in the viewport get Tier-1 full pipeline; clean cached
lines get Tier-2 bytecode execution. Lines after the viewport
get Tier-3 compile-only (with variable-def execution).
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:348
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:1001
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:340
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:1009
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:992
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:383
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:326
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