resolve.js (3052B)
1 import { createMap, isMap } from '../../utils/map.js'; 2 import { isFunctionNode, isNode, isOperatorNode, isParenthesisNode, isSymbolNode } from '../../utils/is.js'; 3 import { factory } from '../../utils/factory.js'; 4 var name = 'resolve'; 5 var dependencies = ['parse', 'ConstantNode', 'FunctionNode', 'OperatorNode', 'ParenthesisNode']; 6 export var createResolve = /* #__PURE__ */factory(name, dependencies, _ref => { 7 var { 8 parse, 9 ConstantNode, 10 FunctionNode, 11 OperatorNode, 12 ParenthesisNode 13 } = _ref; 14 15 /** 16 * resolve(expr, scope) replaces variable nodes with their scoped values 17 * 18 * Syntax: 19 * 20 * resolve(expr, scope) 21 * 22 * Examples: 23 * 24 * math.resolve('x + y', {x:1, y:2}) // Node {1 + 2} 25 * math.resolve(math.parse('x+y'), {x:1, y:2}) // Node {1 + 2} 26 * math.simplify('x+y', {x:2, y:'x+x'}).toString() // "6" 27 * 28 * See also: 29 * 30 * simplify, evaluate 31 * 32 * @param {Node} node 33 * The expression tree to be simplified 34 * @param {Object} scope 35 * Scope specifying variables to be resolved 36 * @return {Node} Returns `node` with variables recursively substituted. 37 * @throws {ReferenceError} 38 * If there is a cyclic dependency among the variables in `scope`, 39 * resolution is impossible and a ReferenceError is thrown. 40 */ 41 function resolve(node, scope) { 42 var within = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new Set(); 43 44 // note `within`: 45 // `within` is not documented, since it is for internal cycle 46 // detection only 47 if (!scope) { 48 return node; 49 } 50 51 if (!isMap(scope)) { 52 scope = createMap(scope); 53 } 54 55 if (isSymbolNode(node)) { 56 if (within.has(node.name)) { 57 var variables = Array.from(within).join(', '); 58 throw new ReferenceError("recursive loop of variable definitions among {".concat(variables, "}")); 59 } 60 61 var value = scope.get(node.name); 62 63 if (isNode(value)) { 64 var nextWithin = new Set(within); 65 nextWithin.add(node.name); 66 return resolve(value, scope, nextWithin); 67 } else if (typeof value === 'number') { 68 return parse(String(value)); 69 } else if (value !== undefined) { 70 return new ConstantNode(value); 71 } else { 72 return node; 73 } 74 } else if (isOperatorNode(node)) { 75 var args = node.args.map(function (arg) { 76 return resolve(arg, scope, within); 77 }); 78 return new OperatorNode(node.op, node.fn, args, node.implicit); 79 } else if (isParenthesisNode(node)) { 80 return new ParenthesisNode(resolve(node.content, scope, within)); 81 } else if (isFunctionNode(node)) { 82 var _args = node.args.map(function (arg) { 83 return resolve(arg, scope, within); 84 }); 85 86 return new FunctionNode(node.name, _args); 87 } // Otherwise just recursively resolve any children (might also work 88 // for some of the above special cases) 89 90 91 return node.map(child => resolve(child, scope, within)); 92 } 93 94 return resolve; 95 });