Comparing version 1.1.10 to 1.1.11
@@ -334,3 +334,7 @@ /** | ||
*/ | ||
validateAssignment(tree: any): any; | ||
validateAssignment(tree: any): { | ||
left: any; | ||
id: string; | ||
args: any[]; | ||
}; | ||
/** | ||
@@ -375,3 +379,3 @@ * Define function in baseFunctionTable. | ||
*/ | ||
Evaluator(tree: any, local: boolean, fname: string): any; | ||
Evaluator(tree: any, local?: boolean, fname?: string): any; | ||
/** | ||
@@ -378,0 +382,0 @@ * Evaluate expression tree. |
import { ComplexDecimal } from './complex-decimal'; | ||
export type Evaluator = any; | ||
/** | ||
* nameTable type (same in evaluator) to be used in MultiArray.setItems | ||
*/ | ||
export type TNameTableEntry = { | ||
args: Array<any>; | ||
expr: any; | ||
}; | ||
export type TNameTable = Record<string, TNameTableEntry>; | ||
export type ArrayElement = MultiArray | ComplexDecimal | any; | ||
@@ -107,3 +115,3 @@ export type dimRange = { | ||
*/ | ||
static evaluate(tree: MultiArray, that: Evaluator, fname: string): MultiArray; | ||
static evaluate(tree: MultiArray, that: Evaluator, local?: boolean, fname?: string): MultiArray; | ||
/** | ||
@@ -177,4 +185,11 @@ * Linearize MultiArray in an array of ComplexDecimal using row-major | ||
static oneRowToDim(M: ComplexDecimal[] | MultiArray): number[]; | ||
static setItems(nameTable: any, id: string, args: any, right: MultiArray): void; | ||
/** | ||
* Set selected items from MultiArray by linear index or subscripts. | ||
* @param nameTable | ||
* @param id | ||
* @param args | ||
* @param right | ||
*/ | ||
static setItems(nameTable: TNameTable, id: string, args: any[], right: MultiArray): void; | ||
/** | ||
* Get selected items from MultiArray by linear index or subscripts. | ||
@@ -181,0 +196,0 @@ * @param M |
{ | ||
"name": "mathjslab", | ||
"version": "1.1.10", | ||
"version": "1.1.11", | ||
"description": "MathJSLab - An interpreter with language syntax like MATLAB®/Octave. ISBN 978-65-00-82338-7", | ||
@@ -5,0 +5,0 @@ "main": "lib/mathjslab.js", |
# MathJSLab | ||
[![npm version](https://badge.fury.io/js/mathjslab.svg)](https://badge.fury.io/js/mathjslab) | ||
[![DOI](https://zenodo.org/badge/606645564.svg)](https://zenodo.org/badge/latestdoi/606645564) | ||
[![MIT License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/sergiolindau/mathjslab/blob/main/LICENSE) | ||
@@ -6,0 +5,0 @@ |
@@ -687,3 +687,3 @@ /** | ||
*/ | ||
public validateAssignment(tree: any): any { | ||
public validateAssignment(tree: any): { left: any; id: string; args: any[] } { | ||
const invalidMessageBase = 'invalid left hand side of assignment'; | ||
@@ -699,3 +699,2 @@ const invalidMessage = `${invalidMessageBase}: cannot assign to a read only value:`; | ||
id: tree.id, | ||
aliasTreeName: this.aliasName(tree.id), | ||
args: [], | ||
@@ -710,3 +709,2 @@ }; | ||
id: tree.expr.id, | ||
aliasTreeName: this.aliasName(tree.expr.id), | ||
args: tree.args, | ||
@@ -830,3 +828,3 @@ }; | ||
*/ | ||
public Evaluator(tree: any, local: boolean, fname: string): any { | ||
public Evaluator(tree: any, local: boolean = false, fname: string = ''): any { | ||
if (this.debug) { | ||
@@ -860,3 +858,3 @@ console.log(`Evaluator(\ntree:${JSON.stringify(tree, null, 2)},\nlocal:${local},\nfname:${fname})`); | ||
/* MATRIX */ | ||
return this.evaluateTensor(tree, this, fname); | ||
return this.evaluateTensor(tree, this, local, fname); | ||
} else if (this.isRange(tree)) { | ||
@@ -924,9 +922,9 @@ /* RANGE */ | ||
case '|=': | ||
let { left, id, aliasTreeName, args } = this.validateAssignment(tree.left); | ||
const { left, id, args } = this.validateAssignment(tree.left); | ||
const op: string = tree.type.substring(0, tree.type.length - 1); | ||
if (args.length === 0) { | ||
/* Name definition */ | ||
/* Name definition. */ | ||
const expr = op.length ? this.nodeOp(op, left, tree.right) : tree.right; | ||
try { | ||
this.nameTable[id] = { args: [], expr: this.Evaluator(expr, false, fname) }; | ||
this.nameTable[id] = { args: [], expr: this.Evaluator(expr) }; | ||
return this.nodeOp('=', left, this.nameTable[id].expr); | ||
@@ -938,14 +936,14 @@ } catch (error) { | ||
} else { | ||
/* Function definition or indexed matrix reference. */ | ||
if (op) { | ||
if (this.nameTable[id]) { | ||
/* Matrix indexing refer at left hand side with operator */ | ||
const right = this.toTensor( | ||
this.Evaluator( | ||
this.nodeOp(op, this.getItems(this.nameTable[id].expr, id, args), this.toTensor(this.Evaluator(tree.right, false, fname))), | ||
false, | ||
fname, | ||
/* Indexed matrix reference on left hand side with operator. */ | ||
this.setItems( | ||
this.nameTable, | ||
id, | ||
args.map((arg: any) => this.linearize(this.Evaluator(arg))), | ||
this.toTensor( | ||
this.Evaluator(this.nodeOp(op, this.getItems(this.nameTable[id].expr, id, args), this.toTensor(this.Evaluator(tree.right))), false, fname), | ||
), | ||
); | ||
args = args.map((arg: any) => this.linearize(this.Evaluator(arg, false, fname))); | ||
this.setItems(this.nameTable, id, args, right); | ||
return this.nodeOp('=', this.nodeName(id), this.nameTable[id].expr); | ||
@@ -956,3 +954,3 @@ } else { | ||
} else { | ||
/* Test if is a function definition (test if args is a list of undefined NAME) */ | ||
/* Test if is a function definition (test if args is a list of undefined NAME). */ | ||
let isFunction: boolean = true; | ||
@@ -972,6 +970,9 @@ for (let i = 0; i < args.length; i++) { | ||
} else { | ||
/* Matrix indexing refer at left hand side */ | ||
const right = this.toTensor(this.Evaluator(tree.right, false, fname)); | ||
args = args.map((arg: any) => this.linearize(this.Evaluator(arg, false, fname))); | ||
this.setItems(this.nameTable, id, args, right); | ||
/* Indexed matrix reference on left hand side. */ | ||
this.setItems( | ||
this.nameTable, | ||
id, | ||
args.map((arg: any) => this.linearize(this.Evaluator(arg))), | ||
this.toTensor(this.Evaluator(tree.right)), | ||
); | ||
return this.nodeOp('=', this.nodeName(id), this.nameTable[id].expr); | ||
@@ -983,16 +984,15 @@ } | ||
if (local && this.localTable[fname] && this.localTable[fname][tree.id]) { | ||
/* Defined in localTable */ | ||
/* Defined in localTable. */ | ||
return this.localTable[fname][tree.id]; | ||
} else if (tree.id in this.nameTable) { | ||
/* Defined in nameTable */ | ||
/* Defined in nameTable. */ | ||
if (this.nameTable[tree.id].args.length === 0) { | ||
/* Defined as name */ | ||
return this.Evaluator(this.nameTable[tree.id].expr, false, fname); | ||
/* Defined as name. */ | ||
return this.Evaluator(this.nameTable[tree.id].expr); | ||
} else { | ||
/* Defined as function name */ | ||
throw new SyntaxError(`calling ${tree.id} function without arguments list.`); | ||
/* Defined as function name. */ | ||
throw new Error(`calling ${tree.id} function without arguments list.`); | ||
} | ||
} | ||
case 'ARG': | ||
let argumentsList: any[] = []; | ||
if (typeof tree.expr === 'undefined') { | ||
@@ -1002,15 +1002,15 @@ throw new Error(`'${tree.id}' undefined.`); | ||
if (tree.expr.type === 'NAME') { | ||
/* Matrix indexing or function call */ | ||
aliasTreeName = this.aliasName(tree.expr.id); | ||
/* Indexed matrix reference or function call. */ | ||
const aliasTreeName = this.aliasName(tree.expr.id); | ||
if (aliasTreeName in this.baseFunctionTable) { | ||
/* Is base function */ | ||
/* Is base function. */ | ||
if (typeof this.baseFunctionTable[aliasTreeName]['mapper'] !== 'undefined') { | ||
/* arguments evaluated */ | ||
argumentsList = tree.args.map((arg: any) => this.Evaluator(arg, local, fname)); | ||
/* Arguments evaluated. */ | ||
const argumentsList = tree.args.map((arg: any) => this.Evaluator(arg, local, fname)); | ||
if (this.baseFunctionTable[aliasTreeName].mapper && argumentsList.length !== 1) { | ||
/* Error if mapper and #arguments!==1 (Invalid call) */ | ||
/* Error if mapper and #arguments!==1 (Invalid call). */ | ||
throw new Error(`Invalid call to ${aliasTreeName}.`); | ||
} | ||
if (argumentsList.length === 1 && 'array' in argumentsList[0] && this.baseFunctionTable[aliasTreeName].mapper) { | ||
/* Test if is mapper */ | ||
/* Test if is mapper. */ | ||
return this.mapTensor(argumentsList[0], this.baseFunctionTable[aliasTreeName].func); | ||
@@ -1021,21 +1021,25 @@ } else { | ||
} else { | ||
/* arguments selectively evaluated */ | ||
argumentsList = tree.args.map((arg: any, i: number) => (this.baseFunctionTable[aliasTreeName].ev[i] ? this.Evaluator(arg, local, fname) : arg)); | ||
return this.baseFunctionTable[aliasTreeName].func(...argumentsList); | ||
/* Arguments selectively evaluated. */ | ||
return this.baseFunctionTable[aliasTreeName].func( | ||
...tree.args.map((arg: any, i: number) => (this.baseFunctionTable[aliasTreeName].ev[i] ? this.Evaluator(arg, local, fname) : arg)), | ||
); | ||
} | ||
} else if (local && this.localTable[fname] && this.localTable[fname][tree.expr.id]) { | ||
/* Defined in localTable **** */ | ||
/* Defined in localTable. **** */ | ||
return this.localTable[fname][tree.expr.id]; | ||
} else if (tree.expr.id in this.nameTable) { | ||
/* Defined in nameTable */ | ||
/* Defined in nameTable. */ | ||
if (this.nameTable[tree.expr.id].args.length === 0) { | ||
/* If is a defined name */ | ||
const temp = this.Evaluator(this.nameTable[tree.expr.id].expr, false, fname); | ||
/* If is a defined name. */ | ||
const temp = this.Evaluator(this.nameTable[tree.expr.id].expr); | ||
if (tree.args.length === 0) { | ||
/* Defined name */ | ||
/* Defined name. */ | ||
return temp; | ||
} else if (this.isTensor(temp)) { | ||
/* Defined matrix indexing */ | ||
argumentsList = tree.args.map((arg: any) => this.Evaluator(arg, local, fname)); | ||
return this.getItems(temp, tree.expr.id, argumentsList); | ||
/* Defined indexed matrix reference. */ | ||
return this.getItems( | ||
temp, | ||
tree.expr.id, | ||
tree.args.map((arg: any) => this.Evaluator(arg, local, fname)), | ||
); | ||
} else { | ||
@@ -1045,14 +1049,14 @@ throw new Error('invalid matrix indexing or function arguments.'); | ||
} else { | ||
/* Else is defined function */ | ||
/* Else is defined function. */ | ||
if (this.nameTable[tree.expr.id].args.length !== tree.args.length) { | ||
throw new Error(`invalid number of arguments in function ${tree.expr.id}.`); | ||
} | ||
/* Create localTable entry */ | ||
/* Create localTable entry. */ | ||
this.localTable[tree.expr.id] = {}; | ||
for (let i = 0; i < tree.args.length; i++) { | ||
/* Evaluate defined function arguments list */ | ||
/* Evaluate defined function arguments list. */ | ||
this.localTable[tree.expr.id][this.nameTable[tree.expr.id].args[i].id] = this.Evaluator(tree.args[i], true, fname); | ||
} | ||
const temp = this.Evaluator(this.nameTable[tree.expr.id].expr, true, tree.expr.id); | ||
/* Delete localTable entry */ | ||
/* Delete localTable entry. */ | ||
delete this.localTable[tree.expr.id]; | ||
@@ -1065,5 +1069,8 @@ return temp; | ||
} else { | ||
/* literal indexing, ex: [1,2;3,4](1,2) */ | ||
argumentsList = tree.args.map((arg: any) => this.Evaluator(arg, local, fname)); | ||
return this.getItems(tree.expr, this.Unparse(tree.expr), argumentsList); | ||
/* literal indexing, ex: [1,2;3,4](1,2). */ | ||
return this.getItems( | ||
tree.expr, | ||
this.Unparse(tree.expr), | ||
tree.args.map((arg: any) => this.Evaluator(arg, local, fname)), | ||
); | ||
} | ||
@@ -1088,3 +1095,3 @@ case 'CmdWList': | ||
this.exitStatus = Evaluator.response.OK; | ||
return this.Evaluator(tree, false, ''); | ||
return this.Evaluator(tree); | ||
} catch (e) { | ||
@@ -1091,0 +1098,0 @@ this.exitStatus = Evaluator.response.EVAL_ERROR; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
442978
6771
180