mathjslab
Version:
MathJSLab - An interpreter with language syntax like MATLAB®/Octave, ISBN 978-65-00-82338-7.
111 lines (110 loc) • 5.53 kB
TypeScript
import type { FunctionTable, NameEntry, NameTable, NodeExpr, NodeFunctionDefinition, NodeInput } from './AST';
import { CharString } from './AST';
type WorkspaceScope = {
parent?: WorkspaceScope;
nameTable: NameTable;
functionTable: FunctionTable;
resolveParentNames: boolean;
defineName(name: string, node: NodeInput): NameEntry;
hasLocalName(name: string): boolean;
};
type ThrowSyntaxError = (message: string) => never;
type EvaluateInScope = (source: string, scope: WorkspaceScope) => NodeInput;
/**
* Workspace helpers shared by function calls and MATLAB/Octave workspace
* built-ins.
*
* This module owns the non-parser parts of `persistent`, `global`, `inputname`,
* `eval`, `evalin`, and `assignin`. Keeping these operations outside
* `Interpreter.ts` makes the execution rules visible and testable without
* requiring a full interpreter instance.
*/
declare class FunctionWorkspace {
/**
* Ensure that a function definition has its persistent-variable table.
*
* Persistent storage lives on the function definition node itself, matching
* the lifetime of a parsed function definition. Call scopes receive copies
* when the function is entered and write values back when it returns.
*/
static ensurePersistentTable(func: NodeFunctionDefinition): Record<string, NodeInput>;
/**
* Copy all variable/function entries visible from `source` into `target`.
*
* The copy walks from outermost to innermost scope so local entries shadow
* parent entries. It stops when a scope disables parent-name resolution,
* preserving detached closure snapshots.
*/
static copyVisibleScopeEntries(target: Pick<WorkspaceScope, 'nameTable' | 'functionTable'>, source?: WorkspaceScope): void;
/**
* Implement `inputname(n)` using the original unevaluated call arguments.
*
* MATLAB/Octave return an empty string when the selected argument is not a
* plain identifier or when the index is outside the supplied input list.
*/
static inputName(inputArgs: NodeExpr[], indexNode: NodeInput, throwSyntaxError: ThrowSyntaxError): CharString;
/**
* Resolve `base` and `caller` workspace names for `evalin` and `assignin`.
*
* External files are intentionally not handled here; the browser UI owns
* external-file access, so this helper only models in-memory workspaces.
*/
static resolveWorkspace(name: string, baseScope: WorkspaceScope, callerScope: WorkspaceScope, throwSyntaxError: ThrowSyntaxError): WorkspaceScope;
/**
* Evaluate source in a target workspace, optionally running a catch string.
*
* This models the two-argument `eval`/three-argument `evalin` form while
* leaving parsing and execution to the callback supplied by the interpreter.
*/
static evaluateWithCatch(scope: WorkspaceScope, source: string, catchSource: string | undefined, evaluate: EvaluateInScope): NodeInput;
/**
* Implement `assignin` after the interpreter has resolved the workspace.
*
* Values are copied before storage to avoid aliasing the caller's AST node.
* The result is `VOID` because assignment-by-side-effect should not display
* an answer in the command UI.
*/
static assignIn(scope: Pick<WorkspaceScope, 'defineName'>, name: string, value: NodeInput): NodeInput;
/**
* Declare or initialize a persistent variable for a function call.
*
* A declaration without initializer creates an empty-array persistent value
* on first use. A declaration with initializer only initializes the table if
* the name has not been seen before, matching MATLAB/Octave persistent
* semantics.
*/
static declarePersistent(name: string, value: NodeInput | undefined, func: NodeFunctionDefinition, scope: Pick<WorkspaceScope, 'defineName'>): void;
/**
* Load all persistent variables into a fresh function-call scope.
*/
static loadPersistentVariables(func: NodeFunctionDefinition, scope: Pick<WorkspaceScope, 'defineName'>): void;
/**
* Store changed persistent variables back into the function definition.
*
* Only names known to the persistent table are saved. This prevents ordinary
* local variables from becoming persistent accidentally.
*/
static storePersistentVariables(func: NodeFunctionDefinition, scope: Pick<WorkspaceScope, 'hasLocalName' | 'nameTable'>): void;
/**
* Declare a global binding in the current scope.
*
* Local and global scopes share the same `NameEntry` object. Mutating one
* side therefore updates the other, which is the behavior expected by
* MATLAB/Octave-like `global` declarations.
*/
static declareGlobal(name: string, value: NodeInput | undefined, globalNameSet: Set<string>, globalNameTable: NameTable, scopeNameTable: NameTable): void;
/**
* Clear all global variables from global, active, and captured scopes.
*
* Function handles and nested functions can keep references to defining
* scopes. The recursive walk follows those defining scopes so `clear global`
* does not leave stale global aliases hidden in closures.
*/
static clearGlobalVariables(globalNameSet: Set<string>, globalScope: WorkspaceScope | undefined, callScopes: WorkspaceScope[]): void;
}
export type { WorkspaceScope };
export { FunctionWorkspace };
declare const _default: {
FunctionWorkspace: typeof FunctionWorkspace;
};
export default _default;