import type { FunctionTable, NameEntry, NameTable, NodeBuiltInFunction, NodeExpr, NodeFunctionDefinition, NodeInput, UndefinedReferenceTable } from './AST';
/**
 * Represents a lexical workspace/scope.
 *
 * A scope stores variable bindings, function bindings, and forward-reference
 * bookkeeping. The parent chain models MATLAB/Octave-like lexical lookup for
 * ordinary functions, nested functions, anonymous-function closures, `eval`,
 * `evalin`, `assignin`, `global`, and `persistent`.
 *
 * Two flags tune lookup/assignment for special function-workspace cases:
 *
 * - `resolveParentNames`: when false, variable lookup stops at this scope.
 *   This is used for captured snapshots where later parent changes must not
 *   leak into a closure.
 * - `assignExistingParentNames`: when true, assignments update an existing
 *   parent binding instead of always creating a local name. Nested functions use
 *   this to emulate MATLAB/Octave shared workspaces.
 */
declare class Scope {
    parent?: Scope | undefined;
    nameTable: NameTable;
    functionTable: FunctionTable;
    undefinedReferenceTable: UndefinedReferenceTable;
    resolveParentNames: boolean;
    assignExistingParentNames: boolean;
    /**
     * Use `Scope.create` so scope tables are always prototype-less maps.
     */
    private constructor();
    /**
     * Create a fresh scope with empty name/function/reference tables.
     *
     * @param parent Optional parent scope for lexical lookup.
     * @param resolveParentNames Whether variable lookup may continue into the parent chain.
     */
    static readonly create: (parent?: Scope, resolveParentNames?: boolean) => Scope;
    /**
     * Define or replace a variable in the current scope only.
     *
     * Existing entries are mutated in place so global aliases, persistent
     * bindings, and UI references that point at the entry object continue to see
     * updates.
     */
    defineName(name: string, node: NodeInput, undefinedReference?: string): NameEntry;
    /**
     * Assign a value using the current scope's assignment policy.
     *
     * Ordinary scopes define locally. Nested-function scopes can opt into
     * parent assignment through `assignExistingParentNames`, which preserves
     * MATLAB/Octave shared-variable behavior.
     */
    assignName(name: string, node: NodeInput, undefinedReference?: string): NameEntry;
    /**
     * Define several local variables at once.
     */
    defineNameTable(table: Record<string, NodeInput>): void;
    /**
     * Resolve a variable through this scope and, when allowed, its parents.
     */
    resolveName(name: string): NameEntry | undefined;
    /**
     * Check whether a name is defined directly in this scope.
     */
    hasLocalName(name: string): boolean;
    /**
     * Remove a local variable binding.
     */
    removeName(name: string): void;
    /**
     * Remove a variable binding from this scope and all parents.
     */
    clearName(name: string): void;
    /**
     * Define or replace a function in the current scope only.
     */
    defineFunction(name: string, func: NodeFunctionDefinition): NodeFunctionDefinition;
    /**
     * Merge a function table into this scope.
     */
    defineFunctionTable(table: FunctionTable): void;
    /**
     * Resolve a function through the lexical function table chain.
     *
     * Function lookup intentionally remains parent-aware even when
     * `resolveParentNames` is false; captured scopes still need live fallback
     * for forward-referenced local/nested functions.
     */
    resolveFunction(name: string): NodeFunctionDefinition | NodeBuiltInFunction | undefined;
    /**
     * Check whether a function is defined directly in this scope.
     */
    hasLocalFunction(name: string): boolean;
    /**
     * Remove a local function binding.
     */
    removeFunction(name: string): void;
    /**
     * Remove a function binding from this scope and all parents.
     */
    clearFunction(name: string): void;
    /**
     * Bind formal parameter names to already evaluated argument nodes.
     */
    bindParameters(names: string[], args: NodeExpr[]): void;
    /**
     * Bind formal parameters after checking exact arity.
     *
     * This low-level helper predates the richer function-call pipeline and is
     * kept for focused tests and simple call paths.
     */
    bindParametersChecked(names: string[], args: NodeExpr[]): void;
    /**
     * Record that `name` depends on an unresolved identifier.
     *
     * Forward references are stored per scope so assigning a missing name can
     * later trigger re-resolution without confusing unrelated workspaces.
     */
    defineUndefinedReference(name: string, undefinedReference: string): string[];
    /**
     * Resolve unresolved-reference metadata through the parent chain.
     */
    resolveUndefinedReference(name: string): string[] | undefined;
    /**
     * Remove a local unresolved-reference entry.
     */
    removeUndefinedReference(name: string): void;
    /**
     * Remove unresolved-reference metadata from this scope and all parents.
     */
    clearUndefinedReference(name: string): void;
    /**
     * Deep-copy the visible variable/function environment into a detached chain.
     *
     * Anonymous functions use snapshots so captured variables keep the value
     * they had when the handle was created. Function tables and unresolved
     * reference lists are also copied so later forward-reference resolution
     * remains deterministic for the captured environment.
     */
    snapshot(copyNode: (node: NodeInput) => NodeInput): Scope;
    /**
     * Create a lexical overlay over the current scope.
     *
     * Current local entries are copied, while misses fall back to the live
     * parent scope. Named local/nested function handles use this mode: existing
     * bindings are stable, but later function definitions can still be resolved
     * through the parent chain.
     */
    capture(copyNode: (node: NodeInput) => NodeInput, resolveParentNames?: boolean): Scope;
}
export { Scope };
export default Scope;
