UNPKG

8.85 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createRangeNode = void 0;
7
8var _is = require("../../utils/is");
9
10var _factory = require("../../utils/factory");
11
12var _operators = require("../operators");
13
14var name = 'RangeNode';
15var dependencies = ['Node'];
16var createRangeNode =
17/* #__PURE__ */
18(0, _factory.factory)(name, dependencies, function (_ref) {
19 var Node = _ref.Node;
20
21 /**
22 * @constructor RangeNode
23 * @extends {Node}
24 * create a range
25 * @param {Node} start included lower-bound
26 * @param {Node} end included upper-bound
27 * @param {Node} [step] optional step
28 */
29 function RangeNode(start, end, step) {
30 if (!(this instanceof RangeNode)) {
31 throw new SyntaxError('Constructor must be called with the new operator');
32 } // validate inputs
33
34
35 if (!(0, _is.isNode)(start)) throw new TypeError('Node expected');
36 if (!(0, _is.isNode)(end)) throw new TypeError('Node expected');
37 if (step && !(0, _is.isNode)(step)) throw new TypeError('Node expected');
38 if (arguments.length > 3) throw new Error('Too many arguments');
39 this.start = start; // included lower-bound
40
41 this.end = end; // included upper-bound
42
43 this.step = step || null; // optional step
44 }
45
46 RangeNode.prototype = new Node();
47 RangeNode.prototype.type = 'RangeNode';
48 RangeNode.prototype.isRangeNode = true;
49 /**
50 * Check whether the RangeNode needs the `end` symbol to be defined.
51 * This end is the size of the Matrix in current dimension.
52 * @return {boolean}
53 */
54
55 RangeNode.prototype.needsEnd = function () {
56 // find all `end` symbols in this RangeNode
57 var endSymbols = this.filter(function (node) {
58 return (0, _is.isSymbolNode)(node) && node.name === 'end';
59 });
60 return endSymbols.length > 0;
61 };
62 /**
63 * Compile a node into a JavaScript function.
64 * This basically pre-calculates as much as possible and only leaves open
65 * calculations which depend on a dynamic scope with variables.
66 * @param {Object} math Math.js namespace with functions and constants.
67 * @param {Object} argNames An object with argument names as key and `true`
68 * as value. Used in the SymbolNode to optimize
69 * for arguments from user assigned functions
70 * (see FunctionAssignmentNode) or special symbols
71 * like `end` (see IndexNode).
72 * @return {function} Returns a function which can be called like:
73 * evalNode(scope: Object, args: Object, context: *)
74 */
75
76
77 RangeNode.prototype._compile = function (math, argNames) {
78 var range = math.range;
79
80 var evalStart = this.start._compile(math, argNames);
81
82 var evalEnd = this.end._compile(math, argNames);
83
84 if (this.step) {
85 var evalStep = this.step._compile(math, argNames);
86
87 return function evalRangeNode(scope, args, context) {
88 return range(evalStart(scope, args, context), evalEnd(scope, args, context), evalStep(scope, args, context));
89 };
90 } else {
91 return function evalRangeNode(scope, args, context) {
92 return range(evalStart(scope, args, context), evalEnd(scope, args, context));
93 };
94 }
95 };
96 /**
97 * Execute a callback for each of the child nodes of this node
98 * @param {function(child: Node, path: string, parent: Node)} callback
99 */
100
101
102 RangeNode.prototype.forEach = function (callback) {
103 callback(this.start, 'start', this);
104 callback(this.end, 'end', this);
105
106 if (this.step) {
107 callback(this.step, 'step', this);
108 }
109 };
110 /**
111 * Create a new RangeNode having it's childs be the results of calling
112 * the provided callback function for each of the childs of the original node.
113 * @param {function(child: Node, path: string, parent: Node): Node} callback
114 * @returns {RangeNode} Returns a transformed copy of the node
115 */
116
117
118 RangeNode.prototype.map = function (callback) {
119 return new RangeNode(this._ifNode(callback(this.start, 'start', this)), this._ifNode(callback(this.end, 'end', this)), this.step && this._ifNode(callback(this.step, 'step', this)));
120 };
121 /**
122 * Create a clone of this node, a shallow copy
123 * @return {RangeNode}
124 */
125
126
127 RangeNode.prototype.clone = function () {
128 return new RangeNode(this.start, this.end, this.step && this.step);
129 };
130 /**
131 * Calculate the necessary parentheses
132 * @param {Node} node
133 * @param {string} parenthesis
134 * @return {Object} parentheses
135 * @private
136 */
137
138
139 function calculateNecessaryParentheses(node, parenthesis) {
140 var precedence = (0, _operators.getPrecedence)(node, parenthesis);
141 var parens = {};
142 var startPrecedence = (0, _operators.getPrecedence)(node.start, parenthesis);
143 parens.start = startPrecedence !== null && startPrecedence <= precedence || parenthesis === 'all';
144
145 if (node.step) {
146 var stepPrecedence = (0, _operators.getPrecedence)(node.step, parenthesis);
147 parens.step = stepPrecedence !== null && stepPrecedence <= precedence || parenthesis === 'all';
148 }
149
150 var endPrecedence = (0, _operators.getPrecedence)(node.end, parenthesis);
151 parens.end = endPrecedence !== null && endPrecedence <= precedence || parenthesis === 'all';
152 return parens;
153 }
154 /**
155 * Get string representation
156 * @param {Object} options
157 * @return {string} str
158 */
159
160
161 RangeNode.prototype._toString = function (options) {
162 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
163 var parens = calculateNecessaryParentheses(this, parenthesis); // format string as start:step:stop
164
165 var str;
166 var start = this.start.toString(options);
167
168 if (parens.start) {
169 start = '(' + start + ')';
170 }
171
172 str = start;
173
174 if (this.step) {
175 var step = this.step.toString(options);
176
177 if (parens.step) {
178 step = '(' + step + ')';
179 }
180
181 str += ':' + step;
182 }
183
184 var end = this.end.toString(options);
185
186 if (parens.end) {
187 end = '(' + end + ')';
188 }
189
190 str += ':' + end;
191 return str;
192 };
193 /**
194 * Get a JSON representation of the node
195 * @returns {Object}
196 */
197
198
199 RangeNode.prototype.toJSON = function () {
200 return {
201 mathjs: 'RangeNode',
202 start: this.start,
203 end: this.end,
204 step: this.step
205 };
206 };
207 /**
208 * Instantiate an RangeNode from its JSON representation
209 * @param {Object} json An object structured like
210 * `{"mathjs": "RangeNode", "start": ..., "end": ..., "step": ...}`,
211 * where mathjs is optional
212 * @returns {RangeNode}
213 */
214
215
216 RangeNode.fromJSON = function (json) {
217 return new RangeNode(json.start, json.end, json.step);
218 };
219 /**
220 * Get HTML representation
221 * @param {Object} options
222 * @return {string} str
223 */
224
225
226 RangeNode.prototype.toHTML = function (options) {
227 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
228 var parens = calculateNecessaryParentheses(this, parenthesis); // format string as start:step:stop
229
230 var str;
231 var start = this.start.toHTML(options);
232
233 if (parens.start) {
234 start = '<span class="math-parenthesis math-round-parenthesis">(</span>' + start + '<span class="math-parenthesis math-round-parenthesis">)</span>';
235 }
236
237 str = start;
238
239 if (this.step) {
240 var step = this.step.toHTML(options);
241
242 if (parens.step) {
243 step = '<span class="math-parenthesis math-round-parenthesis">(</span>' + step + '<span class="math-parenthesis math-round-parenthesis">)</span>';
244 }
245
246 str += '<span class="math-operator math-range-operator">:</span>' + step;
247 }
248
249 var end = this.end.toHTML(options);
250
251 if (parens.end) {
252 end = '<span class="math-parenthesis math-round-parenthesis">(</span>' + end + '<span class="math-parenthesis math-round-parenthesis">)</span>';
253 }
254
255 str += '<span class="math-operator math-range-operator">:</span>' + end;
256 return str;
257 };
258 /**
259 * Get LaTeX representation
260 * @params {Object} options
261 * @return {string} str
262 */
263
264
265 RangeNode.prototype._toTex = function (options) {
266 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep';
267 var parens = calculateNecessaryParentheses(this, parenthesis);
268 var str = this.start.toTex(options);
269
270 if (parens.start) {
271 str = "\\left(".concat(str, "\\right)");
272 }
273
274 if (this.step) {
275 var step = this.step.toTex(options);
276
277 if (parens.step) {
278 step = "\\left(".concat(step, "\\right)");
279 }
280
281 str += ':' + step;
282 }
283
284 var end = this.end.toTex(options);
285
286 if (parens.end) {
287 end = "\\left(".concat(end, "\\right)");
288 }
289
290 str += ':' + end;
291 return str;
292 };
293
294 return RangeNode;
295}, {
296 isClass: true,
297 isNode: true
298});
299exports.createRangeNode = createRangeNode;
\No newline at end of file