UNPKG

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