UNPKG

10.7 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createIndexNode = void 0;
7
8var _is = require("../../utils/is");
9
10var _index = require("../transform/index.transform");
11
12var _array = require("../../utils/array");
13
14var _string = require("../../utils/string");
15
16var _factory = require("../../utils/factory");
17
18function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
19
20function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
21
22function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
23
24function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
25
26var name = 'IndexNode';
27var dependencies = ['Range', 'Node', 'Index', 'size'];
28var createIndexNode =
29/* #__PURE__ */
30(0, _factory.factory)(name, dependencies, function (_ref) {
31 var Range = _ref.Range,
32 Node = _ref.Node,
33 Index = _ref.Index,
34 size = _ref.size;
35 var index = (0, _index.createIndexTransform)({
36 Index: Index
37 });
38 /**
39 * @constructor IndexNode
40 * @extends Node
41 *
42 * Describes a subset of a matrix or an object property.
43 * Cannot be used on its own, needs to be used within an AccessorNode or
44 * AssignmentNode.
45 *
46 * @param {Node[]} dimensions
47 * @param {boolean} [dotNotation=false] Optional property describing whether
48 * this index was written using dot
49 * notation like `a.b`, or using bracket
50 * notation like `a["b"]` (default).
51 * Used to stringify an IndexNode.
52 */
53
54 function IndexNode(dimensions, dotNotation) {
55 if (!(this instanceof IndexNode)) {
56 throw new SyntaxError('Constructor must be called with the new operator');
57 }
58
59 this.dimensions = dimensions;
60 this.dotNotation = dotNotation || false; // validate input
61
62 if (!Array.isArray(dimensions) || !dimensions.every(_is.isNode)) {
63 throw new TypeError('Array containing Nodes expected for parameter "dimensions"');
64 }
65
66 if (this.dotNotation && !this.isObjectProperty()) {
67 throw new Error('dotNotation only applicable for object properties');
68 } // TODO: deprecated since v3, remove some day
69
70
71 var deprecated = function deprecated() {
72 throw new Error('Property `IndexNode.object` is deprecated, use `IndexNode.fn` instead');
73 };
74
75 Object.defineProperty(this, 'object', {
76 get: deprecated,
77 set: deprecated
78 });
79 }
80
81 IndexNode.prototype = new Node();
82 IndexNode.prototype.type = 'IndexNode';
83 IndexNode.prototype.isIndexNode = true;
84 /**
85 * Compile a node into a JavaScript function.
86 * This basically pre-calculates as much as possible and only leaves open
87 * calculations which depend on a dynamic scope with variables.
88 * @param {Object} math Math.js namespace with functions and constants.
89 * @param {Object} argNames An object with argument names as key and `true`
90 * as value. Used in the SymbolNode to optimize
91 * for arguments from user assigned functions
92 * (see FunctionAssignmentNode) or special symbols
93 * like `end` (see IndexNode).
94 * @return {function} Returns a function which can be called like:
95 * evalNode(scope: Object, args: Object, context: *)
96 */
97
98 IndexNode.prototype._compile = function (math, argNames) {
99 // TODO: implement support for bignumber (currently bignumbers are silently
100 // reduced to numbers when changing the value to zero-based)
101 // TODO: Optimization: when the range values are ConstantNodes,
102 // we can beforehand resolve the zero-based value
103 // optimization for a simple object property
104 var evalDimensions = (0, _array.map)(this.dimensions, function (range, i) {
105 if ((0, _is.isRangeNode)(range)) {
106 if (range.needsEnd()) {
107 // create a range containing end (like '4:end')
108 var childArgNames = Object.create(argNames);
109 childArgNames.end = true;
110
111 var evalStart = range.start._compile(math, childArgNames);
112
113 var evalEnd = range.end._compile(math, childArgNames);
114
115 var evalStep = range.step ? range.step._compile(math, childArgNames) : function () {
116 return 1;
117 };
118 return function evalDimension(scope, args, context) {
119 var s = size(context).valueOf();
120 var childArgs = Object.create(args);
121 childArgs.end = s[i];
122 return createRange(evalStart(scope, childArgs, context), evalEnd(scope, childArgs, context), evalStep(scope, childArgs, context));
123 };
124 } else {
125 // create range
126 var _evalStart = range.start._compile(math, argNames);
127
128 var _evalEnd = range.end._compile(math, argNames);
129
130 var _evalStep = range.step ? range.step._compile(math, argNames) : function () {
131 return 1;
132 };
133
134 return function evalDimension(scope, args, context) {
135 return createRange(_evalStart(scope, args, context), _evalEnd(scope, args, context), _evalStep(scope, args, context));
136 };
137 }
138 } else if ((0, _is.isSymbolNode)(range) && range.name === 'end') {
139 // SymbolNode 'end'
140 var _childArgNames = Object.create(argNames);
141
142 _childArgNames.end = true;
143
144 var evalRange = range._compile(math, _childArgNames);
145
146 return function evalDimension(scope, args, context) {
147 var s = size(context).valueOf();
148 var childArgs = Object.create(args);
149 childArgs.end = s[i];
150 return evalRange(scope, childArgs, context);
151 };
152 } else {
153 // ConstantNode
154 var _evalRange = range._compile(math, argNames);
155
156 return function evalDimension(scope, args, context) {
157 return _evalRange(scope, args, context);
158 };
159 }
160 });
161 return function evalIndexNode(scope, args, context) {
162 var dimensions = (0, _array.map)(evalDimensions, function (evalDimension) {
163 return evalDimension(scope, args, context);
164 });
165 return index.apply(void 0, _toConsumableArray(dimensions));
166 };
167 };
168 /**
169 * Execute a callback for each of the child nodes of this node
170 * @param {function(child: Node, path: string, parent: Node)} callback
171 */
172
173
174 IndexNode.prototype.forEach = function (callback) {
175 for (var i = 0; i < this.dimensions.length; i++) {
176 callback(this.dimensions[i], 'dimensions[' + i + ']', this);
177 }
178 };
179 /**
180 * Create a new IndexNode having it's childs be the results of calling
181 * the provided callback function for each of the childs of the original node.
182 * @param {function(child: Node, path: string, parent: Node): Node} callback
183 * @returns {IndexNode} Returns a transformed copy of the node
184 */
185
186
187 IndexNode.prototype.map = function (callback) {
188 var dimensions = [];
189
190 for (var i = 0; i < this.dimensions.length; i++) {
191 dimensions[i] = this._ifNode(callback(this.dimensions[i], 'dimensions[' + i + ']', this));
192 }
193
194 return new IndexNode(dimensions, this.dotNotation);
195 };
196 /**
197 * Create a clone of this node, a shallow copy
198 * @return {IndexNode}
199 */
200
201
202 IndexNode.prototype.clone = function () {
203 return new IndexNode(this.dimensions.slice(0), this.dotNotation);
204 };
205 /**
206 * Test whether this IndexNode contains a single property name
207 * @return {boolean}
208 */
209
210
211 IndexNode.prototype.isObjectProperty = function () {
212 return this.dimensions.length === 1 && (0, _is.isConstantNode)(this.dimensions[0]) && typeof this.dimensions[0].value === 'string';
213 };
214 /**
215 * Returns the property name if IndexNode contains a property.
216 * If not, returns null.
217 * @return {string | null}
218 */
219
220
221 IndexNode.prototype.getObjectProperty = function () {
222 return this.isObjectProperty() ? this.dimensions[0].value : null;
223 };
224 /**
225 * Get string representation
226 * @param {Object} options
227 * @return {string} str
228 */
229
230
231 IndexNode.prototype._toString = function (options) {
232 // format the parameters like "[1, 0:5]"
233 return this.dotNotation ? '.' + this.getObjectProperty() : '[' + this.dimensions.join(', ') + ']';
234 };
235 /**
236 * Get a JSON representation of the node
237 * @returns {Object}
238 */
239
240
241 IndexNode.prototype.toJSON = function () {
242 return {
243 mathjs: 'IndexNode',
244 dimensions: this.dimensions,
245 dotNotation: this.dotNotation
246 };
247 };
248 /**
249 * Instantiate an IndexNode from its JSON representation
250 * @param {Object} json An object structured like
251 * `{"mathjs": "IndexNode", dimensions: [...], dotNotation: false}`,
252 * where mathjs is optional
253 * @returns {IndexNode}
254 */
255
256
257 IndexNode.fromJSON = function (json) {
258 return new IndexNode(json.dimensions, json.dotNotation);
259 };
260 /**
261 * Get HTML representation
262 * @param {Object} options
263 * @return {string} str
264 */
265
266
267 IndexNode.prototype.toHTML = function (options) {
268 // format the parameters like "[1, 0:5]"
269 var dimensions = [];
270
271 for (var i = 0; i < this.dimensions.length; i++) {
272 dimensions[i] = this.dimensions[i].toHTML();
273 }
274
275 if (this.dotNotation) {
276 return '<span class="math-operator math-accessor-operator">.</span>' + '<span class="math-symbol math-property">' + (0, _string.escape)(this.getObjectProperty()) + '</span>';
277 } else {
278 return '<span class="math-parenthesis math-square-parenthesis">[</span>' + dimensions.join('<span class="math-separator">,</span>') + '<span class="math-parenthesis math-square-parenthesis">]</span>';
279 }
280 };
281 /**
282 * Get LaTeX representation
283 * @param {Object} options
284 * @return {string} str
285 */
286
287
288 IndexNode.prototype._toTex = function (options) {
289 var dimensions = this.dimensions.map(function (range) {
290 return range.toTex(options);
291 });
292 return this.dotNotation ? '.' + this.getObjectProperty() + '' : '_{' + dimensions.join(',') + '}';
293 }; // helper function to create a Range from start, step and end
294
295
296 function createRange(start, end, step) {
297 return new Range((0, _is.isBigNumber)(start) ? start.toNumber() : start, (0, _is.isBigNumber)(end) ? end.toNumber() : end, (0, _is.isBigNumber)(step) ? step.toNumber() : step);
298 }
299
300 return IndexNode;
301}, {
302 isClass: true,
303 isNode: true
304});
305exports.createIndexNode = createIndexNode;
\No newline at end of file