@mpxjs/core 2.9.36 → 2.9.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,449 @@
1
+ class Interpreter {
2
+ constructor (contextScope = []) {
3
+ this.stateStack = []
4
+ this.value = undefined
5
+ contextScope.unshift(this.initGlobalContext())
6
+ this.contextScope = contextScope
7
+
8
+ this.TYPE_ERROR = 'TypeError'
9
+ this.REFERENCE_ERROR = 'ReferenceError'
10
+ }
11
+
12
+ eval (ast) {
13
+ const state = new State(ast, {})
14
+ this.stateStack = [state]
15
+ // eslint-disable-next-line
16
+ while (this.step()) { }
17
+ return this.value
18
+ }
19
+
20
+ step () {
21
+ const state = this.stateStack[this.stateStack.length - 1]
22
+ if (!state) {
23
+ return false
24
+ }
25
+ const node = state.node
26
+ const type = node[0]
27
+ // Program
28
+ if (type === 1 && state.done) {
29
+ return false
30
+ }
31
+
32
+ let nextState
33
+ try {
34
+ nextState = this[type](this.stateStack, state, node)
35
+ } catch (e) {
36
+ throw Error(e)
37
+ }
38
+
39
+ if (nextState) {
40
+ this.stateStack.push(nextState)
41
+ }
42
+ return true
43
+ }
44
+
45
+ getValue (ref) {
46
+ if (ref[0] === Interpreter.SCOPE_REFERENCE) {
47
+ // A null/varname variable lookup
48
+ return this.getValueFromScope(ref[1])
49
+ } else {
50
+ // An obj/prop components tuple(foo.bar)
51
+ return ref[0][ref[1]]
52
+ }
53
+ }
54
+
55
+ setValue (ref, value) {
56
+ if (ref[0] === Interpreter.SCOPE_REFERENCE) {
57
+ return this.setValueToScope(ref[1], value)
58
+ } else {
59
+ ref[0][ref[1]] = value
60
+ return value
61
+ }
62
+ }
63
+
64
+ setValueToScope (name, value) {
65
+ let index = this.contextScope.length
66
+ while (index--) {
67
+ const scope = this.contextScope[index]
68
+ if (name in scope) {
69
+ scope[name] = value
70
+ return undefined
71
+ }
72
+ }
73
+ this.throwException(this.REFERENCE_ERROR, name + ' is not defined')
74
+ }
75
+
76
+ getValueFromScope (name) {
77
+ let index = this.contextScope.length
78
+ while (index--) {
79
+ const scope = this.contextScope[index]
80
+ if (name in scope) {
81
+ return scope[name]
82
+ }
83
+ }
84
+ this.throwException(this.REFERENCE_ERROR, name + ' is not defined')
85
+ }
86
+
87
+ throwException (errorType, message) {
88
+ throw new Error('[JsInterpreter]: ' + errorType + ` ${message}.`)
89
+ }
90
+
91
+ initGlobalContext () {
92
+ const context = {
93
+ // eslint-disable-next-line
94
+ 'undefined': undefined
95
+ }
96
+ return context
97
+ }
98
+ }
99
+
100
+ Interpreter.SCOPE_REFERENCE = { SCOPE_REFERENCE: true }
101
+ Interpreter.STEP_ERROR = { STEP_ERROR: true }
102
+
103
+ class State {
104
+ constructor (node, scope) {
105
+ this.node = node
106
+ this.scope = scope
107
+ }
108
+ }
109
+
110
+ // Program
111
+ Interpreter.prototype[1] = function stepProgram (stack, state, node) {
112
+ const bodyIndex = 1
113
+ const expression = node[bodyIndex].shift()
114
+ if (expression) {
115
+ state.done = false
116
+ return new State(expression)
117
+ }
118
+ state.done = true
119
+ }
120
+
121
+ // Identifier
122
+ Interpreter.prototype[2] = function stepIdentifier (stack, state, node) {
123
+ const identifierIndex = 1
124
+ stack.pop()
125
+ // 引用场景: ++a
126
+ if (state.components) {
127
+ stack[stack.length - 1].value = [Interpreter.SCOPE_REFERENCE, node[identifierIndex]]
128
+ return
129
+ }
130
+ const value = this.getValueFromScope(node[identifierIndex])
131
+ stack[stack.length - 1].value = value
132
+ }
133
+
134
+ // Literal 暂未支持正则字面量,也不需要支持
135
+ Interpreter.prototype[3] = function stepLiteral (stack, state, node) {
136
+ stack.pop()
137
+ stack[stack.length - 1].value = node[1]
138
+ }
139
+
140
+ // ArrayExpression
141
+ Interpreter.prototype[28] = function stepArrayExpression (stack, state, node) {
142
+ const elementsIndex = 1
143
+ const elements = node[elementsIndex]
144
+ let n = state.n_ || 0
145
+ if (!state.array_) {
146
+ state.array_ = []
147
+ } else {
148
+ state.array_[n] = state.value
149
+ n++
150
+ }
151
+ while (n < elements.length) {
152
+ if (elements[n]) {
153
+ state.n_ = n
154
+ return new State(elements[n])
155
+ }
156
+ n++
157
+ }
158
+ stack.pop()
159
+ stack[stack.length - 1].value = state.array_
160
+ }
161
+
162
+ // ObjectExpression
163
+ Interpreter.prototype[29] = function stepObjectExpression (stack, state, node) {
164
+ const propertyIndex = 1
165
+ const kindIndex = 3
166
+ let n = state.n_ || 0
167
+ let property = node[propertyIndex][n]
168
+ if (!state.object_) {
169
+ // first execution
170
+ state.object_ = {}
171
+ state.properties_ = {}
172
+ } else {
173
+ const propName = state.destinationName
174
+ if (!state.properties_[propName]) {
175
+ state.properties_[propName] = {}
176
+ }
177
+ state.properties_[propName][property[kindIndex]] = state.value
178
+ state.n_ = ++n
179
+ property = node[propertyIndex][n]
180
+ }
181
+
182
+ if (property) {
183
+ const keyIndex = 1
184
+ const valueIndex = 2
185
+ const key = property[keyIndex]
186
+ const identifierOrLiteralValueIndex = 1
187
+ let propName
188
+ if (key[0] === 2 || key[0] === 3) {
189
+ propName = key[identifierOrLiteralValueIndex]
190
+ } else {
191
+ throw SyntaxError('Unknown object structure: ' + key[0])
192
+ }
193
+ state.destinationName = propName
194
+ return new State(property[valueIndex])
195
+ }
196
+
197
+ for (const key in state.properties_) {
198
+ state.object_[key] = state.properties_[key].init
199
+ }
200
+ stack.pop()
201
+ stack[stack.length - 1].value = state.object_
202
+ }
203
+
204
+ // UnaryExpression
205
+ Interpreter.prototype[33] = function stepUnaryExpression (stack, state, node) {
206
+ const operatorIndex = 1
207
+ const argumentIndex = 2
208
+ if (!state.done_) {
209
+ state.done_ = true
210
+ const nextState = new State(node[argumentIndex])
211
+ nextState.components = node[operatorIndex] === 'delete'
212
+ return nextState
213
+ }
214
+ stack.pop()
215
+ let value = state.value
216
+ switch (node[operatorIndex]) {
217
+ case '-':
218
+ value = -value
219
+ break
220
+ case '+':
221
+ value = +value
222
+ break
223
+ case '!':
224
+ value = !value
225
+ break
226
+ case '~':
227
+ value = ~value
228
+ break
229
+ case 'delete': {
230
+ let result = true
231
+ if (Array.isArray(value)) {
232
+ let context = value[0]
233
+ if (context === Interpreter.SCOPE_REFERENCE) {
234
+ context = this.contextScope
235
+ }
236
+ const name = String(value[1])
237
+ try {
238
+ delete context[0][name]
239
+ } catch (e) {
240
+ this.throwException(this.TYPE_ERROR, "Cannot delete property '" + name + "' of '" + context[0] + "'")
241
+ result = false
242
+ }
243
+ }
244
+ value = result
245
+ break
246
+ }
247
+ case 'typeof':
248
+ value = typeof value
249
+ break
250
+ case 'void':
251
+ value = undefined
252
+ break
253
+ default:
254
+ throw SyntaxError('Unknow unary operator:' + node[operatorIndex])
255
+ }
256
+ stack[stack.length - 1].value = value
257
+ }
258
+
259
+ // UpdateExpression
260
+ Interpreter.prototype[34] = function stepUpdateExpression (stack, state, node) {
261
+ const argumentIndex = 2
262
+ if (!state.doneLeft_) {
263
+ state.doneLeft_ = true
264
+ const nextState = new State(node[argumentIndex])
265
+ nextState.components = true
266
+ return nextState
267
+ }
268
+
269
+ if (!state.leftSide_) {
270
+ state.leftSide_ = state.value
271
+ }
272
+ if (!state.doneGetter_) {
273
+ const leftValue = this.getValue(state.leftSide_)
274
+ state.leftValue_ = leftValue
275
+ }
276
+
277
+ const operatorIndex = 1
278
+ const leftValue = Number(state.leftValue_)
279
+ let changeValue
280
+ if (node[operatorIndex] === '++') {
281
+ changeValue = leftValue + 1
282
+ } else if (node[operatorIndex] === '--') {
283
+ changeValue = leftValue - 1
284
+ } else {
285
+ throw SyntaxError('Unknown update expression: ' + node[operatorIndex])
286
+ }
287
+ const prefixIndex = 3
288
+ const returnValue = node[prefixIndex] ? changeValue : leftValue
289
+ this.setValue(state.leftSide_, changeValue)
290
+
291
+ stack.pop()
292
+ stack[stack.length - 1].value = returnValue
293
+ }
294
+
295
+ // BinaryExpression
296
+ Interpreter.prototype[35] = function stepBinaryExpression (stack, state, node) {
297
+ if (!state.doneLeft_) {
298
+ state.doneLeft_ = true
299
+ const leftNodeIndex = 2
300
+ return new State(node[leftNodeIndex])
301
+ }
302
+ if (!state.doneRight_) {
303
+ state.doneRight_ = true
304
+ state.leftValue_ = state.value
305
+ const rightNodeIndex = 3
306
+ return new State(node[rightNodeIndex])
307
+ }
308
+ stack.pop()
309
+ const leftValue = state.leftValue_
310
+ const rightValue = state.value
311
+ const operatorIndex = 1
312
+ let value
313
+ switch (node[operatorIndex]) {
314
+ // eslint-disable-next-line
315
+ case '==': value = leftValue == rightValue; break
316
+ // eslint-disable-next-line
317
+ case '!=': value = leftValue != rightValue; break
318
+ case '===': value = leftValue === rightValue; break
319
+ case '!==': value = leftValue !== rightValue; break
320
+ case '>': value = leftValue > rightValue; break
321
+ case '>=': value = leftValue >= rightValue; break
322
+ case '<': value = leftValue < rightValue; break
323
+ case '<=': value = leftValue <= rightValue; break
324
+ case '+': value = leftValue + rightValue; break
325
+ case '-': value = leftValue - rightValue; break
326
+ case '*': value = leftValue * rightValue; break
327
+ case '/': value = leftValue / rightValue; break
328
+ case '%': value = leftValue % rightValue; break
329
+ case '&': value = leftValue & rightValue; break
330
+ case '|': value = leftValue | rightValue; break
331
+ case '^': value = leftValue ^ rightValue; break
332
+ case '<<': value = leftValue << rightValue; break
333
+ case '>>': value = leftValue >> rightValue; break
334
+ case '>>>': value = leftValue >>> rightValue; break
335
+ case 'in':
336
+ if (!(rightValue instanceof Object)) {
337
+ this.throwException(this.TYPE_ERROR, "'in' expects an object, not '" + rightValue + "'")
338
+ }
339
+ value = leftValue in rightValue
340
+ break
341
+ case 'instanceof':
342
+ if (!(rightValue instanceof Object)) {
343
+ this.throwException(this.TYPE_ERROR, 'Right-hand side of instanceof is not an object')
344
+ }
345
+ value = leftValue instanceof rightValue
346
+ break
347
+ default:
348
+ throw SyntaxError('Unknown binary operator: ' + node[operatorIndex])
349
+ }
350
+ stack[stack.length - 1].value = value
351
+ }
352
+
353
+ // LogicalExpression
354
+ Interpreter.prototype[37] = function stepLogicalExpression (stack, state, node) {
355
+ const operatorIndex = 1
356
+ const leftIndex = 2
357
+ const rightIndex = 3
358
+ if (node[operatorIndex] !== '&&' && node[operatorIndex] !== '||') {
359
+ throw SyntaxError('Unknown logical operator: ' + node[operatorIndex])
360
+ }
361
+ if (!state.doneLeft_) {
362
+ state.doneLeft_ = true
363
+ return new State(node[leftIndex])
364
+ }
365
+
366
+ if (!state.doneRight_) {
367
+ state.doneRight_ = true
368
+ // Shortcut evaluation
369
+ if ((node[operatorIndex] === '&&' && !state.value) || (node[operatorIndex] === '||' && state.value)) {
370
+ stack.pop()
371
+ stack[stack.length - 1].value = state.value
372
+ } else {
373
+ state.doneRight_ = true
374
+ return new State(node[rightIndex])
375
+ }
376
+ } else {
377
+ stack.pop()
378
+ stack[stack.length - 1].value = state.value
379
+ }
380
+ }
381
+
382
+ // MemberExpression
383
+ Interpreter.prototype[38] = function stepMemberExperssion (stack, state, node) {
384
+ const objectIndex = 1
385
+ if (!state.doneObject_) {
386
+ state.doneObject_ = true
387
+ return new State(node[objectIndex])
388
+ }
389
+
390
+ const computedIndex = 3
391
+ const propertyIndex = 2
392
+ const propertyKeyIndex = 1
393
+ let propName
394
+ if (!node[computedIndex]) {
395
+ state.object_ = state.value
396
+ // obj.foo -- Just access `foo` directly.
397
+ propName = node[propertyIndex][propertyKeyIndex]
398
+ } else if (!state.doneProperty_) {
399
+ state.object_ = state.value
400
+ // obj[foo] -- Compute value of `foo`.
401
+ state.doneProperty_ = true
402
+ return new State(node[propertyIndex])
403
+ } else {
404
+ propName = state.value
405
+ }
406
+ // todo 取值的优化,错误提示等
407
+ const value = state.object_[propName]
408
+ stack.pop()
409
+ stack[stack.length - 1].value = value
410
+ }
411
+
412
+ // ConditionalExpression
413
+ Interpreter.prototype[39] = function stepConditionalExpression (stack, state, node) {
414
+ const testIndex = 1
415
+ const mode = state.mode_ || 0
416
+ if (mode === 0) {
417
+ state.mode_ = 1
418
+ return new State(node[testIndex])
419
+ }
420
+ if (mode === 1) {
421
+ state.mode_ = 2
422
+ const value = Boolean(state.value)
423
+ const consequentIndex = 2
424
+ const alternateIndex = 3
425
+ if (value && node[consequentIndex]) {
426
+ return new State(node[consequentIndex])
427
+ } else if (!value && node[alternateIndex]) {
428
+ return new State(node[alternateIndex])
429
+ }
430
+ }
431
+ stack.pop()
432
+ if (node[0] === 39) {
433
+ stack[stack.length - 1].value = state.value
434
+ }
435
+ }
436
+
437
+ // ExpressionStatement
438
+ Interpreter.prototype[40] = function stepExpressionStatement (stack, state, node) {
439
+ const expressionIndex = 1
440
+ if (!state.done_) {
441
+ state.done_ = true
442
+ return new State(node[expressionIndex])
443
+ }
444
+ stack.pop()
445
+ // Save this value to interpreter.value for use as a return value
446
+ this.value = state.value
447
+ }
448
+
449
+ export default Interpreter