* resolve(expr, scope) replaces variable nodes with their scoped values * * Syntax: * * math.resolve(expr, scope) * * Examples: * * math.resolve('x + y', {x:1, y:2}) // Node '1 + 2' * math.resolve(math.parse('x+y'), {x:1, y:2}) // Node '1 + 2' *
(node, scope, within = new Set())
| 47 | * resolution is impossible and a ReferenceError is thrown. |
| 48 | */ |
| 49 | function _resolve (node, scope, within = new Set()) { // note `within`: |
| 50 | // `within` is not documented, since it is for internal cycle |
| 51 | // detection only |
| 52 | if (!scope) { |
| 53 | return node |
| 54 | } |
| 55 | if (isSymbolNode(node)) { |
| 56 | if (within.has(node.name)) { |
| 57 | const variables = Array.from(within).join(', ') |
| 58 | throw new ReferenceError( |
| 59 | `recursive loop of variable definitions among {${variables}}` |
| 60 | ) |
| 61 | } |
| 62 | const value = scope.get(node.name) |
| 63 | if (isNode(value)) { |
| 64 | const 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 | const 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 | const args = node.args.map(function (arg) { |
| 83 | return _resolve(arg, scope, within) |
| 84 | }) |
| 85 | return new FunctionNode(node.name, args) |
| 86 | } |
| 87 | |
| 88 | // Otherwise just recursively resolve any children (might also work |
| 89 | // for some of the above special cases) |
| 90 | return node.map(child => _resolve(child, scope, within)) |
| 91 | } |
| 92 | |
| 93 | return typed('resolve', { |
| 94 | Node: _resolve, |
no test coverage detected
searching dependent graphs…