@casual-simulation/js-interpreter 3.1.9-alpha.3340590989

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.
package/Interpreter.js ADDED
@@ -0,0 +1,1066 @@
1
+ import { Agent, ManagedRealm, setSurroundingAgent, OrdinaryObjectCreate, CreateDataProperty, Value, Type, inspect, CreateBuiltinFunction, JSStringValue, BigIntValue, NumberValue, SymbolValue, ObjectValue, SameValue, Get, Completion, ThrowCompletion, Construct, NormalCompletion, Set, EnsureCompletion, Call, CreateArrayFromList, DefinePropertyOrThrow, ToPropertyDescriptor, IsCallable, DeletePropertyOrThrow, HasProperty, runJobQueue, IsArray, wellKnownSymbols, EVAL_YIELD, } from '@casual-simulation/engine262';
2
+ import { copyPrototypes, proxyPrototypes } from './Marshalling';
3
+ import { getInterpreterObject, getRegularObject, INTERPRETER_OBJECT, isConstructor, isGenerator, IS_PROXY_OBJECT, markAsProxyObject, markWithInterpretedObject, markWithRegularObject, REGULAR_OBJECT, UNCOPIABLE, unwind, } from './InterpreterUtils';
4
+ const POSSIBLE_BREAKPOINT_LOCATIONS = {
5
+ CallExpression: ['before', 'after'],
6
+ AssignmentExpression: ['before', 'after'],
7
+ LexicalDeclaration: ['after'],
8
+ VariableStatement: ['after'],
9
+ IfStatement: ['before'],
10
+ SwitchStatement: ['before'],
11
+ ReturnStatement: ['before', 'after'],
12
+ AdditiveExpression: ['before', 'after'],
13
+ MultiplicativeExpression: ['before', 'after'],
14
+ BitwiseANDExpression: ['before', 'after'],
15
+ BitwiseORExpression: ['before', 'after'],
16
+ BitwiseXORExpression: ['before', 'after'],
17
+ };
18
+ const NESTED_BREAKPOINTS = {
19
+ IfStatement: [['Statement_b', 'Block']],
20
+ };
21
+ /**
22
+ * Defines a class that wraps common engine262 capabilities.
23
+ */
24
+ export class Interpreter {
25
+ constructor() {
26
+ this._valueSymbolMap = new Map([
27
+ [wellKnownSymbols.asyncIterator, Symbol.asyncIterator],
28
+ [wellKnownSymbols.hasInstance, Symbol.hasInstance],
29
+ [
30
+ wellKnownSymbols.isConcatSpreadable,
31
+ Symbol.isConcatSpreadable,
32
+ ],
33
+ [wellKnownSymbols.iterator, Symbol.iterator],
34
+ [wellKnownSymbols.match, Symbol.match],
35
+ [wellKnownSymbols.matchAll, Symbol.matchAll],
36
+ [wellKnownSymbols.replace, Symbol.replace],
37
+ [wellKnownSymbols.search, Symbol.search],
38
+ [wellKnownSymbols.split, Symbol.split],
39
+ [wellKnownSymbols.toPrimitive, Symbol.toPrimitive],
40
+ [wellKnownSymbols.toStringTag, Symbol.toStringTag],
41
+ [wellKnownSymbols.unscopables, Symbol.unscopables],
42
+ ]);
43
+ this._realSymbolMap = new Map([
44
+ [Symbol.asyncIterator, wellKnownSymbols.asyncIterator],
45
+ [Symbol.hasInstance, wellKnownSymbols.hasInstance],
46
+ [
47
+ Symbol.isConcatSpreadable,
48
+ wellKnownSymbols.isConcatSpreadable,
49
+ ],
50
+ [Symbol.iterator, wellKnownSymbols.iterator],
51
+ [Symbol.match, wellKnownSymbols.match],
52
+ [Symbol.matchAll, wellKnownSymbols.matchAll],
53
+ [Symbol.replace, wellKnownSymbols.replace],
54
+ [Symbol.search, wellKnownSymbols.search],
55
+ [Symbol.split, wellKnownSymbols.split],
56
+ [Symbol.toPrimitive, wellKnownSymbols.toPrimitive],
57
+ [Symbol.toStringTag, wellKnownSymbols.toStringTag],
58
+ [Symbol.unscopables, wellKnownSymbols.unscopables],
59
+ ]);
60
+ this._breakpoints = [];
61
+ this.agent = new Agent({});
62
+ setSurroundingAgent(this.agent);
63
+ this.realm = new ManagedRealm({});
64
+ this.agent.executionContextStack.push(this.realm.topContext);
65
+ this._setupGlobals();
66
+ }
67
+ /**
68
+ * Gets whether this interpreter is currently debugging.
69
+ */
70
+ get debugging() {
71
+ return this._debugging;
72
+ }
73
+ /**
74
+ * Sets whether this interpreter is debugging.
75
+ */
76
+ set debugging(value) {
77
+ this._debugging = value;
78
+ this.agent.hostDefinedOptions.yieldEachNode = value;
79
+ }
80
+ /**
81
+ * Gets the list of breakpoints that have been set on this interpreter.
82
+ */
83
+ get breakpoints() {
84
+ return this._breakpoints;
85
+ }
86
+ /**
87
+ * Creates a new ES6 module using the given code and name.
88
+ * @param moduleCode The code that the module is made up of.
89
+ * @param moduleId The ID of the module.
90
+ * @returns Returns the created module.
91
+ */
92
+ createAndLinkModule(moduleCode, moduleId) {
93
+ const record = this.realm.createSourceTextModule(moduleId, moduleCode);
94
+ if ('Type' in record) {
95
+ throw this.copyFromValue(record.Value);
96
+ }
97
+ this.realm.scope(() => {
98
+ record.Link();
99
+ record.EvaluateAndUnwind();
100
+ });
101
+ return record;
102
+ }
103
+ /**
104
+ * Creates a new function in the global scope using the given function name, function code, and parameters names.
105
+ * @param functionName The name of the function.
106
+ * @param functionCode The code for the body of the function.
107
+ * @param paramNames The names of the parameters.
108
+ */
109
+ createFunction(functionName, functionCode, ...paramNames) {
110
+ const code = `export function ${functionName}(${paramNames.join(',')}) {\n${functionCode}\n}`;
111
+ try {
112
+ const module = this.createAndLinkModule(code, functionName);
113
+ const func = module.Environment.GetBindingValue(new Value(functionName), Value.true);
114
+ let constructedFunction = {
115
+ module,
116
+ func: func,
117
+ name: functionName,
118
+ };
119
+ module[CONSTRUCTED_FUNCTION] = constructedFunction;
120
+ return constructedFunction;
121
+ }
122
+ catch (err) {
123
+ // if (err instanceof SyntaxError) {
124
+ // transformErrorLineNumbers(err, functionName);
125
+ // }
126
+ throw err;
127
+ }
128
+ }
129
+ /**
130
+ * Calls the given function
131
+ * @param func The function that should be called.
132
+ * @param args The arguments that should be provided to the function.
133
+ */
134
+ *callFunction(func, ...args) {
135
+ let a = args.map((a) => {
136
+ const result = this.copyToValue(a);
137
+ if (result.Type !== 'normal') {
138
+ throw this.copyFromValue(result.Value);
139
+ }
140
+ return result.Value;
141
+ });
142
+ const generator = Call(func.func, Value.null, a);
143
+ const result = yield* this._handleBreakpoints(generator);
144
+ const copied = this.copyFromValue(result.Value);
145
+ if (result.Type !== 'normal') {
146
+ throw copied;
147
+ }
148
+ return copied;
149
+ }
150
+ /**
151
+ * Runs the job queue and yields with any interpreter breaks that are encountered along the way.
152
+ */
153
+ *runJobQueue() {
154
+ yield* this._handleBreakpoints(runJobQueue());
155
+ }
156
+ *_handleBreakpoints(generator) {
157
+ while (true) {
158
+ let { done, value } = generator.next();
159
+ if (done) {
160
+ return value;
161
+ }
162
+ else if (this.debugging) {
163
+ if (!(EVAL_YIELD in value)) {
164
+ yield value;
165
+ continue;
166
+ }
167
+ const step = value;
168
+ const possibleLocations = POSSIBLE_BREAKPOINT_LOCATIONS[step.node.type];
169
+ if (!possibleLocations ||
170
+ !possibleLocations.includes(step.evaluationState)) {
171
+ continue;
172
+ }
173
+ const module = this.agent.runningExecutionContext.ScriptOrModule;
174
+ const breakpoint = this._breakpoints.find((b) => {
175
+ if (b.disabled || b.func.module !== module) {
176
+ return false;
177
+ }
178
+ const startLine = step.node.location.start.line;
179
+ const startColumn = step.node.location.start.column;
180
+ return (b.lineNumber === startLine &&
181
+ b.columnNumber === startColumn);
182
+ });
183
+ if (breakpoint &&
184
+ breakpoint.states.includes(step.evaluationState)) {
185
+ if (step.evaluationState === 'before') {
186
+ yield {
187
+ state: step.evaluationState,
188
+ breakpoint,
189
+ node: step.node,
190
+ stack: [...this.agent.executionContextStack],
191
+ };
192
+ }
193
+ else {
194
+ yield {
195
+ state: step.evaluationState,
196
+ result: EnsureCompletion(step.result),
197
+ breakpoint,
198
+ node: step.node,
199
+ stack: [...this.agent.executionContextStack],
200
+ };
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ // private _createTransformObjectFunction(func: ConstructedFunction) {
207
+ // return (obj: any) => {
208
+ // if (obj instanceof Error) {
209
+ // transformErrorLineNumbers(obj, func.name);
210
+ // }
211
+ // };
212
+ // }
213
+ /**
214
+ * Constructs a new interpreted object that proxies all of it's properties back to the given object.
215
+ * @param obj The object that should be proxied.
216
+ */
217
+ proxyObject(obj) {
218
+ if (typeof obj !== 'function') {
219
+ if (typeof obj !== 'object' || obj === null) {
220
+ return this.copyToValue(obj);
221
+ }
222
+ }
223
+ if (INTERPRETER_OBJECT in obj) {
224
+ return NormalCompletion(getInterpreterObject(obj));
225
+ }
226
+ const [proto] = this._getObjectInterpretedProto(obj);
227
+ const constructor = this._getInterpretedProxyConstructor(proto);
228
+ if (constructor) {
229
+ return constructor(obj, proto, this);
230
+ }
231
+ let target;
232
+ const _this = this;
233
+ function copyToValue(value) {
234
+ if (typeof value === 'function' ||
235
+ (value !== null &&
236
+ typeof value === 'object' &&
237
+ (!(value instanceof Error) || INTERPRETER_OBJECT in value))) {
238
+ return _this.proxyObject(value);
239
+ }
240
+ else {
241
+ return _this.copyToValue(value);
242
+ }
243
+ }
244
+ function copyFromValue(value) {
245
+ if (IsCallable(value) === Value.true || Type(value) === 'Object') {
246
+ return _this.reverseProxyObject(value);
247
+ }
248
+ else {
249
+ return _this.copyFromValue(value);
250
+ }
251
+ }
252
+ if (typeof obj === 'object') {
253
+ if (Array.isArray(obj)) {
254
+ target = CreateArrayFromList([]);
255
+ }
256
+ else {
257
+ target = OrdinaryObjectCreate(this.realm.Intrinsics['%Object.prototype%'], []);
258
+ }
259
+ }
260
+ else if (typeof obj === 'function') {
261
+ let func = obj;
262
+ target = CreateBuiltinFunction(function* (args, opts) {
263
+ const thisValue = copyFromValue(opts.thisValue);
264
+ const newTarget = copyFromValue(opts.NewTarget);
265
+ const a = args.map((a) => _this.copyFromValue(a));
266
+ try {
267
+ if (newTarget !== undefined) {
268
+ const result = Reflect.construct(func, a, newTarget);
269
+ return copyToValue(result);
270
+ }
271
+ const result = func.apply(thisValue, a);
272
+ if (isGenerator(result)) {
273
+ return copyToValue(yield* result);
274
+ }
275
+ return copyToValue(result);
276
+ }
277
+ catch (err) {
278
+ const copied = copyToValue(err);
279
+ if (copied.Type !== 'normal') {
280
+ return copied;
281
+ }
282
+ return ThrowCompletion(copied.Value);
283
+ }
284
+ }, func.length, new Value(func.name), [], this.realm, undefined, undefined, isConstructor(func) ? Value.true : Value.false);
285
+ }
286
+ else {
287
+ throw new Error('Cannot proxy primitive values.');
288
+ }
289
+ // const target = ;
290
+ const handler = OrdinaryObjectCreate(this.realm.Intrinsics['%Object.prototype%'], []);
291
+ const getHandler = CreateBuiltinFunction((args) => {
292
+ const [t, prop, reciever] = args;
293
+ if (t === target) {
294
+ const p = this.copyFromValue(prop);
295
+ const result = Reflect.get(obj, p);
296
+ return copyToValue(result);
297
+ }
298
+ else {
299
+ return EnsureCompletion(Value.undefined);
300
+ }
301
+ }, 3, new Value('getHandler'), [], this.realm);
302
+ const setHandler = CreateBuiltinFunction((args) => {
303
+ const [t, prop, value] = args;
304
+ if (t === target) {
305
+ const p = this.copyFromValue(prop);
306
+ const val = this.copyFromValue(value);
307
+ return EnsureCompletion(Reflect.set(obj, p, val) ? Value.true : Value.false);
308
+ }
309
+ else {
310
+ return EnsureCompletion(Value.undefined);
311
+ }
312
+ }, 3, new Value('setHandler'), [], this.realm);
313
+ const deleteHandler = CreateBuiltinFunction((args) => {
314
+ const [t, prop] = args;
315
+ if (t === target) {
316
+ const p = this.copyFromValue(prop);
317
+ return EnsureCompletion(Reflect.deleteProperty(obj, p)
318
+ ? Value.true
319
+ : Value.false);
320
+ }
321
+ else {
322
+ return EnsureCompletion(Value.undefined);
323
+ }
324
+ }, 2, new Value('deleteHandler'), [], this.realm);
325
+ const hasHandler = CreateBuiltinFunction((args) => {
326
+ const [t, key] = args;
327
+ if (t === target) {
328
+ const p = this.copyFromValue(key);
329
+ return EnsureCompletion(Reflect.has(obj, p) ? Value.true : Value.false);
330
+ }
331
+ else {
332
+ return EnsureCompletion(Value.undefined);
333
+ }
334
+ }, 2, new Value('hasHandler'), [], this.realm);
335
+ const definePropertyHandler = CreateBuiltinFunction((args) => {
336
+ const [t, prop, descriptor] = args;
337
+ if (t === target) {
338
+ const p = this.copyFromValue(prop);
339
+ const desc = this.copyFromValue(descriptor);
340
+ const success = Reflect.defineProperty(obj, p, desc);
341
+ if (!success) {
342
+ return NormalCompletion(Value.false);
343
+ }
344
+ return EnsureCompletion(target.DefineOwnProperty(prop, ToPropertyDescriptor(descriptor)));
345
+ }
346
+ else {
347
+ return EnsureCompletion(Value.undefined);
348
+ }
349
+ }, 3, new Value('definePropertyHandler'), [], this.realm);
350
+ const getOwnPropertyDescriptor = CreateBuiltinFunction((args) => {
351
+ const [t, prop] = args;
352
+ if (t === target) {
353
+ const p = this.copyFromValue(prop);
354
+ const desc = Reflect.getOwnPropertyDescriptor(obj, p);
355
+ if (!desc) {
356
+ return NormalCompletion(Value.undefined);
357
+ }
358
+ const d = OrdinaryObjectCreate(this.realm.Intrinsics['%Object.prototype%'], []);
359
+ unwind(Set(d, new Value('configurable'), desc.configurable ? Value.true : Value.false, Value.true));
360
+ unwind(Set(d, new Value('enumerable'), desc.enumerable ? Value.true : Value.false, Value.true));
361
+ if ('value' in desc) {
362
+ const copiedValueResult = copyToValue(desc.value);
363
+ if (copiedValueResult.Type !== 'normal') {
364
+ return copiedValueResult;
365
+ }
366
+ unwind(Set(d, new Value('value'), copiedValueResult.Value, Value.true));
367
+ unwind(Set(d, new Value('writable'), desc.writable ? Value.true : Value.false, Value.true));
368
+ }
369
+ else {
370
+ const copiedGetterResult = copyToValue(desc.get);
371
+ if (copiedGetterResult.Type !== 'normal') {
372
+ return copiedGetterResult;
373
+ }
374
+ const copiedSetterResult = copyToValue(desc.set);
375
+ if (copiedSetterResult.Type !== 'normal') {
376
+ return copiedSetterResult;
377
+ }
378
+ unwind(Set(d, new Value('get'), copiedGetterResult.Value, Value.true));
379
+ unwind(Set(d, new Value('set'), copiedSetterResult.Value, Value.true));
380
+ }
381
+ return NormalCompletion(d);
382
+ }
383
+ else {
384
+ return EnsureCompletion(Value.undefined);
385
+ }
386
+ }, 2, new Value('getOwnPropertyDescriptor'), [], this.realm);
387
+ const ownKeysHandler = CreateBuiltinFunction((args) => {
388
+ const [t] = args;
389
+ if (t === target) {
390
+ const keys = Reflect.ownKeys(obj);
391
+ let results = [];
392
+ for (let key of keys) {
393
+ let result = this.copyToValue(key);
394
+ if (result.Type !== 'normal') {
395
+ return result;
396
+ }
397
+ results.push(result.Value);
398
+ }
399
+ return EnsureCompletion(CreateArrayFromList(results));
400
+ }
401
+ else {
402
+ return EnsureCompletion(Value.undefined);
403
+ }
404
+ }, 1, new Value('ownKeysHandler'), [], this.realm);
405
+ unwind(Set(handler, new Value('get'), getHandler, Value.true));
406
+ unwind(Set(handler, new Value('set'), setHandler, Value.true));
407
+ unwind(Set(handler, new Value('deleteProperty'), deleteHandler, Value.true));
408
+ unwind(Set(handler, new Value('has'), hasHandler, Value.true));
409
+ unwind(Set(handler, new Value('defineProperty'), definePropertyHandler, Value.true));
410
+ unwind(Set(handler, new Value('getOwnPropertyDescriptor'), getOwnPropertyDescriptor, Value.true));
411
+ unwind(Set(handler, new Value('ownKeys'), ownKeysHandler, Value.true));
412
+ const result = markAsProxyObject(markWithRegularObject(unwind(Construct(this.realm.Intrinsics['%Proxy%'], [
413
+ target,
414
+ handler,
415
+ ])), obj));
416
+ markWithInterpretedObject(obj, result);
417
+ return EnsureCompletion(result);
418
+ }
419
+ /**
420
+ * Proxies the given interpreted value as a native JavaScript object.
421
+ * @param obj The interpreted object that should be proxied.
422
+ * @param allowBreakpointsInFunction Whether the object should yield breakpoints when it is called as a function or if it should execute normally. (Default true)
423
+ */
424
+ reverseProxyObject(obj, allowBreakpointsInFunction = true) {
425
+ if (!(obj instanceof ObjectValue)) {
426
+ return this.copyFromValue(obj);
427
+ }
428
+ if (REGULAR_OBJECT in obj) {
429
+ return getRegularObject(obj);
430
+ }
431
+ const [proto] = this._getObjectRealProto(obj);
432
+ const constructor = this._getRealProxyConstructor(proto);
433
+ if (constructor) {
434
+ return constructor(obj, proto, this);
435
+ }
436
+ let target;
437
+ let allowChildFunctionBreakpoints = allowBreakpointsInFunction;
438
+ const _this = this;
439
+ function copyFromValue(value) {
440
+ if (IsCallable(value) === Value.true || Type(value) === 'Object') {
441
+ return _this.reverseProxyObject(value, allowChildFunctionBreakpoints);
442
+ }
443
+ else {
444
+ return _this.copyFromValue(value);
445
+ }
446
+ }
447
+ function copyToValue(value) {
448
+ if (typeof value === 'function' ||
449
+ (value !== null && typeof value === 'object')) {
450
+ return handleCompletion(_this.proxyObject(value));
451
+ }
452
+ else {
453
+ return handleCompletion(_this.copyToValue(value));
454
+ }
455
+ }
456
+ function handleCompletion(completion, func) {
457
+ const c = EnsureCompletion(completion);
458
+ if (c.Type === 'normal') {
459
+ return c.Value;
460
+ }
461
+ else {
462
+ throw _this.copyFromValue(c.Value);
463
+ }
464
+ }
465
+ if (IsCallable(obj) === Value.true) {
466
+ if (allowBreakpointsInFunction) {
467
+ target = function* (...args) {
468
+ // const thisValue = this === target ? target : Value.undefined;
469
+ const a = args.map((a) => handleCompletion(_this.copyToValue(a)));
470
+ const thisProxy = copyToValue(this);
471
+ const result = handleCompletion(yield* _this._handleBreakpoints(Call(obj, thisProxy, a)), obj);
472
+ return copyFromValue(result);
473
+ };
474
+ }
475
+ else {
476
+ target = function (...args) {
477
+ // const thisValue = this === target ? target : Value.undefined;
478
+ const a = args.map((a) => handleCompletion(_this.copyToValue(a)));
479
+ const thisProxy = copyToValue(this);
480
+ const result = handleCompletion(unwind(Call(obj, thisProxy, a)), obj);
481
+ return copyFromValue(result);
482
+ };
483
+ }
484
+ }
485
+ else if (obj instanceof ObjectValue) {
486
+ if (IsArray(obj) === Value.true) {
487
+ target = [];
488
+ allowChildFunctionBreakpoints = false;
489
+ }
490
+ else {
491
+ target = {};
492
+ }
493
+ }
494
+ else {
495
+ throw new Error('Cannot reverse proxy primitive values.');
496
+ }
497
+ let proxy = new Proxy(target, {
498
+ get: (t, prop, reciever) => {
499
+ if (prop === INTERPRETER_OBJECT ||
500
+ prop === IS_PROXY_OBJECT ||
501
+ prop === REGULAR_OBJECT ||
502
+ (typeof target === 'function' && prop in Function.prototype)) {
503
+ return Reflect.get(t, prop, reciever);
504
+ }
505
+ if (t === target) {
506
+ const p = handleCompletion(this.copyToValue(prop));
507
+ const result = handleCompletion(unwind(Get(obj, p)));
508
+ return copyFromValue(result);
509
+ }
510
+ else {
511
+ return undefined;
512
+ }
513
+ },
514
+ set: (t, prop, value) => {
515
+ if (prop === INTERPRETER_OBJECT ||
516
+ prop === IS_PROXY_OBJECT ||
517
+ prop === REGULAR_OBJECT) {
518
+ return Reflect.set(t, prop, value);
519
+ }
520
+ if (t === target) {
521
+ const p = handleCompletion(this.copyToValue(prop));
522
+ const val = handleCompletion(this.copyToValue(value));
523
+ const result = handleCompletion(unwind(Set(obj, p, val, Value.true)));
524
+ return result === Value.true ? true : false;
525
+ }
526
+ else {
527
+ return false;
528
+ }
529
+ },
530
+ deleteProperty: (t, prop) => {
531
+ if (prop === INTERPRETER_OBJECT ||
532
+ prop === IS_PROXY_OBJECT ||
533
+ prop === REGULAR_OBJECT) {
534
+ return Reflect.deleteProperty(t, prop);
535
+ }
536
+ if (t === target) {
537
+ const p = handleCompletion(this.copyToValue(prop));
538
+ const completion = handleCompletion(DeletePropertyOrThrow(obj, p));
539
+ return completion === Value.true ? true : false;
540
+ }
541
+ else {
542
+ return undefined;
543
+ }
544
+ },
545
+ has: (t, prop) => {
546
+ if (prop === INTERPRETER_OBJECT ||
547
+ prop === IS_PROXY_OBJECT ||
548
+ prop === REGULAR_OBJECT) {
549
+ return Reflect.has(t, prop);
550
+ }
551
+ if (t === target) {
552
+ const p = handleCompletion(this.copyToValue(prop));
553
+ const hasProperty = handleCompletion(HasProperty(obj, p));
554
+ return hasProperty === Value.true ? true : false;
555
+ }
556
+ else {
557
+ return undefined;
558
+ }
559
+ },
560
+ defineProperty: (t, prop, descriptor) => {
561
+ if (prop === INTERPRETER_OBJECT ||
562
+ prop === IS_PROXY_OBJECT ||
563
+ prop === REGULAR_OBJECT) {
564
+ return Reflect.defineProperty(t, prop, descriptor);
565
+ }
566
+ if (t === target) {
567
+ const p = handleCompletion(this.copyToValue(prop));
568
+ const desc = ToPropertyDescriptor(handleCompletion(this.copyToValue(descriptor)));
569
+ const success = handleCompletion(DefinePropertyOrThrow(obj, p, desc));
570
+ if (success === Value.false) {
571
+ return false;
572
+ }
573
+ return Reflect.defineProperty(target, prop, descriptor);
574
+ }
575
+ else {
576
+ return undefined;
577
+ }
578
+ },
579
+ getOwnPropertyDescriptor: (t, prop) => {
580
+ if (prop === INTERPRETER_OBJECT ||
581
+ prop === IS_PROXY_OBJECT ||
582
+ prop === REGULAR_OBJECT) {
583
+ return Reflect.getOwnPropertyDescriptor(t, prop);
584
+ }
585
+ if (t === target) {
586
+ const p = handleCompletion(this.copyToValue(prop));
587
+ const desc = handleCompletion(obj.GetOwnProperty(p));
588
+ if (!desc) {
589
+ return undefined;
590
+ }
591
+ let d = {};
592
+ d.configurable =
593
+ desc.Configurable === Value.true ? true : false;
594
+ d.enumerable =
595
+ desc.Enumerable === Value.true ? true : false;
596
+ if (desc.Value !== undefined ||
597
+ desc.Writable !== undefined) {
598
+ d.writable =
599
+ desc.Writable === Value.true ? true : false;
600
+ d.value = copyFromValue(desc.Value);
601
+ }
602
+ else if (desc.Get !== undefined ||
603
+ desc.Set !== undefined) {
604
+ d.get = copyFromValue(desc.Get);
605
+ d.set = copyFromValue(desc.Set);
606
+ }
607
+ return d;
608
+ }
609
+ else {
610
+ return undefined;
611
+ }
612
+ },
613
+ ownKeys: (t) => {
614
+ if (t === target) {
615
+ let ownKeys = handleCompletion(obj.OwnPropertyKeys());
616
+ return [
617
+ ...ownKeys.map((v) => this.copyFromValue(v)),
618
+ INTERPRETER_OBJECT,
619
+ IS_PROXY_OBJECT,
620
+ ];
621
+ }
622
+ else {
623
+ return undefined;
624
+ }
625
+ },
626
+ });
627
+ markWithInterpretedObject(proxy, obj);
628
+ markWithRegularObject(obj, proxy);
629
+ markAsProxyObject(proxy);
630
+ return proxy;
631
+ }
632
+ /**
633
+ * Sets the given breakpoint for execution.
634
+ * @param breakpoint The breakpoint that should be set.
635
+ */
636
+ setBreakpoint(breakpoint) {
637
+ let index = this._breakpoints.findIndex((b) => b.id === breakpoint.id);
638
+ if (index >= 0) {
639
+ this._breakpoints[index] = breakpoint;
640
+ }
641
+ else {
642
+ this._breakpoints.push(breakpoint);
643
+ }
644
+ }
645
+ /**
646
+ * Removes the breakpoint with the given ID.
647
+ * @param id The ID of the breakpoint that should be removed.
648
+ */
649
+ removeBreakpointById(id) {
650
+ let index = this._breakpoints.findIndex((b) => b.id === id);
651
+ if (index >= 0) {
652
+ this._breakpoints.splice(index, 1);
653
+ }
654
+ }
655
+ /**
656
+ * Lists the possible breakpoint locations for the given code.
657
+ * @param code The code.
658
+ */
659
+ listPossibleBreakpoints(code) {
660
+ let locations = [];
661
+ for (let visisted of traverse(code)) {
662
+ const node = visisted.node;
663
+ let possibleStates = POSSIBLE_BREAKPOINT_LOCATIONS[node.type];
664
+ if (possibleStates) {
665
+ locations.push({
666
+ lineNumber: node.location.start.line,
667
+ columnNumber: node.location.start.column,
668
+ possibleStates,
669
+ });
670
+ }
671
+ let nestedStates = NESTED_BREAKPOINTS[node.type];
672
+ if (nestedStates) {
673
+ for (let [prop, type] of nestedStates) {
674
+ if (prop in node) {
675
+ const child = node[prop];
676
+ if (child && child.type === type) {
677
+ locations.push({
678
+ lineNumber: child.location.start.line,
679
+ columnNumber: child.location.start.column,
680
+ possibleStates,
681
+ });
682
+ }
683
+ }
684
+ }
685
+ }
686
+ }
687
+ return locations;
688
+ }
689
+ /**
690
+ * Copies the given value as a new interpreted object.
691
+ * @param value The value that should be copied.
692
+ */
693
+ copyToValue(value) {
694
+ if (value instanceof Value) {
695
+ return NormalCompletion(value);
696
+ }
697
+ else if (value instanceof Completion) {
698
+ return value;
699
+ }
700
+ switch (typeof value) {
701
+ case 'bigint':
702
+ return NormalCompletion(new BigIntValue(value));
703
+ case 'boolean':
704
+ return NormalCompletion(value ? Value.true : Value.false);
705
+ case 'number':
706
+ return NormalCompletion(new NumberValue(value));
707
+ case 'string':
708
+ return NormalCompletion(new JSStringValue(value));
709
+ case 'symbol':
710
+ return NormalCompletion(this._getOrCreateSymbolFromReal(value));
711
+ case 'undefined':
712
+ return NormalCompletion(Value.undefined);
713
+ case 'object':
714
+ case 'function':
715
+ return this._copyToObject(value);
716
+ default:
717
+ throw new Error('Unable to convert value of type: ' + typeof value);
718
+ }
719
+ }
720
+ /**
721
+ * Copies the given value as a new regular JS object.
722
+ * @param value The value that should be copied.
723
+ * @param transformObject An optional function that can be used to transform objects.
724
+ */
725
+ copyFromValue(value, transformObject) {
726
+ if (!(value instanceof Value)) {
727
+ return value;
728
+ }
729
+ switch (Type(value)) {
730
+ case 'BigInt':
731
+ return value.bigintValue();
732
+ case 'Boolean':
733
+ return value.booleanValue();
734
+ case 'String':
735
+ return value.stringValue();
736
+ case 'Null':
737
+ return null;
738
+ case 'Undefined':
739
+ return undefined;
740
+ case 'Number':
741
+ return value.numberValue();
742
+ case 'Symbol':
743
+ return this._getOrCreateSymbolFromValue(value);
744
+ case 'Object':
745
+ return this._copyFromObject(value, transformObject);
746
+ default:
747
+ throw new Error('Unable to convert value of type: ' + Type(value));
748
+ // case ''
749
+ }
750
+ }
751
+ _copyToObject(value) {
752
+ if (value === null) {
753
+ return NormalCompletion(Value.null);
754
+ }
755
+ if (IS_PROXY_OBJECT in value) {
756
+ return NormalCompletion(getInterpreterObject(value));
757
+ }
758
+ if (UNCOPIABLE in value) {
759
+ return this.proxyObject(value);
760
+ }
761
+ try {
762
+ const [proto, constructor] = this._getObjectInterpretedProto(value);
763
+ if (!constructor) {
764
+ throw new Error(`No constructor found for ${proto}`);
765
+ }
766
+ return constructor(value, proto, this);
767
+ }
768
+ catch (err) {
769
+ const result = EnsureCompletion(unwind(Construct(this.realm.Intrinsics['%Error%'], [
770
+ new Value(`Unable to copy value: ${err}`),
771
+ ])));
772
+ if (result.Type === 'normal') {
773
+ result.Value.__original_error = err;
774
+ return ThrowCompletion(result.Value);
775
+ }
776
+ else {
777
+ throw err;
778
+ }
779
+ }
780
+ }
781
+ _copyFromObject(value, transformObject) {
782
+ if (IS_PROXY_OBJECT in value) {
783
+ return getRegularObject(value);
784
+ }
785
+ const [proto, constructor] = this._getObjectRealProto(value);
786
+ if (!constructor) {
787
+ throw new Error(`No constructor found for ${proto}`);
788
+ }
789
+ return constructor(value, proto, this, transformObject);
790
+ }
791
+ _getObjectInterpretedProto(value) {
792
+ let proto = Object.getPrototypeOf(value);
793
+ while ((typeof proto === 'object' || typeof proto === 'function') &&
794
+ proto !== null) {
795
+ for (let [key, prototype, constructor] of copyPrototypes) {
796
+ if (proto === prototype) {
797
+ return [
798
+ this.realm.Intrinsics[key],
799
+ constructor,
800
+ ];
801
+ }
802
+ }
803
+ proto = Object.getPrototypeOf(proto);
804
+ }
805
+ return [];
806
+ }
807
+ _getObjectRealProto(value) {
808
+ let proto = value.GetPrototypeOf();
809
+ while (Type(proto) === 'Object') {
810
+ for (let [key, prototype, _, constructor] of copyPrototypes) {
811
+ if (SameValue(proto, this.realm.Intrinsics[key]) === Value.true) {
812
+ return [prototype, constructor];
813
+ }
814
+ }
815
+ proto = proto.GetPrototypeOf();
816
+ }
817
+ return [];
818
+ }
819
+ _getInterpretedProxyConstructor(prototype) {
820
+ if (!prototype) {
821
+ return null;
822
+ }
823
+ for (let [intrinsic, proto, construct] of proxyPrototypes) {
824
+ if (SameValue(this.realm.Intrinsics[intrinsic], prototype) ===
825
+ Value.true) {
826
+ return construct;
827
+ }
828
+ }
829
+ return null;
830
+ }
831
+ _getRealProxyConstructor(prototype) {
832
+ if (!prototype) {
833
+ return null;
834
+ }
835
+ for (let [intrinsic, proto, _, construct] of proxyPrototypes) {
836
+ if (proto === prototype) {
837
+ return construct;
838
+ }
839
+ }
840
+ return null;
841
+ }
842
+ _getOrCreateSymbolFromReal(value) {
843
+ if (this._realSymbolMap.has(value)) {
844
+ return this._realSymbolMap.get(value);
845
+ }
846
+ else {
847
+ const s = new SymbolValue(value.description);
848
+ this._realSymbolMap.set(value, s);
849
+ this._valueSymbolMap.set(s, value);
850
+ return s;
851
+ }
852
+ }
853
+ _getOrCreateSymbolFromValue(value) {
854
+ if (this._valueSymbolMap.has(value)) {
855
+ return this._valueSymbolMap.get(value);
856
+ }
857
+ else {
858
+ const s = Symbol(value.Description);
859
+ this._valueSymbolMap.set(value, s);
860
+ this._realSymbolMap.set(s, value);
861
+ return s;
862
+ }
863
+ }
864
+ /**
865
+ * Adds the given properties as properties of the global object.
866
+ * @param props The map of property names and values.
867
+ */
868
+ addGlobalProperties(props) {
869
+ this.realm.scope(() => {
870
+ for (let [name, value] of props) {
871
+ const copyResult = this.copyToValue(value);
872
+ if (copyResult.Type !== 'normal') {
873
+ throw this.copyFromValue(copyResult.Value);
874
+ }
875
+ CreateDataProperty(this.realm.GlobalObject, new Value(name), copyResult.Value);
876
+ }
877
+ });
878
+ }
879
+ _setupGlobals() {
880
+ this.realm.scope(() => {
881
+ const con = OrdinaryObjectCreate(this.realm.Intrinsics['%Object.prototype%'], []);
882
+ CreateDataProperty(this.realm.GlobalObject, new Value('console'), con);
883
+ const mapArgs = (args) => args.map((arg, index) => {
884
+ if (index === 0 && Type(arg) === 'String') {
885
+ return arg.stringValue();
886
+ }
887
+ else {
888
+ return inspect(arg);
889
+ }
890
+ });
891
+ const log = CreateBuiltinFunction((args) => {
892
+ console.log(...mapArgs(args));
893
+ }, 1, new Value('log'), [], this.realm);
894
+ const error = CreateBuiltinFunction((args) => {
895
+ console.error(...mapArgs(args));
896
+ }, 1, new Value('error'), [], this.realm);
897
+ const warn = CreateBuiltinFunction((args) => {
898
+ console.warn(...mapArgs(args));
899
+ }, 1, new Value('warn'), [], this.realm);
900
+ CreateDataProperty(con, new Value('log'), log);
901
+ CreateDataProperty(con, new Value('error'), error);
902
+ CreateDataProperty(con, new Value('warn'), warn);
903
+ });
904
+ }
905
+ }
906
+ const CONSTRUCTED_FUNCTION = Symbol('CONSTRUCTED_FUNCTION');
907
+ const VISITOR_KEYS = {
908
+ Script: ['ScriptBody'],
909
+ ScriptBody: ['StatementList'],
910
+ FunctionBody: ['FunctionStatementList'],
911
+ ReturnStatement: ['Expression'],
912
+ IfStatement: ['Expression', 'Statement_a', 'Statement_b'],
913
+ Block: ['StatementList'],
914
+ ExpressionStatement: ['Expression'],
915
+ AdditiveExpression: ['AdditiveExpression', 'MultiplicativeExpression'],
916
+ MultiplicativeExpression: [
917
+ 'ExponentiationExpression',
918
+ 'MultiplicativeExpression',
919
+ ],
920
+ MemberExpression: ['MemberExpression', 'Expression', 'IdentifierName'],
921
+ ObjectLiteral: ['PropertyDefinitionList'],
922
+ PropertyDefinition: ['AssignmentExpression', 'PropertyName'],
923
+ BooleanLiteral: [],
924
+ NumericLiteral: [],
925
+ StringLiteral: [],
926
+ EqualityExpression: ['EqualityExpression', 'RelationalExpression'],
927
+ CallExpression: ['CallExpression', 'Arguments'],
928
+ IdentifierName: [],
929
+ IdentifierReference: [],
930
+ LexicalDeclaration: ['BindingList'],
931
+ LexicalBinding: ['BindingIdentifier', 'BindingPattern', 'Initializer'],
932
+ BindingIdentifier: [],
933
+ SwitchStatement: ['Expression', 'CaseBlock'],
934
+ CaseBlock: ['CaseClauses_a', 'DefaultClause'],
935
+ CaseClause: ['Expression', 'StatementList'],
936
+ BreakStatement: [],
937
+ ForStatement: [
938
+ 'VariableDeclarationList',
939
+ 'Expression_a',
940
+ 'Expression_b',
941
+ 'Statement',
942
+ ],
943
+ ForOfStatement: ['ForDeclaration', 'AssignmentExpression', 'Statement'],
944
+ ForInStatement: ['ForDeclaration', 'Expression', 'Statement'],
945
+ ForDeclaration: ['ForBinding'],
946
+ ForBinding: ['BindingIdentifier', 'Initializer'],
947
+ WhileStatement: ['Expression', 'Statement'],
948
+ DoWhileStatement: ['Expression', 'Statement'],
949
+ TryStatement: ['Block', 'Catch', 'Finally'],
950
+ Catch: ['CatchParameter', 'Block'],
951
+ FunctionDeclaration: [
952
+ 'BindingIdentifier',
953
+ 'FormalParameters',
954
+ 'FunctionBody',
955
+ ],
956
+ SingleNameBinding: ['BindingIdentifier', 'Initializer'],
957
+ ArrowFunction: ['ArrowParameters', 'ConciseBody'],
958
+ ConciseBody: ['ExpressionBody'],
959
+ ObjectBindingPattern: ['BindingPropertyList'],
960
+ ArrayBindingPattern: ['BindingElementList'],
961
+ BindingProperty: ['BindingElement', 'PropertyName'],
962
+ BindingElement: ['BindingPattern', 'Initializer'],
963
+ TemplateLiteral: ['ExpressionList'],
964
+ ConditionalExpression: [
965
+ 'ShortCircuitExpression',
966
+ 'AssignmentExpression_a',
967
+ 'AssignmentExpression_b',
968
+ ],
969
+ CoalesceExpression: ['CoalesceExpressionHead', 'BitwiseORExpression'],
970
+ NullLiteral: [],
971
+ ParenthesizedExpression: ['Expression'],
972
+ AsyncArrowFunction: ['ArrowParameters', 'AsyncConciseBody'],
973
+ AsyncFunctionDeclaration: [
974
+ 'BindingIdentifier',
975
+ 'FormalParameters',
976
+ 'AsyncFunctionBody',
977
+ ],
978
+ AsyncFunctionBody: ['FunctionStatementList'],
979
+ GeneratorDeclaration: [
980
+ 'BindingIdentifier',
981
+ 'FormalParameters',
982
+ 'GeneratorBody',
983
+ ],
984
+ GeneratorBody: ['FunctionStatementList'],
985
+ AsyncGeneratorDeclaration: [
986
+ 'BindingIdentifier',
987
+ 'FormalParameters',
988
+ 'AsyncGeneratorBody',
989
+ ],
990
+ AsyncGeneratorBody: ['FunctionStatementList'],
991
+ ClassDeclaration: ['BindingIdentifier', 'ClassTail'],
992
+ ClassTail: ['ClassHeritage', 'ClassBody'],
993
+ FieldDefinition: ['ClassElementName', 'Initializer'],
994
+ MethodDefinition: [
995
+ 'ClassElementName',
996
+ 'UniqueFormalParameters',
997
+ 'FunctionBody',
998
+ ],
999
+ AsyncMethod: [
1000
+ 'ClassElementName',
1001
+ 'UniqueFormalParameters',
1002
+ 'AsyncFunctionBody',
1003
+ ],
1004
+ GeneratorMethod: [
1005
+ 'ClassElementName',
1006
+ 'UniqueFormalParameters',
1007
+ 'GeneratorBody',
1008
+ ],
1009
+ AsyncGeneratorMethod: [
1010
+ 'ClassElementName',
1011
+ 'UniqueFormalParameters',
1012
+ 'AsyncGeneratorBody',
1013
+ ],
1014
+ AssignmentExpression: ['LeftHandSideExpression', 'AssignmentExpression'],
1015
+ ThisExpression: [],
1016
+ SuperCall: ['Arguments'],
1017
+ SuperProperty: ['IdentifierName', 'Expression'],
1018
+ VariableStatement: ['VariableDeclarationList'],
1019
+ VariableDeclaration: ['BindingIdentifier', 'Initializer'],
1020
+ BitwiseANDExpression: ['A', 'B'],
1021
+ BitwiseORExpression: ['A', 'B'],
1022
+ BitwiseXORExpression: ['A', 'B'],
1023
+ RelationalExpression: ['RelationalExpression', 'ShiftExpression'],
1024
+ };
1025
+ /**
1026
+ * Traverses over the given node.
1027
+ * @param node The node.
1028
+ */
1029
+ export function traverse(node) {
1030
+ return traverseCore(node, 0, null, null);
1031
+ }
1032
+ /**
1033
+ * Traverses over the given node.
1034
+ * @param node The node.
1035
+ */
1036
+ function* traverseCore(node, depth, parent, key) {
1037
+ let visisted = {
1038
+ node,
1039
+ parent,
1040
+ key,
1041
+ depth,
1042
+ };
1043
+ let option = yield visisted;
1044
+ if (option === 'skip') {
1045
+ return;
1046
+ }
1047
+ let keys = VISITOR_KEYS[node.type];
1048
+ if (!keys || keys.length <= 0) {
1049
+ return;
1050
+ }
1051
+ for (let key of keys) {
1052
+ let child = node[key];
1053
+ if (!child) {
1054
+ continue;
1055
+ }
1056
+ if (Array.isArray(child)) {
1057
+ for (let c of child) {
1058
+ yield* traverseCore(c, depth + 1, visisted, key);
1059
+ }
1060
+ }
1061
+ else {
1062
+ yield* traverseCore(child, depth + 1, visisted, key);
1063
+ }
1064
+ }
1065
+ }
1066
+ //# sourceMappingURL=Interpreter.js.map