resolve.js 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { createMap } 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 = ['typed', 'parse', 'ConstantNode', 'FunctionNode', 'OperatorNode', 'ParenthesisNode'];
  6. export var createResolve = /* #__PURE__ */factory(name, dependencies, _ref => {
  7. var {
  8. typed,
  9. parse,
  10. ConstantNode,
  11. FunctionNode,
  12. OperatorNode,
  13. ParenthesisNode
  14. } = _ref;
  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: math.parse('x+x')}).toString() // "6"
  27. *
  28. * See also:
  29. *
  30. * simplify, evaluate
  31. *
  32. * @param {Node | Node[]} node
  33. * The expression tree (or trees) to be simplified
  34. * @param {Object} scope
  35. * Scope specifying variables to be resolved
  36. * @return {Node | 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. // note `within`:
  44. // `within` is not documented, since it is for internal cycle
  45. // detection only
  46. if (!scope) {
  47. return node;
  48. }
  49. if (isSymbolNode(node)) {
  50. if (within.has(node.name)) {
  51. var variables = Array.from(within).join(', ');
  52. throw new ReferenceError("recursive loop of variable definitions among {".concat(variables, "}"));
  53. }
  54. var value = scope.get(node.name);
  55. if (isNode(value)) {
  56. var nextWithin = new Set(within);
  57. nextWithin.add(node.name);
  58. return _resolve(value, scope, nextWithin);
  59. } else if (typeof value === 'number') {
  60. return parse(String(value));
  61. } else if (value !== undefined) {
  62. return new ConstantNode(value);
  63. } else {
  64. return node;
  65. }
  66. } else if (isOperatorNode(node)) {
  67. var args = node.args.map(function (arg) {
  68. return _resolve(arg, scope, within);
  69. });
  70. return new OperatorNode(node.op, node.fn, args, node.implicit);
  71. } else if (isParenthesisNode(node)) {
  72. return new ParenthesisNode(_resolve(node.content, scope, within));
  73. } else if (isFunctionNode(node)) {
  74. var _args = node.args.map(function (arg) {
  75. return _resolve(arg, scope, within);
  76. });
  77. return new FunctionNode(node.name, _args);
  78. }
  79. // Otherwise just recursively resolve any children (might also work
  80. // for some of the above special cases)
  81. return node.map(child => _resolve(child, scope, within));
  82. }
  83. return typed('resolve', {
  84. Node: _resolve,
  85. 'Node, Map | null | undefined': _resolve,
  86. 'Node, Object': (n, scope) => _resolve(n, createMap(scope)),
  87. // For arrays and matrices, we map `self` rather than `_resolve`
  88. // because resolve is fairly expensive anyway, and this way
  89. // we get nice error messages if one entry in the array has wrong type.
  90. 'Array | Matrix': typed.referToSelf(self => A => A.map(n => self(n))),
  91. 'Array | Matrix, null | undefined': typed.referToSelf(self => A => A.map(n => self(n))),
  92. 'Array, Object': typed.referTo('Array,Map', selfAM => (A, scope) => selfAM(A, createMap(scope))),
  93. 'Matrix, Object': typed.referTo('Matrix,Map', selfMM => (A, scope) => selfMM(A, createMap(scope))),
  94. 'Array | Matrix, Map': typed.referToSelf(self => (A, scope) => A.map(n => self(n, scope)))
  95. });
  96. });