@opencode/codemode 0.0.0-beta-19425 → 0.0.0-beta-19500
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/dist/codemode.d.ts +1 -1
- package/dist/codemode.js +1 -1
- package/dist/data.d.ts +4 -6
- package/dist/data.js +44 -18
- package/dist/interpreter/errors.js +3 -4
- package/dist/interpreter/execute.d.ts +2 -1
- package/dist/interpreter/execute.js +2 -2
- package/dist/interpreter/globals.js +4 -0
- package/dist/interpreter/methods.js +64 -55
- package/dist/interpreter/model.d.ts +3 -11
- package/dist/interpreter/model.js +0 -14
- package/dist/interpreter/objects.d.ts +37 -0
- package/dist/interpreter/objects.js +151 -0
- package/dist/interpreter/promises.d.ts +3 -0
- package/dist/interpreter/promises.js +22 -27
- package/dist/interpreter/references.js +9 -11
- package/dist/interpreter/runner.d.ts +4 -3
- package/dist/interpreter/runner.js +9 -6
- package/dist/interpreter/runtime.d.ts +2 -1
- package/dist/interpreter/runtime.js +234 -241
- package/dist/stdlib/array.js +12 -14
- package/dist/stdlib/collections.js +10 -9
- package/dist/stdlib/console.js +16 -14
- package/dist/stdlib/date.js +6 -0
- package/dist/stdlib/json.js +21 -36
- package/dist/stdlib/object.d.ts +2 -0
- package/dist/stdlib/object.js +38 -62
- package/dist/stdlib/regexp.d.ts +2 -1
- package/dist/stdlib/regexp.js +14 -20
- package/dist/stdlib/string.js +5 -0
- package/dist/stdlib/url.js +3 -3
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +25 -26
- package/dist/stdlib/web.d.ts +4 -0
- package/dist/stdlib/web.js +20 -0
- package/dist/tool-runtime.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit } from "effect";
|
|
2
2
|
import { ToolRuntimeError, toProgram } from "../data.js";
|
|
3
3
|
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
-
import { AsyncIteratorSymbol,
|
|
4
|
+
import { AsyncIteratorSymbol, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, IteratorSymbol, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
|
|
5
5
|
import { caughtErrorValue } from "./errors.js";
|
|
6
6
|
import { globals } from "./globals.js";
|
|
7
7
|
import { HostFunction, HostNamespace } from "./host.js";
|
|
8
8
|
import { invokeIntrinsic } from "./methods.js";
|
|
9
|
+
import { assign, get, has, ownKeys, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, record, remove, set, } from "./objects.js";
|
|
9
10
|
import { preserveConsumerError } from "./runner.js";
|
|
10
11
|
import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
11
12
|
import { containsOpaqueReference, describeValue, isRuntimeReference, rejectCircularInsertion, typeofValue, } from "./references.js";
|
|
@@ -16,15 +17,22 @@ import { numberMethods } from "../stdlib/number.js";
|
|
|
16
17
|
import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
|
|
17
18
|
import { stringMethods } from "../stdlib/string.js";
|
|
18
19
|
import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
|
|
20
|
+
import { enumerableSource } from "../stdlib/object.js";
|
|
19
21
|
import { coerceToNumber, coerceToString, compoundOperators, errorBrandName } from "../stdlib/value.js";
|
|
20
22
|
import { Values } from "../values.js";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
// What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
|
|
24
|
+
// Unlabelled break ends this loop; a label the loop does not carry propagates outward.
|
|
25
|
+
const loopExit = (result, labels) => {
|
|
26
|
+
if (result.kind === "return")
|
|
27
|
+
return result;
|
|
28
|
+
if (result.kind === "break") {
|
|
29
|
+
if (result.label !== undefined && !labels?.has(result.label))
|
|
30
|
+
return result;
|
|
31
|
+
return { kind: "none" };
|
|
32
|
+
}
|
|
33
|
+
if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
|
|
34
|
+
return result;
|
|
35
|
+
return undefined;
|
|
28
36
|
};
|
|
29
37
|
const calleeDescription = (callee) => {
|
|
30
38
|
if (callee?.type === "Identifier")
|
|
@@ -42,7 +50,6 @@ const calleeDescription = (callee) => {
|
|
|
42
50
|
}
|
|
43
51
|
return "The called value";
|
|
44
52
|
};
|
|
45
|
-
const hasOwn = (value, key) => value !== null && typeof value === "object" && Object.hasOwn(value, key);
|
|
46
53
|
const constructorName = (value) => {
|
|
47
54
|
if (typeof value === "string")
|
|
48
55
|
return "String";
|
|
@@ -50,7 +57,7 @@ const constructorName = (value) => {
|
|
|
50
57
|
return "Number";
|
|
51
58
|
if (typeof value === "boolean")
|
|
52
59
|
return "Boolean";
|
|
53
|
-
if (
|
|
60
|
+
if (value instanceof ProgramArray)
|
|
54
61
|
return "Array";
|
|
55
62
|
if (value instanceof Values.Date)
|
|
56
63
|
return "Date";
|
|
@@ -66,7 +73,7 @@ const constructorName = (value) => {
|
|
|
66
73
|
return "URLSearchParams";
|
|
67
74
|
if (value instanceof Values.Promise)
|
|
68
75
|
return "Promise";
|
|
69
|
-
if (value
|
|
76
|
+
if (!(value instanceof ProgramObject) || value instanceof ProgramFunction)
|
|
70
77
|
return undefined;
|
|
71
78
|
return errorBrandName(value) ?? "Object";
|
|
72
79
|
};
|
|
@@ -100,6 +107,55 @@ const collectPatternNames = (pattern, out = []) => {
|
|
|
100
107
|
}
|
|
101
108
|
return out;
|
|
102
109
|
};
|
|
110
|
+
// `var` names declared anywhere in a function body except inside nested functions, which own theirs.
|
|
111
|
+
// Memoized per body: a function's var names never change, and hoisting runs on every call.
|
|
112
|
+
const varNames = new WeakMap();
|
|
113
|
+
const collectVarNames = (node, out = []) => {
|
|
114
|
+
if (!node)
|
|
115
|
+
return out;
|
|
116
|
+
switch (node.type) {
|
|
117
|
+
case "VariableDeclaration":
|
|
118
|
+
if (node.kind === "var")
|
|
119
|
+
for (const declaration of node.declarations)
|
|
120
|
+
collectPatternNames(declaration.id, out);
|
|
121
|
+
break;
|
|
122
|
+
case "BlockStatement":
|
|
123
|
+
for (const statement of node.body)
|
|
124
|
+
collectVarNames(statement, out);
|
|
125
|
+
break;
|
|
126
|
+
case "IfStatement":
|
|
127
|
+
collectVarNames(node.consequent, out);
|
|
128
|
+
collectVarNames(node.alternate, out);
|
|
129
|
+
break;
|
|
130
|
+
case "ForStatement":
|
|
131
|
+
if (node.init?.type === "VariableDeclaration")
|
|
132
|
+
collectVarNames(node.init, out);
|
|
133
|
+
collectVarNames(node.body, out);
|
|
134
|
+
break;
|
|
135
|
+
case "ForInStatement":
|
|
136
|
+
case "ForOfStatement":
|
|
137
|
+
if (node.left.type === "VariableDeclaration")
|
|
138
|
+
collectVarNames(node.left, out);
|
|
139
|
+
collectVarNames(node.body, out);
|
|
140
|
+
break;
|
|
141
|
+
case "WhileStatement":
|
|
142
|
+
case "DoWhileStatement":
|
|
143
|
+
case "LabeledStatement":
|
|
144
|
+
collectVarNames(node.body, out);
|
|
145
|
+
break;
|
|
146
|
+
case "SwitchStatement":
|
|
147
|
+
for (const item of node.cases)
|
|
148
|
+
for (const statement of item.consequent)
|
|
149
|
+
collectVarNames(statement, out);
|
|
150
|
+
break;
|
|
151
|
+
case "TryStatement":
|
|
152
|
+
collectVarNames(node.block, out);
|
|
153
|
+
collectVarNames(node.handler?.body, out);
|
|
154
|
+
collectVarNames(node.finalizer, out);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
};
|
|
103
159
|
const loopDeclaration = (left, statement) => {
|
|
104
160
|
if (left.type !== "VariableDeclaration")
|
|
105
161
|
return undefined;
|
|
@@ -118,12 +174,6 @@ const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
|
|
|
118
174
|
value instanceof PromiseInstanceMethodReference ||
|
|
119
175
|
value instanceof IntrinsicReference ||
|
|
120
176
|
value instanceof GeneratorMethodReference;
|
|
121
|
-
const copyIteratorSymbols = (source, target, consumed) => {
|
|
122
|
-
for (const symbol of IteratorSymbols) {
|
|
123
|
-
if (!consumed?.has(symbol) && Object.hasOwn(source, symbol))
|
|
124
|
-
Reflect.set(target, symbol, Reflect.get(source, symbol));
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
177
|
const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
|
|
128
178
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
129
179
|
export class Runtime {
|
|
@@ -136,7 +186,7 @@ export class Runtime {
|
|
|
136
186
|
/** Built-in globals by name, unaffected by program shadowing. */
|
|
137
187
|
builtins;
|
|
138
188
|
root;
|
|
139
|
-
constructor(executeTool, search, toolKeys, promises, logs = []) {
|
|
189
|
+
constructor(executeTool, search, toolKeys, promises, logs = [], extraGlobals = () => []) {
|
|
140
190
|
this.executeTool = executeTool;
|
|
141
191
|
this.search = search;
|
|
142
192
|
this.toolKeys = toolKeys;
|
|
@@ -151,7 +201,7 @@ export class Runtime {
|
|
|
151
201
|
settlePromise: (promise) => this.root.settlePromise(promise),
|
|
152
202
|
syncIterator: (value, node) => this.root.syncIterator(value, node),
|
|
153
203
|
};
|
|
154
|
-
this.builtins = new Map(globals(this));
|
|
204
|
+
this.builtins = new Map([...globals(this), ...extraGlobals(this)]);
|
|
155
205
|
for (const [name, value] of this.builtins)
|
|
156
206
|
globalScope.set(name, { mutable: false, value });
|
|
157
207
|
}
|
|
@@ -176,6 +226,7 @@ class Frame {
|
|
|
176
226
|
return Effect.gen(function* () {
|
|
177
227
|
self.predeclareLexical(program.body);
|
|
178
228
|
self.hoistFunctions(program.body);
|
|
229
|
+
self.hoistVars(program.body);
|
|
179
230
|
let value = undefined;
|
|
180
231
|
for (const [index, statement] of program.body.entries()) {
|
|
181
232
|
if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
|
|
@@ -273,8 +324,15 @@ class Frame {
|
|
|
273
324
|
return { kind: "none" };
|
|
274
325
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
275
326
|
}
|
|
276
|
-
createFunction(node) {
|
|
277
|
-
return new
|
|
327
|
+
createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
|
|
328
|
+
return new ProgramFunction(name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
329
|
+
}
|
|
330
|
+
// NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
|
|
331
|
+
evaluateNamed(node, name) {
|
|
332
|
+
if (node.type === "ArrowFunctionExpression" || (node.type === "FunctionExpression" && !node.id)) {
|
|
333
|
+
return Effect.sync(() => this.createFunction(node, name));
|
|
334
|
+
}
|
|
335
|
+
return this.evaluateExpression(node);
|
|
278
336
|
}
|
|
279
337
|
hoistFunctions(statements) {
|
|
280
338
|
for (const node of statements) {
|
|
@@ -283,6 +341,19 @@ class Frame {
|
|
|
283
341
|
this.scopes.declare(node.id.name, this.createFunction(node), true, node);
|
|
284
342
|
}
|
|
285
343
|
}
|
|
344
|
+
// Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
|
|
345
|
+
// into their own scope above the parameters so closures in parameter defaults keep seeing outer names.
|
|
346
|
+
hoistVars(statements, parameters) {
|
|
347
|
+
const names = varNames.get(statements) ??
|
|
348
|
+
statements.reduce((out, statement) => collectVarNames(statement, out), []);
|
|
349
|
+
varNames.set(statements, names);
|
|
350
|
+
const scope = this.scopes.current();
|
|
351
|
+
for (const name of names) {
|
|
352
|
+
if (scope.has(name))
|
|
353
|
+
continue;
|
|
354
|
+
scope.set(name, { mutable: true, value: parameters?.get(name)?.value, initialized: true });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
286
357
|
predeclareLexical(statements) {
|
|
287
358
|
for (const statement of statements) {
|
|
288
359
|
if (statement.type !== "VariableDeclaration")
|
|
@@ -318,7 +389,9 @@ class Frame {
|
|
|
318
389
|
self.scopes.push();
|
|
319
390
|
return yield* Effect.gen(function* () {
|
|
320
391
|
const cases = node.cases;
|
|
321
|
-
|
|
392
|
+
const statements = cases.flatMap((branch) => branch.consequent);
|
|
393
|
+
self.predeclareLexical(statements);
|
|
394
|
+
self.hoistFunctions(statements);
|
|
322
395
|
let defaultIndex;
|
|
323
396
|
let selected;
|
|
324
397
|
for (const [index, branch] of cases.entries()) {
|
|
@@ -359,20 +432,9 @@ class Frame {
|
|
|
359
432
|
const self = this;
|
|
360
433
|
return Effect.gen(function* () {
|
|
361
434
|
while (yield* self.evaluateExpression(node.test)) {
|
|
362
|
-
const
|
|
363
|
-
if (
|
|
364
|
-
|
|
365
|
-
return result;
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
if (result.kind === "break") {
|
|
369
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
370
|
-
return result;
|
|
371
|
-
return { kind: "none" };
|
|
372
|
-
}
|
|
373
|
-
if (result.kind === "return") {
|
|
374
|
-
return result;
|
|
375
|
-
}
|
|
435
|
+
const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
|
|
436
|
+
if (exit !== undefined)
|
|
437
|
+
return exit;
|
|
376
438
|
}
|
|
377
439
|
return { kind: "none" };
|
|
378
440
|
});
|
|
@@ -381,20 +443,9 @@ class Frame {
|
|
|
381
443
|
const self = this;
|
|
382
444
|
return Effect.gen(function* () {
|
|
383
445
|
do {
|
|
384
|
-
const
|
|
385
|
-
if (
|
|
386
|
-
|
|
387
|
-
return result;
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
if (result.kind === "break") {
|
|
391
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
392
|
-
return result;
|
|
393
|
-
return { kind: "none" };
|
|
394
|
-
}
|
|
395
|
-
if (result.kind === "return") {
|
|
396
|
-
return result;
|
|
397
|
-
}
|
|
446
|
+
const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
|
|
447
|
+
if (exit !== undefined)
|
|
448
|
+
return exit;
|
|
398
449
|
} while (yield* self.evaluateExpression(node.test));
|
|
399
450
|
return { kind: "none" };
|
|
400
451
|
});
|
|
@@ -429,24 +480,13 @@ class Frame {
|
|
|
429
480
|
};
|
|
430
481
|
nextIteration();
|
|
431
482
|
while (testNode ? yield* self.evaluateExpression(testNode) : true) {
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
434
|
-
return
|
|
435
|
-
}
|
|
436
|
-
if (result.kind === "break") {
|
|
437
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
438
|
-
return result;
|
|
439
|
-
return { kind: "none" };
|
|
440
|
-
}
|
|
441
|
-
if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
|
|
442
|
-
return result;
|
|
483
|
+
const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
|
|
484
|
+
if (exit !== undefined)
|
|
485
|
+
return exit;
|
|
443
486
|
nextIteration();
|
|
444
487
|
if (updateNode) {
|
|
445
488
|
yield* self.evaluateExpression(updateNode);
|
|
446
489
|
}
|
|
447
|
-
if (result.kind === "continue") {
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
490
|
}
|
|
451
491
|
return { kind: "none" };
|
|
452
492
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
@@ -477,18 +517,20 @@ class Frame {
|
|
|
477
517
|
}
|
|
478
518
|
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
479
519
|
const evaluateBody = (value) => Effect.gen(function* () {
|
|
480
|
-
if (declared) {
|
|
520
|
+
if (declared?.lexical) {
|
|
481
521
|
self.scopes.push();
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
522
|
+
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
523
|
+
yield* self.declarePattern(declared.pattern, value, declared.mutable, left, true);
|
|
524
|
+
}
|
|
525
|
+
else if (declared) {
|
|
526
|
+
yield* self.assignPattern(declared.pattern, value, left);
|
|
485
527
|
}
|
|
486
528
|
else if (assignment) {
|
|
487
529
|
yield* self.assignPattern(assignment, value, left);
|
|
488
530
|
}
|
|
489
531
|
return yield* self.evaluateStatement(node.body);
|
|
490
532
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
491
|
-
if (declared)
|
|
533
|
+
if (declared?.lexical)
|
|
492
534
|
self.scopes.pop();
|
|
493
535
|
})));
|
|
494
536
|
while (true) {
|
|
@@ -506,20 +548,10 @@ class Frame {
|
|
|
506
548
|
}
|
|
507
549
|
return yield* Effect.failCause(bodyExit.cause);
|
|
508
550
|
}
|
|
509
|
-
const
|
|
510
|
-
if (
|
|
511
|
-
yield* close();
|
|
512
|
-
return result;
|
|
513
|
-
}
|
|
514
|
-
if (result.kind === "break") {
|
|
515
|
-
yield* close();
|
|
516
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
517
|
-
return result;
|
|
518
|
-
return { kind: "none" };
|
|
519
|
-
}
|
|
520
|
-
if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label)) {
|
|
551
|
+
const exit = loopExit(bodyExit.value, labels);
|
|
552
|
+
if (exit !== undefined) {
|
|
521
553
|
yield* close();
|
|
522
|
-
return
|
|
554
|
+
return exit;
|
|
523
555
|
}
|
|
524
556
|
}
|
|
525
557
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
@@ -543,8 +575,8 @@ class Frame {
|
|
|
543
575
|
});
|
|
544
576
|
}
|
|
545
577
|
syncIterator(value, node) {
|
|
546
|
-
const iterator =
|
|
547
|
-
? value[Symbol.iterator]()
|
|
578
|
+
const iterator = value instanceof ProgramArray
|
|
579
|
+
? value.items[Symbol.iterator]()
|
|
548
580
|
: typeof value === "string"
|
|
549
581
|
? value[Symbol.iterator]()
|
|
550
582
|
: value instanceof Values.Map
|
|
@@ -558,7 +590,10 @@ class Frame {
|
|
|
558
590
|
return Effect.succeed({
|
|
559
591
|
next: Effect.sync(() => {
|
|
560
592
|
const step = iterator.next();
|
|
561
|
-
return {
|
|
593
|
+
return {
|
|
594
|
+
done: Boolean(step.done),
|
|
595
|
+
value: Array.isArray(step.value) ? new ProgramArray(step.value) : step.value,
|
|
596
|
+
};
|
|
562
597
|
}),
|
|
563
598
|
close: Effect.void,
|
|
564
599
|
});
|
|
@@ -581,10 +616,10 @@ class Frame {
|
|
|
581
616
|
asynchronous: value.asynchronous,
|
|
582
617
|
});
|
|
583
618
|
}
|
|
584
|
-
if (!
|
|
619
|
+
if (!(value instanceof ProgramObject))
|
|
585
620
|
return Effect.undefined;
|
|
586
|
-
const asyncMethod = allowAsync ?
|
|
587
|
-
const method = asyncMethod ??
|
|
621
|
+
const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
|
|
622
|
+
const method = asyncMethod ?? get(value, IteratorSymbol);
|
|
588
623
|
if (method === undefined || method === null)
|
|
589
624
|
return Effect.undefined;
|
|
590
625
|
const self = this;
|
|
@@ -594,7 +629,7 @@ class Frame {
|
|
|
594
629
|
iterator: object,
|
|
595
630
|
next: object instanceof CodeModeGenerator
|
|
596
631
|
? new GeneratorMethodReference(object, "next")
|
|
597
|
-
: self.requireIteratorMethod(object
|
|
632
|
+
: self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
|
|
598
633
|
asynchronous: asyncMethod !== undefined && asyncMethod !== null,
|
|
599
634
|
};
|
|
600
635
|
});
|
|
@@ -604,7 +639,7 @@ class Frame {
|
|
|
604
639
|
return Effect.gen(function* () {
|
|
605
640
|
if (iterator.asynchronous) {
|
|
606
641
|
const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
|
|
607
|
-
return { done: Boolean(object
|
|
642
|
+
return { done: Boolean(get(object, "done")), value: get(object, "value") };
|
|
608
643
|
}
|
|
609
644
|
const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
|
|
610
645
|
if (!Exit.isSuccess(called)) {
|
|
@@ -614,7 +649,7 @@ class Frame {
|
|
|
614
649
|
}
|
|
615
650
|
const captured = yield* Effect.exit(Effect.sync(() => {
|
|
616
651
|
const object = self.requireIteratorObject(called.value, "Iterator next() result", node);
|
|
617
|
-
return { done: Boolean(object
|
|
652
|
+
return { done: Boolean(get(object, "done")), value: get(object, "value") };
|
|
618
653
|
}));
|
|
619
654
|
if (!Exit.isSuccess(captured)) {
|
|
620
655
|
if (awaiting)
|
|
@@ -632,7 +667,7 @@ class Frame {
|
|
|
632
667
|
closeIterator(iterator, node, awaiting = true) {
|
|
633
668
|
const close = iterator.iterator instanceof CodeModeGenerator
|
|
634
669
|
? new GeneratorMethodReference(iterator.iterator, "return")
|
|
635
|
-
: iterator.iterator
|
|
670
|
+
: get(iterator.iterator, "return");
|
|
636
671
|
if (close === undefined || close === null)
|
|
637
672
|
return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
|
|
638
673
|
const self = this;
|
|
@@ -648,7 +683,7 @@ class Frame {
|
|
|
648
683
|
yield* Effect.yieldNow;
|
|
649
684
|
return yield* Effect.failCause(called.cause);
|
|
650
685
|
}
|
|
651
|
-
const captured = yield* Effect.exit(Effect.sync(() => self.requireIteratorObject(called.value, "Iterator return() result", node)
|
|
686
|
+
const captured = yield* Effect.exit(Effect.sync(() => get(self.requireIteratorObject(called.value, "Iterator return() result", node), "value")));
|
|
652
687
|
if (!Exit.isSuccess(captured)) {
|
|
653
688
|
if (awaiting)
|
|
654
689
|
yield* Effect.yieldNow;
|
|
@@ -659,7 +694,7 @@ class Frame {
|
|
|
659
694
|
});
|
|
660
695
|
}
|
|
661
696
|
requireIteratorObject(value, context, node) {
|
|
662
|
-
if (
|
|
697
|
+
if (value instanceof ProgramObject)
|
|
663
698
|
return value;
|
|
664
699
|
throw new InterpreterRuntimeError(`${context} must be an object.`, node).as("TypeError");
|
|
665
700
|
}
|
|
@@ -673,17 +708,13 @@ class Frame {
|
|
|
673
708
|
return value;
|
|
674
709
|
throw new InterpreterRuntimeError(`${context} must be a function.`, node).as("TypeError");
|
|
675
710
|
}
|
|
676
|
-
|
|
677
|
-
|
|
711
|
+
// for...in over null/undefined iterates nothing, like JS.
|
|
712
|
+
enumerableKeys(value, node) {
|
|
713
|
+
if (value instanceof ToolReference)
|
|
678
714
|
return [...this.runtime.toolKeys(value.path)];
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
if (value !== null && typeof value === "object" && !isRuntimeReference(value)) {
|
|
684
|
-
return Object.keys(value);
|
|
685
|
-
}
|
|
686
|
-
return undefined;
|
|
715
|
+
if (value === null || value === undefined)
|
|
716
|
+
return [];
|
|
717
|
+
return ownKeys(enumerableSource("for...in", value, node)).filter((key) => typeof key === "string");
|
|
687
718
|
}
|
|
688
719
|
evaluateForInStatement(node, labels) {
|
|
689
720
|
const left = node.left;
|
|
@@ -695,43 +726,32 @@ class Frame {
|
|
|
695
726
|
if (declared?.lexical)
|
|
696
727
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
697
728
|
const right = yield* self.evaluateExpression(node.right);
|
|
698
|
-
const keys = self.enumerableKeys(right);
|
|
699
|
-
if (keys === undefined) {
|
|
700
|
-
throw new InterpreterRuntimeError("for...in requires a plain object, array, or tools reference. Use for...of for arrays/strings/Maps/Sets, or Object.keys(value) for a key list.", node);
|
|
701
|
-
}
|
|
729
|
+
const keys = self.enumerableKeys(right, node.right);
|
|
702
730
|
if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
|
|
703
731
|
throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
|
|
704
732
|
}
|
|
705
733
|
const assignmentName = left.type === "Identifier" ? left.name : undefined;
|
|
706
734
|
for (const key of keys) {
|
|
707
735
|
const result = yield* Effect.gen(function* () {
|
|
708
|
-
if (declared) {
|
|
736
|
+
if (declared?.lexical) {
|
|
709
737
|
self.scopes.push();
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
738
|
+
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
739
|
+
yield* self.declarePattern(declared.pattern, key, declared.mutable, left, true);
|
|
740
|
+
}
|
|
741
|
+
else if (declared) {
|
|
742
|
+
yield* self.assignPattern(declared.pattern, key, left);
|
|
713
743
|
}
|
|
714
744
|
else if (assignmentName) {
|
|
715
745
|
self.scopes.set(assignmentName, key, left);
|
|
716
746
|
}
|
|
717
747
|
return yield* self.evaluateStatement(node.body);
|
|
718
748
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
719
|
-
if (declared)
|
|
749
|
+
if (declared?.lexical)
|
|
720
750
|
self.scopes.pop();
|
|
721
751
|
})));
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
if (result.kind === "break") {
|
|
726
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
727
|
-
return result;
|
|
728
|
-
return { kind: "none" };
|
|
729
|
-
}
|
|
730
|
-
if (result.kind === "continue") {
|
|
731
|
-
if (result.label !== undefined && !labels?.has(result.label))
|
|
732
|
-
return result;
|
|
733
|
-
continue;
|
|
734
|
-
}
|
|
752
|
+
const exit = loopExit(result, labels);
|
|
753
|
+
if (exit !== undefined)
|
|
754
|
+
return exit;
|
|
735
755
|
}
|
|
736
756
|
return { kind: "none" };
|
|
737
757
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
@@ -812,8 +832,16 @@ class Frame {
|
|
|
812
832
|
throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
|
|
813
833
|
}
|
|
814
834
|
const init = declaration.init;
|
|
815
|
-
|
|
816
|
-
|
|
835
|
+
// `var x` alone is a no-op: the binding was hoisted on function entry.
|
|
836
|
+
const id = declaration.id;
|
|
837
|
+
const evaluate = (init) => id.type === "Identifier" ? self.evaluateNamed(init, id.name) : self.evaluateExpression(init);
|
|
838
|
+
if (kind === "var") {
|
|
839
|
+
if (init)
|
|
840
|
+
yield* self.assignPattern(id, yield* evaluate(init), declaration);
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
const value = init ? yield* evaluate(init) : undefined;
|
|
844
|
+
yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, true);
|
|
817
845
|
}
|
|
818
846
|
});
|
|
819
847
|
}
|
|
@@ -829,23 +857,19 @@ class Frame {
|
|
|
829
857
|
return;
|
|
830
858
|
}
|
|
831
859
|
if (pattern.type === "AssignmentPattern") {
|
|
832
|
-
const resolved = value === undefined ? yield* self.
|
|
860
|
+
const resolved = value === undefined ? yield* self.evaluateDefault(pattern) : value;
|
|
833
861
|
yield* self.declarePattern(pattern.left, resolved, mutable, node, initialize);
|
|
834
862
|
return;
|
|
835
863
|
}
|
|
836
864
|
if (pattern.type === "ObjectPattern") {
|
|
837
|
-
if (value
|
|
865
|
+
if (!(value instanceof ProgramObject)) {
|
|
838
866
|
throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
|
|
839
867
|
}
|
|
840
868
|
const consumed = new Set();
|
|
841
869
|
for (const property of pattern.properties) {
|
|
842
870
|
if (property.type === "RestElement") {
|
|
843
|
-
const rest =
|
|
844
|
-
|
|
845
|
-
if (!consumed.has(key))
|
|
846
|
-
rest[key] = item;
|
|
847
|
-
}
|
|
848
|
-
copyIteratorSymbols(value, rest, consumed);
|
|
871
|
+
const rest = new ProgramObject();
|
|
872
|
+
assign(rest, value, consumed);
|
|
849
873
|
yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
|
|
850
874
|
continue;
|
|
851
875
|
}
|
|
@@ -873,30 +897,25 @@ class Frame {
|
|
|
873
897
|
return;
|
|
874
898
|
}
|
|
875
899
|
if (pattern.type === "AssignmentPattern") {
|
|
876
|
-
const resolved = value === undefined ? yield* self.
|
|
900
|
+
const resolved = value === undefined ? yield* self.evaluateDefault(pattern) : value;
|
|
877
901
|
yield* self.assignPattern(pattern.left, resolved, node);
|
|
878
902
|
return;
|
|
879
903
|
}
|
|
880
904
|
if (pattern.type === "ObjectPattern") {
|
|
881
|
-
if (value
|
|
905
|
+
if (!(value instanceof ProgramObject)) {
|
|
882
906
|
throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
|
|
883
907
|
}
|
|
884
|
-
const source = value;
|
|
885
908
|
const consumed = new Set();
|
|
886
909
|
for (const property of pattern.properties) {
|
|
887
910
|
if (property.type === "RestElement") {
|
|
888
|
-
const rest =
|
|
889
|
-
|
|
890
|
-
if (!consumed.has(key))
|
|
891
|
-
rest[key] = item;
|
|
892
|
-
}
|
|
893
|
-
copyIteratorSymbols(source, rest, consumed);
|
|
911
|
+
const rest = new ProgramObject();
|
|
912
|
+
assign(rest, value, consumed);
|
|
894
913
|
yield* self.assignPattern(property.argument, rest, property);
|
|
895
914
|
continue;
|
|
896
915
|
}
|
|
897
916
|
const key = yield* self.destructuringPropertyKey(property);
|
|
898
917
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
899
|
-
yield* self.assignPattern(property.value, self.destructuringPropertyValue(
|
|
918
|
+
yield* self.assignPattern(property.value, self.destructuringPropertyValue(value, key), property);
|
|
900
919
|
}
|
|
901
920
|
return;
|
|
902
921
|
}
|
|
@@ -906,6 +925,11 @@ class Frame {
|
|
|
906
925
|
throw new InterpreterRuntimeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
|
|
907
926
|
});
|
|
908
927
|
}
|
|
928
|
+
evaluateDefault(pattern) {
|
|
929
|
+
return pattern.left.type === "Identifier"
|
|
930
|
+
? this.evaluateNamed(pattern.right, pattern.left.name)
|
|
931
|
+
: this.evaluateExpression(pattern.right);
|
|
932
|
+
}
|
|
909
933
|
destructureArrayPattern(pattern, value, consume) {
|
|
910
934
|
const self = this;
|
|
911
935
|
return Effect.gen(function* () {
|
|
@@ -918,7 +942,7 @@ class Frame {
|
|
|
918
942
|
if (done) {
|
|
919
943
|
if (element === null)
|
|
920
944
|
continue;
|
|
921
|
-
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ?
|
|
945
|
+
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray() : undefined, element);
|
|
922
946
|
if (element.type === "RestElement")
|
|
923
947
|
return;
|
|
924
948
|
continue;
|
|
@@ -937,7 +961,7 @@ class Frame {
|
|
|
937
961
|
if (!done)
|
|
938
962
|
rest.push(next.value);
|
|
939
963
|
}
|
|
940
|
-
yield* consume(element.argument, rest, element);
|
|
964
|
+
yield* consume(element.argument, new ProgramArray(rest), element);
|
|
941
965
|
return;
|
|
942
966
|
}
|
|
943
967
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
@@ -962,14 +986,10 @@ class Frame {
|
|
|
962
986
|
throw unsupportedSyntax(keyNode.type, keyNode);
|
|
963
987
|
}
|
|
964
988
|
destructuringPropertyValue(source, key) {
|
|
965
|
-
if (!
|
|
966
|
-
return
|
|
967
|
-
if (key
|
|
968
|
-
return source
|
|
969
|
-
if (typeof key === "number")
|
|
970
|
-
return source[key];
|
|
971
|
-
if (Object.hasOwn(source, key))
|
|
972
|
-
return Reflect.get(source, key);
|
|
989
|
+
if (!(source instanceof ProgramArray))
|
|
990
|
+
return get(source, key);
|
|
991
|
+
if (has(source, key))
|
|
992
|
+
return get(source, key);
|
|
973
993
|
if (typeof key === "string" && arrayMethods.has(key))
|
|
974
994
|
return new IntrinsicReference(source, key);
|
|
975
995
|
return undefined;
|
|
@@ -1044,7 +1064,7 @@ class Frame {
|
|
|
1044
1064
|
// unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
|
|
1045
1065
|
// otherwise; say `new` is unsupported for them and point at the plain call.
|
|
1046
1066
|
const name = calleeDescription(node.callee);
|
|
1047
|
-
const message = callee instanceof
|
|
1067
|
+
const message = callee instanceof ProgramFunction
|
|
1048
1068
|
? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
|
|
1049
1069
|
: callee instanceof HostFunction
|
|
1050
1070
|
? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
|
|
@@ -1074,6 +1094,9 @@ class Frame {
|
|
|
1074
1094
|
return lhs === rhs;
|
|
1075
1095
|
if (operator === "!==")
|
|
1076
1096
|
return lhs !== rhs;
|
|
1097
|
+
if (operator === "in" && rhs instanceof ProgramObject && !containsOpaqueReference(lhs)) {
|
|
1098
|
+
return has(rhs, lhs !== null && typeof lhs === "object" ? coerceToString(lhs) : lhs);
|
|
1099
|
+
}
|
|
1077
1100
|
if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
|
|
1078
1101
|
throw new InterpreterRuntimeError("Binary operators require data values.", node, "InvalidDataValue");
|
|
1079
1102
|
}
|
|
@@ -1126,11 +1149,10 @@ class Frame {
|
|
|
1126
1149
|
case ">>>":
|
|
1127
1150
|
return l >>> r;
|
|
1128
1151
|
case "in":
|
|
1129
|
-
if (rhs
|
|
1152
|
+
if (!(rhs instanceof ProgramObject)) {
|
|
1130
1153
|
throw new InterpreterRuntimeError("The 'in' operator requires a data object on the right-hand side.", node);
|
|
1131
1154
|
}
|
|
1132
|
-
|
|
1133
|
-
return Object.hasOwn(rhs, coerceOperand(lhs));
|
|
1155
|
+
return has(rhs, coerceOperand(lhs));
|
|
1134
1156
|
default:
|
|
1135
1157
|
throw new InterpreterRuntimeError(`Unsupported binary operator '${operator}'.`, node);
|
|
1136
1158
|
}
|
|
@@ -1209,7 +1231,7 @@ class Frame {
|
|
|
1209
1231
|
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1210
1232
|
return self.scopes.set(name, next, left);
|
|
1211
1233
|
}
|
|
1212
|
-
const rightValue = yield* self.
|
|
1234
|
+
const rightValue = yield* self.evaluateNamed(node.right, name);
|
|
1213
1235
|
return self.scopes.set(name, rightValue, left);
|
|
1214
1236
|
}
|
|
1215
1237
|
if (left.type === "MemberExpression") {
|
|
@@ -1232,7 +1254,7 @@ class Frame {
|
|
|
1232
1254
|
const current = self.scopes.get(name, left);
|
|
1233
1255
|
if (!shouldAssign(current))
|
|
1234
1256
|
return current;
|
|
1235
|
-
const rightValue = yield* self.
|
|
1257
|
+
const rightValue = yield* self.evaluateNamed(node.right, name);
|
|
1236
1258
|
return self.scopes.set(name, rightValue, left);
|
|
1237
1259
|
});
|
|
1238
1260
|
}
|
|
@@ -1306,7 +1328,7 @@ class Frame {
|
|
|
1306
1328
|
}
|
|
1307
1329
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1308
1330
|
}
|
|
1309
|
-
if (callable instanceof
|
|
1331
|
+
if (callable instanceof ProgramFunction) {
|
|
1310
1332
|
return yield* self.invokeFunction(callable, args);
|
|
1311
1333
|
}
|
|
1312
1334
|
if (callable instanceof GeneratorMethodReference) {
|
|
@@ -1365,12 +1387,14 @@ class Frame {
|
|
|
1365
1387
|
}
|
|
1366
1388
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1367
1389
|
if (parameter.type === "RestElement") {
|
|
1368
|
-
yield* invocation.declarePattern(parameter.argument, args.slice(index), true, parameter, true);
|
|
1390
|
+
yield* invocation.declarePattern(parameter.argument, new ProgramArray(args.slice(index)), true, parameter, true);
|
|
1369
1391
|
break;
|
|
1370
1392
|
}
|
|
1371
1393
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1372
1394
|
}
|
|
1373
1395
|
if (fn.body.type === "BlockStatement") {
|
|
1396
|
+
invocation.scopes.push();
|
|
1397
|
+
invocation.hoistVars(fn.body.body, paramScope);
|
|
1374
1398
|
const result = yield* invocation.evaluateStatement(fn.body);
|
|
1375
1399
|
return result.kind === "return" ? result.value : undefined;
|
|
1376
1400
|
}
|
|
@@ -1380,12 +1404,7 @@ class Frame {
|
|
|
1380
1404
|
return Effect.succeed(this.createGenerator(invocation, run, fn.async));
|
|
1381
1405
|
if (!fn.async)
|
|
1382
1406
|
return run;
|
|
1383
|
-
|
|
1384
|
-
const box = {};
|
|
1385
|
-
return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, box))), (promise) => {
|
|
1386
|
-
box.promise = promise;
|
|
1387
|
-
return promise;
|
|
1388
|
-
});
|
|
1407
|
+
return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, self)));
|
|
1389
1408
|
}
|
|
1390
1409
|
createGenerator(invocation, run, asynchronous) {
|
|
1391
1410
|
const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
|
|
@@ -1410,13 +1429,13 @@ class Frame {
|
|
|
1410
1429
|
if (state.completed) {
|
|
1411
1430
|
if (kind === "throw")
|
|
1412
1431
|
return Effect.fail(new ProgramThrow(value));
|
|
1413
|
-
return Effect.succeed({ value: kind === "return" ? value : undefined, done: true });
|
|
1432
|
+
return Effect.succeed(record({ value: kind === "return" ? value : undefined, done: true }));
|
|
1414
1433
|
}
|
|
1415
1434
|
if (!state.started && kind !== "next") {
|
|
1416
1435
|
state.completed = true;
|
|
1417
1436
|
if (kind === "throw")
|
|
1418
1437
|
return Effect.fail(new ProgramThrow(value));
|
|
1419
|
-
return Effect.succeed({ value, done: true });
|
|
1438
|
+
return Effect.succeed(record({ value, done: true }));
|
|
1420
1439
|
}
|
|
1421
1440
|
state.pending.push(request);
|
|
1422
1441
|
if (state.available) {
|
|
@@ -1436,7 +1455,7 @@ class Frame {
|
|
|
1436
1455
|
const active = state.active;
|
|
1437
1456
|
state.active = undefined;
|
|
1438
1457
|
if (active) {
|
|
1439
|
-
Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed({ value: exit.value, done: true }) : exit);
|
|
1458
|
+
Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(record({ value: exit.value, done: true })) : exit);
|
|
1440
1459
|
}
|
|
1441
1460
|
yield* invocation.completeGeneratorRequests(state, asynchronous);
|
|
1442
1461
|
state.completed = true;
|
|
@@ -1460,10 +1479,10 @@ class Frame {
|
|
|
1460
1479
|
}
|
|
1461
1480
|
if (asynchronous && pending.kind === "return") {
|
|
1462
1481
|
const resolved = yield* Effect.exit(self.awaitValue(pending.value));
|
|
1463
|
-
Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed({ value: resolved.value, done: true }) : resolved);
|
|
1482
|
+
Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(record({ value: resolved.value, done: true })) : resolved);
|
|
1464
1483
|
continue;
|
|
1465
1484
|
}
|
|
1466
|
-
Deferred.doneUnsafe(pending.response, Exit.succeed({ value: pending.kind === "return" ? pending.value : undefined, done: true }));
|
|
1485
|
+
Deferred.doneUnsafe(pending.response, Exit.succeed(record({ value: pending.kind === "return" ? pending.value : undefined, done: true })));
|
|
1467
1486
|
}
|
|
1468
1487
|
});
|
|
1469
1488
|
}
|
|
@@ -1504,7 +1523,7 @@ class Frame {
|
|
|
1504
1523
|
const state = this.generatorState;
|
|
1505
1524
|
if (!state?.active)
|
|
1506
1525
|
throw new InterpreterRuntimeError("Generator has no active request.", node);
|
|
1507
|
-
Deferred.doneUnsafe(state.active.response, Exit.succeed({ value, done: false }));
|
|
1526
|
+
Deferred.doneUnsafe(state.active.response, Exit.succeed(record({ value, done: false })));
|
|
1508
1527
|
state.active = undefined;
|
|
1509
1528
|
return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
|
|
1510
1529
|
state.active = request;
|
|
@@ -1520,7 +1539,7 @@ class Frame {
|
|
|
1520
1539
|
delegateYield(value, node) {
|
|
1521
1540
|
const self = this;
|
|
1522
1541
|
return Effect.gen(function* () {
|
|
1523
|
-
if (
|
|
1542
|
+
if (value instanceof ProgramArray ||
|
|
1524
1543
|
typeof value === "string" ||
|
|
1525
1544
|
value instanceof Values.Map ||
|
|
1526
1545
|
value instanceof Values.Set ||
|
|
@@ -1557,7 +1576,7 @@ class Frame {
|
|
|
1557
1576
|
? iterator.next
|
|
1558
1577
|
: iterator.iterator instanceof CodeModeGenerator
|
|
1559
1578
|
? new GeneratorMethodReference(iterator.iterator, kind)
|
|
1560
|
-
: iterator.iterator
|
|
1579
|
+
: get(iterator.iterator, kind);
|
|
1561
1580
|
if (method === undefined || method === null) {
|
|
1562
1581
|
if (kind === "return")
|
|
1563
1582
|
return yield* Effect.fail(new GeneratorReturn(input));
|
|
@@ -1566,10 +1585,10 @@ class Frame {
|
|
|
1566
1585
|
}
|
|
1567
1586
|
const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
|
|
1568
1587
|
const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
|
|
1569
|
-
const done = Boolean(result
|
|
1588
|
+
const done = Boolean(get(result, "done"));
|
|
1570
1589
|
const resultValue = self.generatorAsync && !iterator.asynchronous
|
|
1571
|
-
? yield* self.awaitAsyncFromSyncValue(iterator, result
|
|
1572
|
-
: result
|
|
1590
|
+
? yield* self.awaitAsyncFromSyncValue(iterator, get(result, "value"), node, kind !== "return" && !done)
|
|
1591
|
+
: get(result, "value");
|
|
1573
1592
|
if (done) {
|
|
1574
1593
|
if (kind === "return")
|
|
1575
1594
|
return yield* Effect.fail(new GeneratorReturn(resultValue));
|
|
@@ -1591,20 +1610,15 @@ class Frame {
|
|
|
1591
1610
|
});
|
|
1592
1611
|
}
|
|
1593
1612
|
evaluateObjectExpression(node) {
|
|
1594
|
-
const objectValue =
|
|
1613
|
+
const objectValue = new ProgramObject();
|
|
1595
1614
|
const self = this;
|
|
1596
1615
|
return Effect.gen(function* () {
|
|
1597
1616
|
for (const property of node.properties) {
|
|
1598
1617
|
if (property.type === "SpreadElement") {
|
|
1599
1618
|
const spread = yield* self.evaluateExpression(property.argument);
|
|
1600
|
-
if (spread === null || spread === undefined
|
|
1619
|
+
if (spread === null || spread === undefined)
|
|
1601
1620
|
continue;
|
|
1602
|
-
|
|
1603
|
-
throw new InterpreterRuntimeError(`Object spread requires a data object, received ${describeValue(spread)}.`, property, "InvalidDataValue");
|
|
1604
|
-
}
|
|
1605
|
-
for (const [key, value] of Object.entries(spread))
|
|
1606
|
-
objectValue[key] = value;
|
|
1607
|
-
copyIteratorSymbols(spread, objectValue);
|
|
1621
|
+
assign(objectValue, enumerableSource("Object spread", spread, property));
|
|
1608
1622
|
continue;
|
|
1609
1623
|
}
|
|
1610
1624
|
if (property.kind !== "init") {
|
|
@@ -1624,7 +1638,12 @@ class Frame {
|
|
|
1624
1638
|
else {
|
|
1625
1639
|
throw new InterpreterRuntimeError("Unsupported object property key shape.", keyNode);
|
|
1626
1640
|
}
|
|
1627
|
-
|
|
1641
|
+
const name = key === IteratorSymbol
|
|
1642
|
+
? "[Symbol.iterator]"
|
|
1643
|
+
: key === AsyncIteratorSymbol
|
|
1644
|
+
? "[Symbol.asyncIterator]"
|
|
1645
|
+
: String(key);
|
|
1646
|
+
set(objectValue, key, yield* self.evaluateNamed(property.value, name));
|
|
1628
1647
|
}
|
|
1629
1648
|
return objectValue;
|
|
1630
1649
|
});
|
|
@@ -1655,7 +1674,7 @@ class Frame {
|
|
|
1655
1674
|
values.push(yield* self.evaluateExpression(element));
|
|
1656
1675
|
}
|
|
1657
1676
|
}
|
|
1658
|
-
return values;
|
|
1677
|
+
return new ProgramArray(values);
|
|
1659
1678
|
});
|
|
1660
1679
|
}
|
|
1661
1680
|
evaluateTemplateLiteral(node) {
|
|
@@ -1718,7 +1737,9 @@ class Frame {
|
|
|
1718
1737
|
return new ComputedValue(objectValue.member(key, propertyNode));
|
|
1719
1738
|
}
|
|
1720
1739
|
// Values have no prototype chain, so `.constructor` resolves to the owning built-in directly.
|
|
1721
|
-
if (operation === "read" &&
|
|
1740
|
+
if (operation === "read" &&
|
|
1741
|
+
key === "constructor" &&
|
|
1742
|
+
!(objectValue instanceof ProgramObject && has(objectValue, key))) {
|
|
1722
1743
|
const name = constructorName(objectValue);
|
|
1723
1744
|
if (name !== undefined)
|
|
1724
1745
|
return new ComputedValue(self.runtime.builtins.get(name));
|
|
@@ -1802,28 +1823,16 @@ class Frame {
|
|
|
1802
1823
|
}
|
|
1803
1824
|
return new ComputedValue(undefined);
|
|
1804
1825
|
}
|
|
1826
|
+
if (objectValue instanceof ProgramObject)
|
|
1827
|
+
return { target: objectValue, key };
|
|
1805
1828
|
if (isRuntimeReference(objectValue)) {
|
|
1806
1829
|
throw new InterpreterRuntimeError(`Cannot read properties of ${describeValue(objectValue)}; only data values expose properties.`, objectNode, "InvalidDataValue");
|
|
1807
1830
|
}
|
|
1808
|
-
|
|
1809
|
-
throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
|
|
1810
|
-
}
|
|
1811
|
-
if (Array.isArray(objectValue)) {
|
|
1812
|
-
if (operation === "delete")
|
|
1813
|
-
return { target: objectValue, key };
|
|
1814
|
-
const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
|
|
1815
|
-
if (key !== "length" && !(typeof key === "string" && arrayMethods.has(key)) && index === undefined) {
|
|
1816
|
-
if (typeof key === "string" && Object.hasOwn(objectValue, key)) {
|
|
1817
|
-
return new ComputedValue(objectValue[key]);
|
|
1818
|
-
}
|
|
1819
|
-
return new ComputedValue(undefined);
|
|
1820
|
-
}
|
|
1821
|
-
return { target: objectValue, key: index ?? key };
|
|
1822
|
-
}
|
|
1823
|
-
return { target: objectValue, key };
|
|
1831
|
+
throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
|
|
1824
1832
|
});
|
|
1825
1833
|
}
|
|
1826
1834
|
readMember(node) {
|
|
1835
|
+
const self = this;
|
|
1827
1836
|
return Effect.map(this.getMemberReference(node), (reference) => {
|
|
1828
1837
|
if (reference === OptionalShortCircuit)
|
|
1829
1838
|
return OptionalShortCircuit;
|
|
@@ -1831,19 +1840,15 @@ class Frame {
|
|
|
1831
1840
|
return reference.value;
|
|
1832
1841
|
if (reference === undefined || isOpaqueMemberReference(reference))
|
|
1833
1842
|
return reference;
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
if (reference.target instanceof Values.URL) {
|
|
1844
|
-
return Reflect.get(reference.target.url, reference.key);
|
|
1845
|
-
}
|
|
1846
|
-
return Reflect.get(reference.target, reference.key);
|
|
1843
|
+
const value = self.readReferenceValue(reference, reference.key);
|
|
1844
|
+
if (value === undefined &&
|
|
1845
|
+
reference.target instanceof ProgramArray &&
|
|
1846
|
+
typeof reference.key === "string" &&
|
|
1847
|
+
arrayMethods.has(reference.key) &&
|
|
1848
|
+
!has(reference.target, reference.key)) {
|
|
1849
|
+
return new IntrinsicReference(reference.target, reference.key);
|
|
1850
|
+
}
|
|
1851
|
+
return value;
|
|
1847
1852
|
});
|
|
1848
1853
|
}
|
|
1849
1854
|
writeMember(node, value) {
|
|
@@ -1866,7 +1871,7 @@ class Frame {
|
|
|
1866
1871
|
if (reference.target instanceof Values.RegExp) {
|
|
1867
1872
|
return Reflect.deleteProperty(reference.target.regex, reference.key);
|
|
1868
1873
|
}
|
|
1869
|
-
return
|
|
1874
|
+
return remove(reference.target, reference.key);
|
|
1870
1875
|
});
|
|
1871
1876
|
}
|
|
1872
1877
|
// Resolve side-effecting object and key expressions exactly once.
|
|
@@ -1880,13 +1885,6 @@ class Frame {
|
|
|
1880
1885
|
isOpaqueMemberReference(reference)) {
|
|
1881
1886
|
throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
|
|
1882
1887
|
}
|
|
1883
|
-
if (Array.isArray(reference.target)) {
|
|
1884
|
-
if (reference.key === "length")
|
|
1885
|
-
throw new InterpreterRuntimeError("Array length cannot be assigned.", node);
|
|
1886
|
-
if (typeof reference.key === "string" && arrayMethods.has(reference.key)) {
|
|
1887
|
-
throw new InterpreterRuntimeError("Array methods cannot be assigned.", node);
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
1888
|
const key = reference.key;
|
|
1891
1889
|
const { write, next, result } = yield* compute(self.readReferenceValue(reference, key));
|
|
1892
1890
|
if (write)
|
|
@@ -1900,18 +1898,9 @@ class Frame {
|
|
|
1900
1898
|
}
|
|
1901
1899
|
if (reference.target instanceof Values.RegExp)
|
|
1902
1900
|
return reference.target.lastIndex;
|
|
1903
|
-
return
|
|
1901
|
+
return get(reference.target, key);
|
|
1904
1902
|
}
|
|
1905
1903
|
assignToReference(reference, key, next, node) {
|
|
1906
|
-
if (Array.isArray(reference.target)) {
|
|
1907
|
-
const target = reference.target;
|
|
1908
|
-
if (typeof key !== "number" || parseArrayIndex(key) === undefined) {
|
|
1909
|
-
throw new InterpreterRuntimeError("Array assignment index must be a valid array index.", node, "InvalidDataValue");
|
|
1910
|
-
}
|
|
1911
|
-
rejectCircularInsertion(target, next, "Array assignment result", node);
|
|
1912
|
-
target[key] = next;
|
|
1913
|
-
return;
|
|
1914
|
-
}
|
|
1915
1904
|
if (reference.target instanceof Values.URL) {
|
|
1916
1905
|
const property = key;
|
|
1917
1906
|
if (!urlWritableProperties.has(property)) {
|
|
@@ -1933,8 +1922,12 @@ class Frame {
|
|
|
1933
1922
|
return;
|
|
1934
1923
|
}
|
|
1935
1924
|
const target = reference.target;
|
|
1936
|
-
rejectCircularInsertion(target, next, "Object assignment result", node);
|
|
1937
|
-
|
|
1925
|
+
rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
|
|
1926
|
+
if (set(target, key, next))
|
|
1927
|
+
return;
|
|
1928
|
+
if (target instanceof ProgramArray)
|
|
1929
|
+
throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
|
|
1930
|
+
throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node).as("TypeError");
|
|
1938
1931
|
}
|
|
1939
1932
|
toPropertyKey(value, node) {
|
|
1940
1933
|
if (typeof value === "string" || typeof value === "number") {
|