UNPKG

6.58 kBJavaScriptView Raw
1import { isAccessorNode, isArrayNode, isConstantNode, isFunctionNode, isIndexNode, isNode, isObjectNode, isParenthesisNode, isSymbolNode } from '../../utils/is.js';
2import { getSafeProperty } from '../../utils/customs.js';
3import { factory } from '../../utils/factory.js';
4import { accessFactory } from './utils/access.js';
5var name = 'AccessorNode';
6var dependencies = ['subset', 'Node'];
7export var createAccessorNode = /* #__PURE__ */factory(name, dependencies, (_ref) => {
8 var {
9 subset,
10 Node
11 } = _ref;
12 var access = accessFactory({
13 subset
14 });
15 /**
16 * @constructor AccessorNode
17 * @extends {Node}
18 * Access an object property or get a matrix subset
19 *
20 * @param {Node} object The object from which to retrieve
21 * a property or subset.
22 * @param {IndexNode} index IndexNode containing ranges
23 */
24
25 function AccessorNode(object, index) {
26 if (!(this instanceof AccessorNode)) {
27 throw new SyntaxError('Constructor must be called with the new operator');
28 }
29
30 if (!isNode(object)) {
31 throw new TypeError('Node expected for parameter "object"');
32 }
33
34 if (!isIndexNode(index)) {
35 throw new TypeError('IndexNode expected for parameter "index"');
36 }
37
38 this.object = object || null;
39 this.index = index; // readonly property name
40
41 Object.defineProperty(this, 'name', {
42 get: function () {
43 if (this.index) {
44 return this.index.isObjectProperty() ? this.index.getObjectProperty() : '';
45 } else {
46 return this.object.name || '';
47 }
48 }.bind(this),
49 set: function set() {
50 throw new Error('Cannot assign a new name, name is read-only');
51 }
52 });
53 }
54
55 AccessorNode.prototype = new Node();
56 AccessorNode.prototype.type = 'AccessorNode';
57 AccessorNode.prototype.isAccessorNode = true;
58 /**
59 * Compile a node into a JavaScript function.
60 * This basically pre-calculates as much as possible and only leaves open
61 * calculations which depend on a dynamic scope with variables.
62 * @param {Object} math Math.js namespace with functions and constants.
63 * @param {Object} argNames An object with argument names as key and `true`
64 * as value. Used in the SymbolNode to optimize
65 * for arguments from user assigned functions
66 * (see FunctionAssignmentNode) or special symbols
67 * like `end` (see IndexNode).
68 * @return {function} Returns a function which can be called like:
69 * evalNode(scope: Object, args: Object, context: *)
70 */
71
72 AccessorNode.prototype._compile = function (math, argNames) {
73 var evalObject = this.object._compile(math, argNames);
74
75 var evalIndex = this.index._compile(math, argNames);
76
77 if (this.index.isObjectProperty()) {
78 var prop = this.index.getObjectProperty();
79 return function evalAccessorNode(scope, args, context) {
80 return getSafeProperty(evalObject(scope, args, context), prop);
81 };
82 } else {
83 return function evalAccessorNode(scope, args, context) {
84 var object = evalObject(scope, args, context);
85 var index = evalIndex(scope, args, object); // we pass object here instead of context
86
87 return access(object, index);
88 };
89 }
90 };
91 /**
92 * Execute a callback for each of the child nodes of this node
93 * @param {function(child: Node, path: string, parent: Node)} callback
94 */
95
96
97 AccessorNode.prototype.forEach = function (callback) {
98 callback(this.object, 'object', this);
99 callback(this.index, 'index', this);
100 };
101 /**
102 * Create a new AccessorNode having it's childs be the results of calling
103 * the provided callback function for each of the childs of the original node.
104 * @param {function(child: Node, path: string, parent: Node): Node} callback
105 * @returns {AccessorNode} Returns a transformed copy of the node
106 */
107
108
109 AccessorNode.prototype.map = function (callback) {
110 return new AccessorNode(this._ifNode(callback(this.object, 'object', this)), this._ifNode(callback(this.index, 'index', this)));
111 };
112 /**
113 * Create a clone of this node, a shallow copy
114 * @return {AccessorNode}
115 */
116
117
118 AccessorNode.prototype.clone = function () {
119 return new AccessorNode(this.object, this.index);
120 };
121 /**
122 * Get string representation
123 * @param {Object} options
124 * @return {string}
125 */
126
127
128 AccessorNode.prototype._toString = function (options) {
129 var object = this.object.toString(options);
130
131 if (needParenthesis(this.object)) {
132 object = '(' + object + ')';
133 }
134
135 return object + this.index.toString(options);
136 };
137 /**
138 * Get HTML representation
139 * @param {Object} options
140 * @return {string}
141 */
142
143
144 AccessorNode.prototype.toHTML = function (options) {
145 var object = this.object.toHTML(options);
146
147 if (needParenthesis(this.object)) {
148 object = '<span class="math-parenthesis math-round-parenthesis">(</span>' + object + '<span class="math-parenthesis math-round-parenthesis">)</span>';
149 }
150
151 return object + this.index.toHTML(options);
152 };
153 /**
154 * Get LaTeX representation
155 * @param {Object} options
156 * @return {string}
157 */
158
159
160 AccessorNode.prototype._toTex = function (options) {
161 var object = this.object.toTex(options);
162
163 if (needParenthesis(this.object)) {
164 object = '\\left(\' + object + \'\\right)';
165 }
166
167 return object + this.index.toTex(options);
168 };
169 /**
170 * Get a JSON representation of the node
171 * @returns {Object}
172 */
173
174
175 AccessorNode.prototype.toJSON = function () {
176 return {
177 mathjs: 'AccessorNode',
178 object: this.object,
179 index: this.index
180 };
181 };
182 /**
183 * Instantiate an AccessorNode from its JSON representation
184 * @param {Object} json An object structured like
185 * `{"mathjs": "AccessorNode", object: ..., index: ...}`,
186 * where mathjs is optional
187 * @returns {AccessorNode}
188 */
189
190
191 AccessorNode.fromJSON = function (json) {
192 return new AccessorNode(json.object, json.index);
193 };
194 /**
195 * Are parenthesis needed?
196 * @private
197 */
198
199
200 function needParenthesis(node) {
201 // TODO: maybe make a method on the nodes which tells whether they need parenthesis?
202 return !(isAccessorNode(node) || isArrayNode(node) || isConstantNode(node) || isFunctionNode(node) || isObjectNode(node) || isParenthesisNode(node) || isSymbolNode(node));
203 }
204
205 return AccessorNode;
206}, {
207 isClass: true,
208 isNode: true
209});
\No newline at end of file