1 | 'use strict'
|
2 |
|
3 | const getSafeProperty = require('../../utils/customs').getSafeProperty
|
4 |
|
5 | function factory (type, config, load, typed) {
|
6 | const Node = load(require('./Node'))
|
7 | const access = load(require('./utils/access'))
|
8 |
|
9 | |
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | function AccessorNode (object, index) {
|
19 | if (!(this instanceof AccessorNode)) {
|
20 | throw new SyntaxError('Constructor must be called with the new operator')
|
21 | }
|
22 |
|
23 | if (!type.isNode(object)) {
|
24 | throw new TypeError('Node expected for parameter "object"')
|
25 | }
|
26 | if (!type.isIndexNode(index)) {
|
27 | throw new TypeError('IndexNode expected for parameter "index"')
|
28 | }
|
29 |
|
30 | this.object = object || null
|
31 | this.index = index
|
32 |
|
33 |
|
34 | Object.defineProperty(this, 'name', {
|
35 | get: function () {
|
36 | if (this.index) {
|
37 | return (this.index.isObjectProperty())
|
38 | ? this.index.getObjectProperty()
|
39 | : ''
|
40 | } else {
|
41 | return this.object.name || ''
|
42 | }
|
43 | }.bind(this),
|
44 | set: function () {
|
45 | throw new Error('Cannot assign a new name, name is read-only')
|
46 | }
|
47 | })
|
48 | }
|
49 |
|
50 | AccessorNode.prototype = new Node()
|
51 |
|
52 | AccessorNode.prototype.type = 'AccessorNode'
|
53 |
|
54 | AccessorNode.prototype.isAccessorNode = true
|
55 |
|
56 | |
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | AccessorNode.prototype._compile = function (math, argNames) {
|
70 | const evalObject = this.object._compile(math, argNames)
|
71 | const evalIndex = this.index._compile(math, argNames)
|
72 |
|
73 | if (this.index.isObjectProperty()) {
|
74 | const prop = this.index.getObjectProperty()
|
75 | return function evalAccessorNode (scope, args, context) {
|
76 | return getSafeProperty(evalObject(scope, args, context), prop)
|
77 | }
|
78 | } else {
|
79 | return function evalAccessorNode (scope, args, context) {
|
80 | const object = evalObject(scope, args, context)
|
81 | const index = evalIndex(scope, args, object)
|
82 | return access(object, index)
|
83 | }
|
84 | }
|
85 | }
|
86 |
|
87 | |
88 |
|
89 |
|
90 |
|
91 | AccessorNode.prototype.forEach = function (callback) {
|
92 | callback(this.object, 'object', this)
|
93 | callback(this.index, 'index', this)
|
94 | }
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | AccessorNode.prototype.map = function (callback) {
|
103 | return new AccessorNode(
|
104 | this._ifNode(callback(this.object, 'object', this)),
|
105 | this._ifNode(callback(this.index, 'index', this))
|
106 | )
|
107 | }
|
108 |
|
109 | |
110 |
|
111 |
|
112 |
|
113 | AccessorNode.prototype.clone = function () {
|
114 | return new AccessorNode(this.object, this.index)
|
115 | }
|
116 |
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 | AccessorNode.prototype._toString = function (options) {
|
123 | let object = this.object.toString(options)
|
124 | if (needParenthesis(this.object)) {
|
125 | object = '(' + object + ')'
|
126 | }
|
127 |
|
128 | return object + this.index.toString(options)
|
129 | }
|
130 |
|
131 | |
132 |
|
133 |
|
134 |
|
135 |
|
136 | AccessorNode.prototype.toHTML = function (options) {
|
137 | let object = this.object.toHTML(options)
|
138 | if (needParenthesis(this.object)) {
|
139 | object = '<span class="math-parenthesis math-round-parenthesis">(</span>' + object + '<span class="math-parenthesis math-round-parenthesis">)</span>'
|
140 | }
|
141 |
|
142 | return object + this.index.toHTML(options)
|
143 | }
|
144 |
|
145 | |
146 |
|
147 |
|
148 |
|
149 |
|
150 | AccessorNode.prototype._toTex = function (options) {
|
151 | let object = this.object.toTex(options)
|
152 | if (needParenthesis(this.object)) {
|
153 | object = `\\left(' + object + '\\right)`
|
154 | }
|
155 |
|
156 | return object + this.index.toTex(options)
|
157 | }
|
158 |
|
159 | |
160 |
|
161 |
|
162 |
|
163 | AccessorNode.prototype.toJSON = function () {
|
164 | return {
|
165 | mathjs: 'AccessorNode',
|
166 | object: this.object,
|
167 | index: this.index
|
168 | }
|
169 | }
|
170 |
|
171 | |
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 | AccessorNode.fromJSON = function (json) {
|
179 | return new AccessorNode(json.object, json.index)
|
180 | }
|
181 |
|
182 | |
183 |
|
184 |
|
185 |
|
186 | function needParenthesis (node) {
|
187 |
|
188 | return !(
|
189 | type.isAccessorNode(node) ||
|
190 | type.isArrayNode(node) ||
|
191 | type.isConstantNode(node) ||
|
192 | type.isFunctionNode(node) ||
|
193 | type.isObjectNode(node) ||
|
194 | type.isParenthesisNode(node) ||
|
195 | type.isSymbolNode(node))
|
196 | }
|
197 |
|
198 | return AccessorNode
|
199 | }
|
200 |
|
201 | exports.name = 'AccessorNode'
|
202 | exports.path = 'expression.node'
|
203 | exports.factory = factory
|