UNPKG

7.55 kBJavaScriptView Raw
1import { getPrecedence } from '../operators.js';
2import { escape } from '../../utils/string.js';
3import { getSafeProperty } from '../../utils/customs.js';
4import { latexOperators } from '../../utils/latex.js';
5import { factory } from '../../utils/factory.js';
6var name = 'RelationalNode';
7var dependencies = ['Node'];
8export var createRelationalNode = /* #__PURE__ */factory(name, dependencies, (_ref) => {
9 var {
10 Node
11 } = _ref;
12
13 /**
14 * A node representing a chained conditional expression, such as 'x > y > z'
15 *
16 * @param {String[]} conditionals An array of conditional operators used to compare the parameters
17 * @param {Node[]} params The parameters that will be compared
18 *
19 * @constructor RelationalNode
20 * @extends {Node}
21 */
22 function RelationalNode(conditionals, params) {
23 if (!(this instanceof RelationalNode)) {
24 throw new SyntaxError('Constructor must be called with the new operator');
25 }
26
27 if (!Array.isArray(conditionals)) throw new TypeError('Parameter conditionals must be an array');
28 if (!Array.isArray(params)) throw new TypeError('Parameter params must be an array');
29 if (conditionals.length !== params.length - 1) throw new TypeError('Parameter params must contain exactly one more element than parameter conditionals');
30 this.conditionals = conditionals;
31 this.params = params;
32 }
33
34 RelationalNode.prototype = new Node();
35 RelationalNode.prototype.type = 'RelationalNode';
36 RelationalNode.prototype.isRelationalNode = true;
37 /**
38 * Compile a node into a JavaScript function.
39 * This basically pre-calculates as much as possible and only leaves open
40 * calculations which depend on a dynamic scope with variables.
41 * @param {Object} math Math.js namespace with functions and constants.
42 * @param {Object} argNames An object with argument names as key and `true`
43 * as value. Used in the SymbolNode to optimize
44 * for arguments from user assigned functions
45 * (see FunctionAssignmentNode) or special symbols
46 * like `end` (see IndexNode).
47 * @return {function} Returns a function which can be called like:
48 * evalNode(scope: Object, args: Object, context: *)
49 */
50
51 RelationalNode.prototype._compile = function (math, argNames) {
52 var self = this;
53 var compiled = this.params.map(p => p._compile(math, argNames));
54 return function evalRelationalNode(scope, args, context) {
55 var evalLhs;
56 var evalRhs = compiled[0](scope, args, context);
57
58 for (var i = 0; i < self.conditionals.length; i++) {
59 evalLhs = evalRhs;
60 evalRhs = compiled[i + 1](scope, args, context);
61 var condFn = getSafeProperty(math, self.conditionals[i]);
62
63 if (!condFn(evalLhs, evalRhs)) {
64 return false;
65 }
66 }
67
68 return true;
69 };
70 };
71 /**
72 * Execute a callback for each of the child nodes of this node
73 * @param {function(child: Node, path: string, parent: Node)} callback
74 */
75
76
77 RelationalNode.prototype.forEach = function (callback) {
78 this.params.forEach((n, i) => callback(n, 'params[' + i + ']', this), this);
79 };
80 /**
81 * Create a new RelationalNode having its childs be the results of calling
82 * the provided callback function for each of the childs of the original node.
83 * @param {function(child: Node, path: string, parent: Node): Node} callback
84 * @returns {RelationalNode} Returns a transformed copy of the node
85 */
86
87
88 RelationalNode.prototype.map = function (callback) {
89 return new RelationalNode(this.conditionals.slice(), this.params.map((n, i) => this._ifNode(callback(n, 'params[' + i + ']', this)), this));
90 };
91 /**
92 * Create a clone of this node, a shallow copy
93 * @return {RelationalNode}
94 */
95
96
97 RelationalNode.prototype.clone = function () {
98 return new RelationalNode(this.conditionals, this.params);
99 };
100 /**
101 * Get string representation.
102 * @param {Object} options
103 * @return {string} str
104 */
105
106
107 RelationalNode.prototype._toString = function (options) {
108 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
109 var precedence = getPrecedence(this, parenthesis);
110 var paramStrings = this.params.map(function (p, index) {
111 var paramPrecedence = getPrecedence(p, parenthesis);
112 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '(' + p.toString(options) + ')' : p.toString(options);
113 });
114 var operatorMap = {
115 equal: '==',
116 unequal: '!=',
117 smaller: '<',
118 larger: '>',
119 smallerEq: '<=',
120 largerEq: '>='
121 };
122 var ret = paramStrings[0];
123
124 for (var i = 0; i < this.conditionals.length; i++) {
125 ret += ' ' + operatorMap[this.conditionals[i]] + ' ' + paramStrings[i + 1];
126 }
127
128 return ret;
129 };
130 /**
131 * Get a JSON representation of the node
132 * @returns {Object}
133 */
134
135
136 RelationalNode.prototype.toJSON = function () {
137 return {
138 mathjs: 'RelationalNode',
139 conditionals: this.conditionals,
140 params: this.params
141 };
142 };
143 /**
144 * Instantiate a RelationalNode from its JSON representation
145 * @param {Object} json An object structured like
146 * `{"mathjs": "RelationalNode", "condition": ..., "trueExpr": ..., "falseExpr": ...}`,
147 * where mathjs is optional
148 * @returns {RelationalNode}
149 */
150
151
152 RelationalNode.fromJSON = function (json) {
153 return new RelationalNode(json.conditionals, json.params);
154 };
155 /**
156 * Get HTML representation
157 * @param {Object} options
158 * @return {string} str
159 */
160
161
162 RelationalNode.prototype.toHTML = function (options) {
163 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
164 var precedence = getPrecedence(this, parenthesis);
165 var paramStrings = this.params.map(function (p, index) {
166 var paramPrecedence = getPrecedence(p, parenthesis);
167 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '<span class="math-parenthesis math-round-parenthesis">(</span>' + p.toHTML(options) + '<span class="math-parenthesis math-round-parenthesis">)</span>' : p.toHTML(options);
168 });
169 var operatorMap = {
170 equal: '==',
171 unequal: '!=',
172 smaller: '<',
173 larger: '>',
174 smallerEq: '<=',
175 largerEq: '>='
176 };
177 var ret = paramStrings[0];
178
179 for (var i = 0; i < this.conditionals.length; i++) {
180 ret += '<span class="math-operator math-binary-operator math-explicit-binary-operator">' + escape(operatorMap[this.conditionals[i]]) + '</span>' + paramStrings[i + 1];
181 }
182
183 return ret;
184 };
185 /**
186 * Get LaTeX representation
187 * @param {Object} options
188 * @return {string} str
189 */
190
191
192 RelationalNode.prototype._toTex = function (options) {
193 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
194 var precedence = getPrecedence(this, parenthesis);
195 var paramStrings = this.params.map(function (p, index) {
196 var paramPrecedence = getPrecedence(p, parenthesis);
197 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '\\left(' + p.toTex(options) + '\right)' : p.toTex(options);
198 });
199 var ret = paramStrings[0];
200
201 for (var i = 0; i < this.conditionals.length; i++) {
202 ret += latexOperators[this.conditionals[i]] + paramStrings[i + 1];
203 }
204
205 return ret;
206 };
207
208 return RelationalNode;
209}, {
210 isClass: true,
211 isNode: true
212});
\No newline at end of file