/**
 * Tree-walking interpreter + sandbox + path resolver — Task H.1.4.
 *
 * Sandbox guarantees (pre-research §3.3):
 *   1. No string-eval / no dynamic Function-constructor — audit-grep
 *      invariant on this file (see pre-research §3.1 on why we reject
 *      Node's vm + the VM2 family).
 *   2. No prototype access — every path step uses `Object.hasOwn`, blocking
 *      reserved JS property names like the dunder-proto slot, the ctor
 *      slot, the proto slot, toString, etc.
 *   3. Depth cap 64 — guards against stack-overflow from pathological ASTs.
 *      Counted at each recursive `evaluate()` entry (depth + 1 per descent).
 *   4. Step cap 10_000 — guards against compute-bound DoS from compound
 *      expressions. Counted at every `evaluate()` call (before any branch).
 *   5. Allow-listed function dispatch only — `FUNCTIONS` registry lookup
 *      (frozen, null-prototype base — see functions.ts); missing names
 *      throw `InterpreterRuntimeError`. Tests inject a per-call writable
 *      registry via `EvalCtx.functions`; production callers omit it and
 *      get the audited 5-function default (`len`, `contains`, `match`,
 *      `startsWith`, `endsWith`).
 *   6. No filesystem / network / process / time / random access in any path.
 *   7. Comparison operators use STRICT equality per pre-research §12.3 lock
 *      — no `String()` coercion. `==` and `===` both lower to the same
 *      `BinaryOp.'=='` (lexer collapses `EqEq`); same for `!=` / `!==`.
 *
 * Errors fall into two classes — both are caught by the outer evaluator
 * driver (lands later in H.1.6) which converts to `false + warn`:
 *   - `InterpreterLimitError` — depth or step cap hit.
 *   - `InterpreterRuntimeError` — unknown function call (only runtime-
 *     reachable error in H.1.4; type-mismatches return `false`, not throw).
 *
 * Design comparison (pre-research §3.1): we use the Lua/Cerbos pattern of
 * runtime visit-counting rather than Cerbos's precomputed cost analysis
 * (simpler, equally safe for our size). We explicitly REJECT Node's `vm`
 * module + VM2 (CVE-2023-29017) — the tree-walking interpreter pattern is
 * the safe choice for in-process untrusted expression evaluation.
 */
import { type ASTNode } from './ast.js';
import { type FnHandler } from './functions.js';
/** AST-nesting depth cap. See pre-research §3.2. */
export declare const MAX_DEPTH = 64;
/** Per-eval node-visit cap. See pre-research §3.2. */
export declare const MAX_STEPS = 10000;
/** Thrown when depth or step cap is exceeded. Caller converts to `false`. */
export declare class InterpreterLimitError extends Error {
    constructor(message: string);
}
/** Thrown for runtime conditions like unknown function names. */
export declare class InterpreterRuntimeError extends Error {
    constructor(message: string);
}
/**
 * Per-evaluation context. Pass a fresh `EvalCtx` per top-level evaluation —
 * `steps` is mutated to count every node visit across the whole tree.
 * `bindings` is a plain `Map` so author-supplied keys can't collide with
 * Object.prototype keys (a `Map<string, unknown>` doesn't share prototype
 * keys with the binding value lookups).
 */
export interface EvalCtx {
    bindings: Map<string, unknown>;
    /** Mutated per visit; `evaluate` throws `InterpreterLimitError` on overrun. */
    steps: number;
    /**
     * Optional function-registry override. Defaults to the frozen `FUNCTIONS`
     * import. Tests pass a per-call writable registry to inject throwing
     * stubs (short-circuit proofs) and arg-passthrough captures without
     * mutating the frozen production registry. Production callers (the H.1.6
     * `evalCondition` driver) omit this field — the default is the correct,
     * audited allow-list.
     */
    functions?: Record<string, FnHandler>;
}
/**
 * Tree-walking evaluator. Returns the typed value of `node` under `ctx`.
 *
 * Recursion contract: increment `depth + 1` at every recursive call so the
 * depth cap measures AST nesting, not call-stack depth (these would diverge
 * if helpers like `resolvePath` recursed). Increment `ctx.steps` at the top
 * of each call before any branching so the step cap catches pathological
 * trees even when the work happens inside a binary's RHS.
 */
export declare function evaluate(node: ASTNode, ctx: EvalCtx, depth?: number): unknown;
//# sourceMappingURL=interpreter.d.ts.map