/** * Trampoline evaluator — explicit-stack evaluation engine. * * `stepNode(node, env, k)` maps an AST node to the next `Step`. * `applyFrame(frame, value, k)` processes a completed sub-result against a frame. * `tick(step)` processes one step and returns the next (or a Promise for async). * `runSyncTrampoline(step)` runs the trampoline synchronously to completion. * `runAsyncTrampoline(step)` runs the trampoline asynchronously to completion. * * Entry points: * - `evaluate(ast, contextStack)` — evaluate an AST (sync or async) * - `evaluateNode(node, contextStack)` — evaluate a single node (sync or async) * * Design principles: * - `stepNode` is always synchronous and returns `Step`. * - `applyFrame` may return `Step | Promise` when normal expressions * or compound function types produce async results. * - Normal built-in expressions are called directly with pre-evaluated args. * - All binding and pattern matching use frame-based slot processing. * - All state lives in frames (no JS closures) — enabling serialization later. */ import type { Any } from '../interface'; import type { Ast, AstNode, BindingTarget } from '../parser/types'; import type { SourceCodeInfo } from '../tokenizer/token'; import type { MaybePromise } from '../utils/maybePromise'; import type { Handlers, RunResult, Snapshot, SnapshotState } from './effectTypes'; import type { ContextStack } from './ContextStack'; import type { DeserializeOptions } from './suspension'; import type { ContinuationStack, Frame } from './frames'; import type { Step } from './step'; export type { Step }; /** * Given an AST node, its environment, and a continuation stack, return * the next Step for the trampoline to process. * * Leaf nodes (numbers, strings, symbols) immediately produce values. * Compound nodes (expressions) push frames and return sub-evaluations. */ export declare function stepNode(node: AstNode, env: ContextStack, k: ContinuationStack): Step | Promise; /** * Given a completed sub-expression value and the top frame from the * continuation stack, determine the next Step. */ export declare function applyFrame(frame: Frame, value: Any, k: ContinuationStack): Step | Promise; type SnapshotStateSeed = SnapshotState | { snapshots: Snapshot[]; nextSnapshotIndex: number; maxSnapshots?: number; autoCheckpoint?: boolean; }; /** * Start processing a binding pattern using linearized slots. * This is the entry point for frame-based destructuring. * @internal Exported for testing/incremental migration */ export declare function startBindingSlots(target: BindingTarget, rootValue: Any, env: ContextStack, sourceCodeInfo: SourceCodeInfo | undefined, k: ContinuationStack): Step; /** * Process one step of the trampoline. Returns the next step, or a * Promise when an async operation (e.g., native JS function) is * encountered. * * - `Value` with empty `k`: the program is done (terminal state). * - `Value` with non-empty `k`: pop the top frame and apply it. * - `Eval`: evaluate an AST node via `stepNode` (always synchronous). * - `Apply`: apply a frame to a value (may return Promise). * - `Perform`: effect dispatch — local (try/with) first, then host handlers. * * When `handlers` and `signal` are provided (from `run()`), host handlers are * available as a fallback for effects not matched by any local `try/with`. */ export declare function tick(step: Step, handlers?: Handlers, signal?: AbortSignal, snapshotState?: SnapshotState): Step | Promise; /** * Run the trampoline synchronously to completion. * Throws if any step produces a Promise (i.e., an async operation was * encountered in a synchronous context). */ export declare function runSyncTrampoline(initial: Step, effectHandlers?: Handlers): Any; /** * Run the trampoline asynchronously to completion. * Awaits any Promise that surfaces from async operations. */ export declare function runAsyncTrampoline(initial: Step): Promise; /** * Evaluate an AST using the trampoline. * Returns the final value synchronously, or a Promise if async operations * are involved (e.g., native JS functions returning Promises). */ export declare function evaluate(ast: Ast, contextStack: ContextStack): MaybePromise; /** * Evaluate an AST using the async trampoline directly. * Use this when the caller knows that async operations may be involved * (e.g., from Dvala.async.run) to avoid the sync-first-then-retry pattern * which can cause side effects to be executed twice. */ export declare function evaluateAsync(ast: Ast, contextStack: ContextStack): Promise; /** * Evaluate a single AST node using the trampoline. * Used as the `evaluateNode` callback passed to `getUndefinedSymbols` * and other utilities. */ export declare function evaluateNode(node: AstNode, contextStack: ContextStack): MaybePromise; /** * Evaluate an AST with full effect handler support. * * Uses the async trampoline loop, passing `handlers` and `signal` to `tick` * so that `dispatchPerform` can fall back to host handlers when no local * `try/with` matches. * * Always resolves — never rejects. All errors are captured in * `RunResult.error`. Suspension is signaled via `RunResult.suspended`. * * The `AbortController` is created internally per `run()` call. The signal * is passed to every host handler. Used for `race()` cancellation (Phase 6) * and host-side timeouts. */ export declare function evaluateWithEffects(ast: Ast, contextStack: ContextStack, handlers?: Handlers, maxSnapshots?: number, deserializeOptions?: DeserializeOptions, autoCheckpoint?: boolean, terminalSnapshot?: boolean, onNodeEval?: SnapshotState['onNodeEval']): Promise; /** * Evaluate an AST synchronously with effect handler support. * * Uses the sync trampoline with `effectHandlers` threaded through `tick`. * Throws if an async operation is encountered (e.g., an async handler * is used). Handlers may call `resume(value)`, `fail(msg?)`, or `next()`. * Calling `suspend()` will throw a runtime error. */ export declare function evaluateWithSyncEffects(ast: Ast, contextStack: ContextStack, effectHandlers?: Handlers): Any; /** * Resume a suspended continuation with a value. * * Re-enters the trampoline with `{ type: 'Value', value, k }` where `k` is * the deserialized continuation stack. Host handlers and signal are provided * fresh for this run. */ export declare function resumeWithEffects(k: ContinuationStack, value: Any, handlers?: Handlers, initialSnapshotState?: SnapshotStateSeed, deserializeOptions?: DeserializeOptions): Promise; export declare function continueWithEffects(initial: Step, handlers?: Handlers, initialSnapshotState?: SnapshotStateSeed, deserializeOptions?: DeserializeOptions, terminalSnapshot?: boolean): Promise; /** * Re-trigger the effect from a suspended snapshot. * * Deserializes the continuation from `snapshot` and re-dispatches the * original effect (captured in `snapshot.effectName` / `snapshot.effectArg`) * to the registered host handlers. The handler then calls `resume(value)`, * `fail()`, or `suspend()` as normal. * * Throws if the snapshot has no captured effect (e.g. suspended from a * parallel/race branch rather than an effect handler). */ export declare function retriggerWithEffects(k: ContinuationStack, effectName: string, effectArg: unknown, handlers?: Handlers, initialSnapshotState?: SnapshotStateSeed, deserializeOptions?: DeserializeOptions, outerSignal?: AbortSignal, inheritedExecutionId?: string): Promise;