mathjslab
Version:
MathJSLab - An interpreter with language syntax like MATLAB®/Octave, ISBN 978-65-00-82338-7.
726 lines (725 loc) • 22 kB
TypeScript
import { CharString, StringQuoteCharacter } from './CharString';
import { ComplexType } from './Complex';
import { Scope } from './Scope';
import { FunctionHandle } from './FunctionHandle';
import { type ElementType, MultiArray } from './MultiArray';
/**
* AST (Abstract Syntax Tree).
*/
/**
* Operator type.
*/
type OperatorType = '+' | '-' | '.*' | '*' | './' | '/' | '.\\' | '\\' | '.^' | '^' | '.**' | '**' | '<' | '<=' | '==' | '>=' | '>' | '!=' | '~=' | '&' | '|' | '&&' | '||' | '=' | '+=' | '-=' | '*=' | '/=' | '\\=' | '^=' | '**=' | '.*=' | './=' | '.\\=' | '.^=' | '.**=' | '&=' | '|=' | '()' | '!' | '~' | '+_' | '-_' | '++_' | '--_' | ".'" | "'" | '_++' | '_--';
/**
* Delimiter used by an index expression.
*
* Parentheses mean ordinary array/function indexing; braces mean cell-array
* content indexing.
*/
type IndexingDelimiterType = '()' | '{}';
/**
* NodeType
*/
type NodeType = 'IDENT' | 'CMDWLIST' | 'IDX' | 'RANGE' | 'ENDRANGE' | 'LIST' | '.' | ':' | '<~>' | 'VOID' | 'RETLIST' | 'FCNDEF' | 'USERFCN' | 'BUILTIN' | 'ARGVALID' | 'ARGS' | 'GLOBAL' | 'PERSIST' | 'RETURN' | 'IF' | 'ELSEIF' | 'ELSE' | 'SWITCH' | 'CASE' | OperatorType;
/**
* Table of symbolic aliases recognized by the lexer/parser layer.
*/
type AliasNameTable = Record<string, RegExp>;
/**
* Node base.
*/
interface NodeBase {
type: NodeType | number;
parent?: any;
index?: number;
omitOutput?: boolean;
omitAnswer?: boolean;
start?: {
line: number;
column: number;
};
stop?: {
line: number;
column: number;
};
}
/**
* Explicit "no value" node.
*/
interface NodeVoid extends NodeBase {
type: 'VOID';
}
/**
* Any AST node that can be used as an executable/evaluable input.
*/
type NodeInput = NodeExpr | NodeList | NodeDeclaration | NodeReturn | NodeIf | NodeSwitch;
/**
* Expression node.
*/
type NodeExpr = ElementType | NodeIdentifier | NodeIndexExpr | NodeOperation | NodeRange | NodeIndirectRef | NodeReturnList | any;
/**
* Reserved node.
*/
interface NodeReserved extends NodeBase {
}
/**
* Literal node.
*/
interface NodeLiteral extends NodeBase {
}
/**
* Name node.
*/
interface NodeIdentifier extends NodeBase {
type: 'IDENT';
id: string;
}
/**
* Command word list node.
*/
interface NodeCmdWList extends NodeBase {
type: 'CMDWLIST';
id: string;
args: CharString[];
}
/**
* Expression and arguments node.
*/
interface NodeIndexExpr extends NodeBase {
type: 'IDX';
expr: NodeExpr;
exprEvaluated?: NodeExpr;
args: NodeExpr[];
delim: IndexingDelimiterType;
}
/**
* Range node.
*/
interface NodeRange extends NodeBase {
type: 'RANGE';
start_: NodeExpr | null;
stop_: NodeExpr | null;
stride_: NodeExpr | null;
}
/**
* Colon token node used by ranges and indexing.
*/
interface NodeColon extends NodeBase {
type: ':';
}
/**
* `end` token node used inside indexing ranges.
*/
interface NodeEndRange extends NodeBase {
type: 'ENDRANGE';
}
/**
* Operation node.
*/
type NodeOperation = UnaryOperation | BinaryOperation;
/**
* Unary operation node.
*/
type UnaryOperation = UnaryOperationL | UnaryOperationR;
/**
* Right unary operation node.
*/
interface UnaryOperationR extends NodeBase {
right: NodeExpr;
}
/**
* Left unary operation node.
*/
interface UnaryOperationL extends NodeBase {
left: NodeExpr;
}
/**
* Binary operation.
*/
interface BinaryOperation extends NodeBase {
left: NodeExpr;
right: NodeExpr;
}
/**
* Ignored return target (`~`) in a return or assignment list.
*/
interface NodeIgnoredTarget extends NodeBase {
type: '<~>';
}
/**
* List node
*/
interface NodeList extends NodeBase {
type: 'LIST';
list: NodeInput[];
}
/**
* Dot-reference node for structures and chained field access.
*/
interface NodeIndirectRef extends NodeBase {
type: '.';
obj: NodeExpr;
field: (string | NodeExpr)[];
}
/**
* Lazily evaluated return values keyed by result name.
*/
type ReturnHandlerResult = {
length: number;
} & Record<string, NodeExpr>;
/**
* Select a single output from a realized return handler result.
*/
type ReturnSelector = (evaluated: ReturnHandlerResult, index: number) => NodeExpr;
/**
* Materialize the outputs requested by a caller.
*/
type ReturnHandler = (length: number) => ReturnHandlerResult;
/**
* Error callback used by AST helpers that should not depend on Interpreter.
*/
type ThrowError = (message: string) => never;
/**
* Return list node
*/
interface NodeReturnList extends NodeBase {
type: 'RETLIST';
selector: ReturnSelector;
handler: ReturnHandler;
}
/**
* Common fields shared by user-defined and built-in functions.
*/
interface NodeFunction extends NodeBase {
type: 'FCNDEF' | 'BUILTIN';
id: string;
mapper: boolean;
ev: boolean[];
func: Function;
definingScope?: Scope;
attributes?: {
/**
* Per-function persistent variable storage.
*
* Values are copied into the call scope at function entry and copied
* back after execution. The table lives on the function node so it
* survives between calls while the definition remains registered.
*/
persistent?: Record<string, NodeInput>;
/**
* Marks function definitions registered from inside another function.
*
* Nested functions share selected parent-scope bindings and are reported
* as nested by introspection helpers such as `which` and `functions`.
*/
nested?: boolean;
};
}
/**
* AST node for a MATLAB/Octave-like user function definition.
*/
interface NodeFunctionDefinition extends NodeFunction {
type: 'FCNDEF';
/**
* Return variables (IDENT nodes)
* Example: function [a,b] = f(x)
*/
return: NodeList;
/**
* Formal parameters (IDENT nodes)
*/
parameter: NodeList;
/**
* Argument validation blocks (MATLAB-style).
*
* These blocks are validated during definition registration and function
* calls. They support Input, Output, Repeating, defaults, name-value
* declarations, size/class declarations, and supported validator functions.
*/
arguments: NodeList;
/**
* Function body statements
*/
statements: NodeList;
}
/**
* Declarative arity shape for built-ins.
*
* `arity < 0` denotes a variadic signature. The absolute value is the 1-based
* position where variadic arguments begin, matching the convention used by
* MATLAB/Octave `nargin`/`nargout` introspection.
*/
interface BuiltInFunctionArity {
arity: number;
min?: number;
max?: number;
}
/**
* Supported declarative validators for built-in function parameters.
*/
type BuiltInFunctionParameterValidator = 'numeric' | 'numericOrLogical' | 'text' | 'textScalar' | 'scalar' | 'scalarOrEmpty' | 'scalarOrVector' | 'empty' | 'matrix2d' | 'squareMatrix' | 'vector' | 'twoElement' | 'oneOrTwoElement' | 'dimension' | 'dimensionGreaterThanOne' | 'dimensionVector' | 'reshapeDimension' | 'reshapeDimensionVector' | 'nonempty' | 'positive' | 'nonnegative' | 'nonzero' | 'zeroOrOne' | 'integer' | 'finite' | 'real';
/**
* One declarative built-in parameter.
*
* The signature validator uses these records to replace ad hoc argument checks
* inside individual built-ins.
*/
interface BuiltInFunctionParameter {
name: string;
classes?: string[];
validators?: BuiltInFunctionParameterValidator[];
allowedStrings?: string[];
identifier?: boolean;
alternatives?: BuiltInFunctionParameter[];
variadicGroup?: BuiltInFunctionParameter[];
allowInfinity?: boolean;
optional?: boolean;
variadic?: boolean;
}
/**
* One input overload for a built-in function.
*/
interface BuiltInFunctionInputSignature extends BuiltInFunctionArity {
parameters?: BuiltInFunctionParameter[];
}
/**
* Declarative built-in signature metadata.
*/
interface BuiltInFunctionSignature {
inputs?: BuiltInFunctionInputSignature | BuiltInFunctionInputSignature[];
outputs?: BuiltInFunctionArity | BuiltInFunctionArity[];
}
/**
* Built-in function node registered by the runtime.
*/
interface NodeBuiltInFunction extends NodeFunction {
type: 'BUILTIN';
/**
* Optional declarative call signature used by the shared validator.
*/
signature?: BuiltInFunctionSignature;
UnparserMathML?: (tree: NodeInput) => string;
}
/**
* `builtInFunctionTable` type.
*/
type BuiltInFunctionTable = Record<string, NodeBuiltInFunction>;
/**
* User-defined function table keyed by function name.
*/
type FunctionTable = Record<string, NodeFunctionDefinition>;
/**
* One variable binding in a scope name table.
*/
type NameEntry = {
/**
* Identifier that blocked evaluation when forward references are enabled.
*/
undefinedReference?: string;
/**
* Bound value, if the entry has been assigned.
*/
node?: NodeInput;
/**
* Marks shared entries created by `global`.
*/
global?: boolean;
};
/**
* Variable binding table keyed by identifier.
*/
type NameTable = Record<string, NameEntry>;
/**
* Forward-reference dependency table keyed by identifier.
*/
type UndefinedReferenceTable = Record<string, string[]>;
/**
* `commandWordListFunction` type.
*/
type CommandWordListFunction = (...args: string[]) => any;
/**
* `commandWordListTable` entry type.
*/
type CommandWordListEntry = {
func: CommandWordListFunction;
};
/**
* `commandWordListTable` type.
*/
type CommandWordListTable = Record<string, CommandWordListEntry>;
/**
* One declaration inside an `arguments` block.
*/
interface NodeArgumentValidation extends NodeBase {
type: 'ARGVALID';
/**
* Identifier or name-value target such as `opts.Name`.
*/
name: NodeExpr;
/**
* Literal/symbolic size declaration.
*/
size: NodeInput[];
/**
* Class declaration. May be a single identifier or a list.
*/
class: NodeInput | null;
/**
* Validator function declarations.
*/
functions: NodeInput[];
/**
* Default expression, when declared for an input argument.
*/
default: NodeExpr;
}
/**
* `arguments` block node.
*/
interface NodeArguments extends NodeBase {
type: 'ARGS';
attribute: NodeIdentifier | null;
validation: NodeArgumentValidation[];
}
/**
* Declaration node for `global` and `persistent`.
*/
interface NodeDeclaration extends NodeBase {
type: 'GLOBAL' | 'PERSIST';
list: NodeExpr[];
}
/**
* `return` statement node.
*/
interface NodeReturn extends NodeBase {
type: 'RETURN';
}
/**
* `if` statement node.
*/
interface NodeIf extends NodeBase {
type: 'IF';
expression: NodeExpr[];
then: NodeList[];
else: NodeList | null;
}
/**
* `elseif` clause node.
*/
interface NodeElseIf extends NodeBase {
type: 'ELSEIF';
expression: NodeExpr;
then: NodeList;
}
/**
* `else` clause node.
*/
interface NodeElse extends NodeBase {
type: 'ELSE';
else: NodeList;
}
/**
* `case` clause node.
*/
interface NodeSwitchCase extends NodeBase {
type: 'CASE';
expression: NodeExpr;
then: NodeList;
}
/**
* `switch` statement node.
*/
interface NodeSwitch extends NodeBase {
type: 'SWITCH';
expression: NodeExpr;
cases: NodeSwitchCase[];
otherwise: NodeList | null;
}
/**
* AST (Abstract Syntax Tree) node factory methods.
*/
declare abstract class AST {
/**
* External node factory methods.
*/
static nodeString: (str: string, quote?: StringQuoteCharacter) => CharString;
/**
* External number factory, rebound by `reload`.
*/
static nodeNumber: (value: string) => ComplexType;
/**
* External first-row matrix factory, rebound by `reload`.
*/
static firstRow: (row: ElementType[], iscell?: boolean) => MultiArray;
/**
* External row-append matrix factory, rebound by `reload`.
*/
static appendRow: (M: MultiArray, row: ElementType[]) => MultiArray;
/**
* External empty-array factory, rebound by `reload`.
*/
static emptyArray: (iscell?: boolean | undefined) => MultiArray;
/**
* Reload external node factory methods.
*/
static readonly reload: () => void;
/**
* It makes a shallow copy of the node.
* @param node AST node to copy.
* @returns Shallow copy of `node`.
*/
static readonly nodeCopy: <T = object>(node: T) => T;
/**
* Create an explicit no-value node.
*/
static readonly nodeVoid: () => NodeVoid;
/**
* Create name node.
* @param nodeid
* @returns
*/
static readonly nodeIdentifier: (id: string) => NodeIdentifier;
/**
* Create command word list node.
* @param nodename
* @param nodelist
* @returns
*/
static readonly nodeCmdWList: (nodename: NodeIdentifier, nodelist: NodeList) => NodeCmdWList;
/**
* Create expression and arguments node.
* @param nodeexpr
* @param nodelist
* @returns
*/
static readonly nodeIndexExpr: (nodeexpr: NodeExpr, nodelist?: NodeList | null, delimiter?: IndexingDelimiterType) => NodeIndexExpr;
/**
* Create range node.
* @param start_
* @param stop_
* @param stride_
* @returns NodeRange.
*/
static readonly nodeRange: (start_: NodeExpr, stop_: NodeExpr, stride_?: NodeExpr) => NodeRange;
/**
* Create a colon token node.
*/
static readonly nodeColon: () => NodeColon;
/**
* Create an `end` token node for indexing ranges.
*/
static readonly nodeEndRange: () => NodeEndRange;
/**
* Node types that, by definition, should omit writing to the `ans`
* variable.
*/
private static readonly omitAnswerNodeOperation;
/**
* Create operator node.
* @param op
* @param data1
* @param data2
* @returns
*/
static readonly nodeOperation: (op: OperatorType, data1: NodeExpr, data2?: NodeExpr) => NodeOperation;
/**
* Create an ignored return/assignment target node.
*/
static readonly nodeIgnoredTarget: () => NodeIgnoredTarget;
/**
* Create first element of list node.
* @param node First element of list node.
* @returns A NodeList.
*/
static readonly nodeListFirst: (node?: NodeInput) => NodeList;
/**
* Append node to list node.
* @param lnode NodeList.
* @param node Element to append to list.
* @returns NodeList with element appended.
*/
static readonly appendNodeList: (lnode: NodeList, node: NodeInput) => NodeList;
/**
*
* @param list
* @returns
*/
static readonly nodeList: (list: NodeInput[]) => NodeList;
/**
* Create first row of a MultiArray.
* @param row
* @returns
*/
static readonly nodeFirstRow: (row?: NodeList | null, iscell?: boolean) => MultiArray;
/**
* Append row to MultiArray.
* @param M
* @param row
* @returns
*/
static readonly nodeAppendRow: (M: MultiArray, row?: NodeList | null) => MultiArray;
/**
*
* @param left
* @param right
* @returns
*/
static readonly nodeIndirectRef: (left: NodeExpr, right: string | NodeExpr) => NodeIndirectRef;
/**
* Creates NodeReturnList (multiple assignment)
* @param selector Left side selector function.
* @param handler A handler that returns an object containing the length
* of the multiple assignment and the values evaluated by the function in
* a single execution. The `selector` function uses these values.
* @returns Return list node.
*/
static readonly nodeReturnList: (selector: ReturnSelector, handler?: ReturnHandler) => NodeReturnList;
/**
* Ensures that the node is of type `NodeReturnList`.
* @param node A `NodeExpr`
* @returns `node` as NodeReturnList
*/
static readonly ensureReturnList: (node: NodeExpr) => NodeReturnList;
/**
* Throws error if left hand side length of multiple assignment greater
* than maximum length (to be used in ReturnSelector functions).
* @param maxLength Maximum length of return list.
* @param currentLength Requested length of return list.
*/
static readonly throwErrorIfGreaterThanReturnList: (maxLength: number, currentLength: number, throwError?: ThrowError) => void | never;
/**
* Tests if it is a NodeReturnList and if so reduces it to its first
* element.
* @param value A node.
* @returns Reduced node if `tree` is a NodeReturnList.
*/
static readonly reduceToFirstIfReturnList: (tree: NodeInput) => NodeInput;
/**
* Throw invalid call error if (optional) test is true.
* @param name
*/
static readonly throwInvalidCallError: (name: string, test?: boolean, throwError?: ThrowError) => void | never;
/**
*
* @param id
* @param parameter_list
* @param expression
* @returns
*/
static readonly nodeFunctionHandle: (id?: NodeIdentifier | null, parameter_list?: NodeList | null, expression?: NodeExpr) => FunctionHandle;
/**
*
* @param id
* @param return_list
* @param parameter_list
* @param arguments_list
* @param statements_list
* @returns
*/
static readonly nodeFunctionDefinition: (id: NodeIdentifier, return_list: NodeList, parameter_list: NodeList, arguments_list: NodeList, statements_list: NodeList) => NodeFunctionDefinition;
/**
* Create one `arguments` block declaration.
*
* @param name Identifier or name-value field target.
* @param size Size declaration list.
* @param cl Class declaration node.
* @param functions Validator function list.
* @param dflt Default expression.
* @returns Argument validation node.
*/
static readonly nodeArgumentValidation: (name: NodeExpr, size: NodeList, cl: (NodeInput | null) | undefined, functions: NodeList, dflt?: NodeExpr) => NodeArgumentValidation;
/**
* Create an `arguments` block.
*
* @param attribute Optional block attribute (`Input`, `Output`, `Repeating`).
* @param validationList Declaration list.
* @returns Arguments block node.
*/
static readonly nodeArguments: (attribute: NodeIdentifier | null, validationList: NodeList) => NodeArguments;
/**
* Create the first node for a `global` or `persistent` declaration list.
*/
static readonly nodeDeclarationFirst: (type: "GLOBAL" | "PERSIST") => NodeDeclaration;
/**
* Create a `return` statement node.
*/
static readonly nodeReturn: () => NodeReturn;
/**
* Normalize declaration list entries.
*
* Older generated parser code may append the parser context instead of
* the AST node itself; in that case the actual node is stored in `.node`.
*
* @param declaration Declaration list entry.
* @returns AST node for the declaration entry.
*/
static readonly getDeclarationNode: (declaration: NodeExpr | {
node: NodeExpr;
}) => NodeExpr;
/**
*
* @param node
* @param declaration
* @returns
*/
static readonly nodeAppendDeclaration: (node: NodeDeclaration, declaration: NodeExpr) => NodeDeclaration;
/**
*
* @param expression
* @param then
* @returns
*/
static readonly nodeIfBegin: (expression: NodeExpr, then: NodeList) => NodeIf;
/**
*
* @param nodeIf
* @param nodeElse
* @returns
*/
static readonly nodeIfAppendElse: (nodeIf: NodeIf, nodeElse: NodeElse) => NodeIf;
/**
*
* @param nodeIf
* @param nodeElseIf
* @returns
*/
static readonly nodeIfAppendElseIf: (nodeIf: NodeIf, nodeElseIf: NodeElseIf) => NodeIf;
/**
*
* @param expression
* @param then
* @returns
*/
static readonly nodeElseIf: (expression: NodeExpr, then: NodeList) => NodeElseIf;
/**
*
* @param elseStmt
* @returns
*/
static readonly nodeElse: (elseStmt: NodeList) => NodeElse;
/**
* Create a `switch` statement node.
*/
static readonly nodeSwitch: (expression: NodeExpr, cases: NodeList, otherwise?: NodeList | null) => NodeSwitch;
/**
* Create a `case` clause node.
*/
static readonly nodeSwitchCase: (expression: NodeExpr, then: NodeList) => NodeSwitchCase;
}
export type { OperatorType, IndexingDelimiterType, NodeType, AliasNameTable, NodeBase, NodeInput, NodeExpr, NodeReserved, NodeLiteral, NodeIdentifier, NodeCmdWList, NodeIndexExpr, NodeRange, NodeColon, NodeEndRange, NodeOperation, UnaryOperation, UnaryOperationR, UnaryOperationL, BinaryOperation, NodeIgnoredTarget, NodeList, NodeIndirectRef, ReturnHandlerResult, ReturnHandler, ReturnSelector, NodeReturnList, NodeFunction, NodeFunctionDefinition, BuiltInFunctionParameterValidator, BuiltInFunctionParameter, BuiltInFunctionInputSignature, BuiltInFunctionSignature, NodeBuiltInFunction, BuiltInFunctionTable, FunctionTable, NameEntry, NameTable, UndefinedReferenceTable, CommandWordListFunction, CommandWordListEntry, CommandWordListTable, NodeArgumentValidation, NodeArguments, NodeDeclaration, NodeReturn, NodeIf, NodeElseIf, NodeElse, NodeSwitch, NodeSwitchCase, };
export { AST };
declare const _default: {
AST: typeof AST;
};
export default _default;
/**
* External exports.
*/
export type { SingleQuoteCharacter, DoubleQuoteCharacter, StringQuoteCharacter } from './CharString';
export { singleQuoteCharacter, doubleQuoteCharacter, stringClass, CharString } from './CharString';
export type { Decimal, RealType, NumberObjectType, RealTypeDescriptor, ComplexType } from './Complex';
export { Complex } from './Complex';
export type { ElementType } from './MultiArray';
export { MultiArray } from './MultiArray';
export { Structure } from './Structure';
export { FunctionHandle } from './FunctionHandle';