mathjslab
Version:
MathJSLab - An interpreter with language syntax like MATLAB®/Octave, ISBN 978-65-00-82338-7.
152 lines (151 loc) • 6.1 kB
TypeScript
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;