@opencode/codemode 2.0.12 → 2.0.13
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/data.d.ts +5 -4
- package/dist/interpreter/callback.d.ts +10 -15
- package/dist/interpreter/callback.js +15 -7
- package/dist/interpreter/errors.d.ts +3 -3
- package/dist/interpreter/errors.js +1 -2
- package/dist/interpreter/execute.d.ts +2 -1
- package/dist/interpreter/extensions.d.ts +2 -1
- package/dist/interpreter/extensions.js +7 -35
- package/dist/interpreter/globals.d.ts +2 -1
- package/dist/interpreter/globals.js +1 -1
- package/dist/interpreter/interpreter.d.ts +8 -19
- package/dist/interpreter/interpreter.js +96 -98
- package/dist/interpreter/intrinsics.d.ts +3 -3
- package/dist/interpreter/intrinsics.js +2 -0
- package/dist/interpreter/model.d.ts +7 -8
- package/dist/interpreter/model.js +0 -1
- package/dist/interpreter/native.d.ts +5 -5
- package/dist/interpreter/objects.d.ts +148 -47
- package/dist/interpreter/objects.js +224 -26
- package/dist/interpreter/promises.d.ts +7 -7
- package/dist/interpreter/promises.js +32 -11
- package/dist/interpreter/references.d.ts +8 -7
- package/dist/interpreter/references.js +10 -46
- package/dist/interpreter/scope.d.ts +5 -4
- package/dist/stdlib/array.d.ts +2 -1
- package/dist/stdlib/array.js +29 -51
- package/dist/stdlib/bytes.js +14 -24
- package/dist/stdlib/collections.js +27 -30
- package/dist/stdlib/console.d.ts +2 -2
- package/dist/stdlib/console.js +6 -50
- package/dist/stdlib/date.js +1 -2
- package/dist/stdlib/headers.js +10 -22
- package/dist/stdlib/iterator.d.ts +1 -1
- package/dist/stdlib/iterator.js +294 -6
- package/dist/stdlib/json.js +3 -5
- package/dist/stdlib/math.js +5 -17
- package/dist/stdlib/number.js +8 -21
- package/dist/stdlib/object.d.ts +3 -4
- package/dist/stdlib/object.js +5 -16
- package/dist/stdlib/regexp.d.ts +3 -3
- package/dist/stdlib/regexp.js +1 -2
- package/dist/stdlib/string.js +10 -20
- package/dist/stdlib/url.d.ts +2 -1
- package/dist/stdlib/url.js +6 -16
- package/dist/stdlib/value.d.ts +0 -3
- package/dist/stdlib/value.js +2 -74
- package/dist/stdlib/web.js +1 -2
- package/dist/tool-runtime.js +38 -28
- package/package.json +1 -1
|
@@ -6,14 +6,14 @@ import { checkStringLength } from "./limits.js";
|
|
|
6
6
|
import { locate, materialize } from "./errors.js";
|
|
7
7
|
import { primitivePrototype } from "./intrinsics.js";
|
|
8
8
|
import { globals } from "./globals.js";
|
|
9
|
-
import { assign, Callable, define, get, has, hasPrototype, keys, Native, parseArrayIndex, Arr,
|
|
9
|
+
import { assign, Callable, define, get, hostCursor, IteratorObj, has, hidden, hasPrototype, keys, Native, parseArrayIndex, Arr, Fn, GeneratorObj, Obj, PromiseObj, record, remove, set, coerceToNumber, coerceToString, } from "./objects.js";
|
|
10
10
|
import { preserveConsumerError } from "./callback.js";
|
|
11
11
|
import { Pending, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
12
12
|
import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
13
13
|
import { ScopeStack } from "./scope.js";
|
|
14
14
|
import { constructRegExp } from "../stdlib/regexp.js";
|
|
15
15
|
import { enumerableSource } from "../stdlib/object.js";
|
|
16
|
-
import {
|
|
16
|
+
import { compoundOperators } from "../stdlib/value.js";
|
|
17
17
|
// What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
|
|
18
18
|
// Unlabelled break ends this loop; a label the loop does not carry propagates outward.
|
|
19
19
|
const loopExit = (result, labels) => {
|
|
@@ -51,6 +51,14 @@ const calleeDescription = (node) => {
|
|
|
51
51
|
return object === undefined ? undefined : `${object}.${key}`;
|
|
52
52
|
};
|
|
53
53
|
// OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
|
|
54
|
+
// acorn types every literal as possibly a BigInt or RegExp; regex literals become RegExp objects before this is asked.
|
|
55
|
+
const literal = (node) => {
|
|
56
|
+
if (typeof node.value === "bigint")
|
|
57
|
+
throw typeError("BigInt literals are not supported.", node);
|
|
58
|
+
if (node.value instanceof RegExp)
|
|
59
|
+
throw unsupportedSyntax("RegExpLiteral", node);
|
|
60
|
+
return node.value;
|
|
61
|
+
};
|
|
54
62
|
const instanceofValue = (lhs, rhs, node) => {
|
|
55
63
|
if (!(rhs instanceof Callable)) {
|
|
56
64
|
throw typeError("The right-hand side of 'instanceof' is not callable.", node);
|
|
@@ -180,6 +188,9 @@ export class Interpreter {
|
|
|
180
188
|
iterate(value) {
|
|
181
189
|
return this.root.iterate(value);
|
|
182
190
|
}
|
|
191
|
+
iterateDirect(value) {
|
|
192
|
+
return this.root.iterateDirect(value);
|
|
193
|
+
}
|
|
183
194
|
/** Runs one host tool: arguments cross as JSON and the result comes back as program values. */
|
|
184
195
|
tool(run, args) {
|
|
185
196
|
const ctx = this;
|
|
@@ -307,7 +318,16 @@ class Frame {
|
|
|
307
318
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
308
319
|
}
|
|
309
320
|
createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
|
|
310
|
-
|
|
321
|
+
const builtins = this.ctx.builtins;
|
|
322
|
+
const fn = new Fn(builtins.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
323
|
+
// Each generator function gets its own prototype, so `g() instanceof g` holds as in JS.
|
|
324
|
+
if (node.generator)
|
|
325
|
+
define(fn, "prototype", new Obj(node.async ? builtins.AsyncGenerator : builtins.Generator), hidden);
|
|
326
|
+
// The body of a named function expression sees its own name, read-only.
|
|
327
|
+
if (node.type === "FunctionExpression" && node.id) {
|
|
328
|
+
fn.capturedScopes.push(new Map([[node.id.name, { mutable: false, value: fn, initialized: true }]]));
|
|
329
|
+
}
|
|
330
|
+
return fn;
|
|
311
331
|
}
|
|
312
332
|
// NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
|
|
313
333
|
evaluateNamed(node, name) {
|
|
@@ -316,11 +336,12 @@ class Frame {
|
|
|
316
336
|
}
|
|
317
337
|
return this.evaluateExpression(node);
|
|
318
338
|
}
|
|
339
|
+
// Repeated `function` declarations and `var` clashes are legal: the last declaration wins.
|
|
319
340
|
hoistFunctions(statements) {
|
|
320
341
|
for (const node of statements) {
|
|
321
342
|
if (node.type !== "FunctionDeclaration")
|
|
322
343
|
continue;
|
|
323
|
-
this.scopes.
|
|
344
|
+
this.scopes.current().set(node.id.name, { mutable: true, value: this.createFunction(node), initialized: true });
|
|
324
345
|
}
|
|
325
346
|
}
|
|
326
347
|
// Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
|
|
@@ -484,10 +505,10 @@ class Frame {
|
|
|
484
505
|
if (declared?.lexical)
|
|
485
506
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
486
507
|
const right = yield* self.evaluateExpression(node.right);
|
|
487
|
-
const cursor = self.
|
|
508
|
+
const cursor = self.builtinCursor(right);
|
|
488
509
|
const iterator = cursor === undefined ? yield* self.customIterator(right, node, awaiting) : undefined;
|
|
489
510
|
if (iterator === undefined && cursor === undefined) {
|
|
490
|
-
throw invalidData(`${awaiting ? "for await...of" : "for...of"} requires an
|
|
511
|
+
throw invalidData(`${awaiting ? "for await...of" : "for...of"} requires an iterable value, received ${describeValue(right)}.`, node);
|
|
491
512
|
}
|
|
492
513
|
const close = () => iterator
|
|
493
514
|
? self.closeIterator(iterator, node, awaiting)
|
|
@@ -525,10 +546,9 @@ class Frame {
|
|
|
525
546
|
const bodyExit = yield* Effect.exit(evaluateBody(step.value));
|
|
526
547
|
if (!Exit.isSuccess(bodyExit)) {
|
|
527
548
|
// Process interruption must remain prompt; user cleanup cannot extend a timeout.
|
|
528
|
-
if (
|
|
529
|
-
yield* Effect.
|
|
530
|
-
|
|
531
|
-
return yield* Effect.failCause(bodyExit.cause);
|
|
549
|
+
if (Cause.hasInterruptsOnly(bodyExit.cause))
|
|
550
|
+
return yield* Effect.failCause(bodyExit.cause);
|
|
551
|
+
return yield* preserveConsumerError(close(), Effect.failCause(bodyExit.cause));
|
|
532
552
|
}
|
|
533
553
|
const exit = loopExit(bodyExit.value, labels);
|
|
534
554
|
if (exit !== undefined) {
|
|
@@ -557,49 +577,41 @@ class Frame {
|
|
|
557
577
|
});
|
|
558
578
|
}
|
|
559
579
|
iterate(value, node) {
|
|
560
|
-
const cursor = this.
|
|
580
|
+
const cursor = this.builtinCursor(value);
|
|
561
581
|
if (cursor !== undefined)
|
|
562
582
|
return Effect.succeed(cursor);
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
583
|
+
return Effect.map(this.customIterator(value, node, false), (iterator) => iterator === undefined ? undefined : this.customCursor(iterator, node));
|
|
584
|
+
}
|
|
585
|
+
/** GetIteratorDirect: drive an iterator by its own `next`, without asking for `[Symbol.iterator]`. */
|
|
586
|
+
iterateDirect(value, node) {
|
|
587
|
+
if (value instanceof IteratorObj)
|
|
588
|
+
return value.cursor;
|
|
589
|
+
if (!(value instanceof Obj)) {
|
|
590
|
+
throw typeError(`An iterator must be an object, received ${describeValue(value)}.`, node);
|
|
591
|
+
}
|
|
592
|
+
return this.customCursor({
|
|
593
|
+
iterator: value,
|
|
594
|
+
next: this.requireIteratorMethod(get(value, "next"), "Iterator next", node),
|
|
595
|
+
asynchronous: false,
|
|
596
|
+
}, node);
|
|
570
597
|
}
|
|
571
|
-
|
|
572
|
-
const iterator = value instanceof Arr
|
|
573
|
-
? value.items[Symbol.iterator]()
|
|
574
|
-
: typeof value === "string"
|
|
575
|
-
? value[Symbol.iterator]()
|
|
576
|
-
: value instanceof MapObj
|
|
577
|
-
? value.map.entries()
|
|
578
|
-
: value instanceof SetObj
|
|
579
|
-
? value.set.values()
|
|
580
|
-
: value instanceof URLSearchParamsObj
|
|
581
|
-
? value.params.entries()
|
|
582
|
-
: value instanceof HeadersObj
|
|
583
|
-
? value.headers.entries()
|
|
584
|
-
: value instanceof Bytes
|
|
585
|
-
? value.bytes.values()
|
|
586
|
-
: value instanceof IteratorObj
|
|
587
|
-
? value.iterator
|
|
588
|
-
: undefined;
|
|
589
|
-
if (iterator === undefined)
|
|
590
|
-
return undefined;
|
|
591
|
-
const proto = this.ctx.builtins.Array;
|
|
598
|
+
customCursor(iterator, node) {
|
|
592
599
|
return {
|
|
593
|
-
next:
|
|
594
|
-
|
|
595
|
-
return {
|
|
596
|
-
done: Boolean(step.done),
|
|
597
|
-
value: Array.isArray(step.value) ? new Arr(proto, step.value) : step.value,
|
|
598
|
-
};
|
|
599
|
-
}),
|
|
600
|
-
close: Effect.void,
|
|
600
|
+
next: this.nextIteratorResult(iterator, node, false),
|
|
601
|
+
close: Effect.suspend(() => this.closeIterator(iterator, node, false)),
|
|
601
602
|
};
|
|
602
603
|
}
|
|
604
|
+
builtinCursor(value) {
|
|
605
|
+
// Natives build their cursors without knowing R, like `lift` in native.ts.
|
|
606
|
+
if (value instanceof IteratorObj)
|
|
607
|
+
return value.cursor;
|
|
608
|
+
const iterator = typeof value === "string"
|
|
609
|
+
? value[Symbol.iterator]()
|
|
610
|
+
: value instanceof Obj
|
|
611
|
+
? value.iterator(this.ctx.builtins)
|
|
612
|
+
: undefined;
|
|
613
|
+
return iterator === undefined ? undefined : hostCursor(iterator);
|
|
614
|
+
}
|
|
603
615
|
customIterator(value, node, allowAsync = true) {
|
|
604
616
|
if (!(value instanceof Obj))
|
|
605
617
|
return Effect.undefined;
|
|
@@ -941,7 +953,7 @@ class Frame {
|
|
|
941
953
|
return;
|
|
942
954
|
}
|
|
943
955
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
944
|
-
yield* step.done ? consumed : preserveConsumerError(cursor, consumed);
|
|
956
|
+
yield* step.done ? consumed : preserveConsumerError(cursor.close, consumed);
|
|
945
957
|
}
|
|
946
958
|
if (!done)
|
|
947
959
|
yield* cursor.close;
|
|
@@ -953,7 +965,7 @@ class Frame {
|
|
|
953
965
|
}
|
|
954
966
|
const keyNode = property.key;
|
|
955
967
|
if (property.computed) {
|
|
956
|
-
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value
|
|
968
|
+
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value));
|
|
957
969
|
}
|
|
958
970
|
if (keyNode.type === "Identifier")
|
|
959
971
|
return Effect.succeed(keyNode.name);
|
|
@@ -967,9 +979,7 @@ class Frame {
|
|
|
967
979
|
const regex = node.regex;
|
|
968
980
|
if (regex)
|
|
969
981
|
return Effect.sync(() => constructRegExp(this.ctx.builtins, [regex.pattern, regex.flags]));
|
|
970
|
-
|
|
971
|
-
throw typeError("BigInt literals are not supported.", node);
|
|
972
|
-
return Effect.succeed(node.value);
|
|
982
|
+
return Effect.succeed(literal(node));
|
|
973
983
|
}
|
|
974
984
|
case "Identifier":
|
|
975
985
|
return Effect.sync(() => this.scopes.get(node.name, node));
|
|
@@ -1069,14 +1079,9 @@ class Frame {
|
|
|
1069
1079
|
if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
|
|
1070
1080
|
throw invalidData("Binary operators require data values.", node);
|
|
1071
1081
|
}
|
|
1072
|
-
//
|
|
1073
|
-
|
|
1074
|
-
const coerceOperand = (operand) =>
|
|
1075
|
-
if (operand instanceof DateObj) {
|
|
1076
|
-
return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
|
|
1077
|
-
}
|
|
1078
|
-
return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
|
|
1079
|
-
};
|
|
1082
|
+
// Addition and loose equality use the default hint; every other operator asks for a number.
|
|
1083
|
+
const hint = operator === "+" || operator === "==" || operator === "!=" ? "default" : "number";
|
|
1084
|
+
const coerceOperand = (operand) => (operand instanceof Obj ? operand.toPrimitive(hint) : operand);
|
|
1080
1085
|
const bothObjects = lhs !== null && typeof lhs === "object" && rhs !== null && typeof rhs === "object";
|
|
1081
1086
|
const l = coerceOperand(lhs);
|
|
1082
1087
|
const r = coerceOperand(rhs);
|
|
@@ -1161,11 +1166,7 @@ class Frame {
|
|
|
1161
1166
|
if (containsOpaqueReference(value)) {
|
|
1162
1167
|
throw invalidData("Unary operators require data values.", node);
|
|
1163
1168
|
}
|
|
1164
|
-
const operand = value instanceof
|
|
1165
|
-
? value.time
|
|
1166
|
-
: value !== null && typeof value === "object"
|
|
1167
|
-
? coerceToString(value)
|
|
1168
|
-
: value;
|
|
1169
|
+
const operand = value instanceof Obj ? value.toPrimitive("number") : value;
|
|
1169
1170
|
let result;
|
|
1170
1171
|
switch (operator) {
|
|
1171
1172
|
case "+":
|
|
@@ -1358,14 +1359,14 @@ class Frame {
|
|
|
1358
1359
|
if (depth > MAX_CALL_DEPTH)
|
|
1359
1360
|
throw rangeError("Maximum call stack size exceeded", node);
|
|
1360
1361
|
const invocation = new Frame(this.ctx, new ScopeStack([...fn.capturedScopes, new Map()]), depth);
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
for (const
|
|
1365
|
-
|
|
1366
|
-
paramScope.set(name, { mutable: true, value: undefined, initialized: false });
|
|
1367
|
-
}
|
|
1362
|
+
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
|
1363
|
+
const paramScope = invocation.scopes.current();
|
|
1364
|
+
for (const parameter of fn.parameters) {
|
|
1365
|
+
for (const name of collectPatternNames(parameter)) {
|
|
1366
|
+
paramScope.set(name, { mutable: true, value: undefined, initialized: false });
|
|
1368
1367
|
}
|
|
1368
|
+
}
|
|
1369
|
+
const bind = Effect.gen(function* () {
|
|
1369
1370
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1370
1371
|
if (parameter.type === "RestElement") {
|
|
1371
1372
|
yield* invocation.declarePattern(parameter.argument, new Arr(self.ctx.builtins.Array, args.slice(index)), true, parameter, true);
|
|
@@ -1373,6 +1374,8 @@ class Frame {
|
|
|
1373
1374
|
}
|
|
1374
1375
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1375
1376
|
}
|
|
1377
|
+
});
|
|
1378
|
+
const body = Effect.gen(function* () {
|
|
1376
1379
|
if (fn.body.type === "BlockStatement") {
|
|
1377
1380
|
invocation.scopes.push();
|
|
1378
1381
|
invocation.hoistVars(fn.body.body, paramScope);
|
|
@@ -1381,14 +1384,17 @@ class Frame {
|
|
|
1381
1384
|
}
|
|
1382
1385
|
return yield* invocation.evaluateExpression(fn.body);
|
|
1383
1386
|
});
|
|
1387
|
+
// Generators bind parameters at the call and defer only the body to the first `next()`, as in JS.
|
|
1384
1388
|
if (fn.generator)
|
|
1385
|
-
return Effect.
|
|
1389
|
+
return Effect.map(bind, () => this.createGenerator(invocation, body, fn));
|
|
1390
|
+
const run = Effect.andThen(bind, body);
|
|
1386
1391
|
if (!fn.async)
|
|
1387
1392
|
return run;
|
|
1388
1393
|
return this.ctx.pending.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.ctx, value, self)));
|
|
1389
1394
|
});
|
|
1390
1395
|
}
|
|
1391
|
-
createGenerator(invocation, run,
|
|
1396
|
+
createGenerator(invocation, run, fn) {
|
|
1397
|
+
const asynchronous = fn.async;
|
|
1392
1398
|
const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
|
|
1393
1399
|
invocation.generatorState = state;
|
|
1394
1400
|
invocation.generatorAsync = asynchronous;
|
|
@@ -1447,8 +1453,8 @@ class Frame {
|
|
|
1447
1453
|
}
|
|
1448
1454
|
return Deferred.await(request.response);
|
|
1449
1455
|
};
|
|
1450
|
-
const
|
|
1451
|
-
return
|
|
1456
|
+
const proto = get(fn, "prototype");
|
|
1457
|
+
return new GeneratorObj(proto instanceof Obj ? proto : builtins.Generator, asynchronous, request);
|
|
1452
1458
|
}
|
|
1453
1459
|
completeGeneratorRequests(state, asynchronous) {
|
|
1454
1460
|
const self = this;
|
|
@@ -1524,16 +1530,8 @@ class Frame {
|
|
|
1524
1530
|
delegateYield(value, node) {
|
|
1525
1531
|
const self = this;
|
|
1526
1532
|
return Effect.gen(function* () {
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
value instanceof MapObj ||
|
|
1530
|
-
value instanceof SetObj ||
|
|
1531
|
-
value instanceof URLSearchParamsObj ||
|
|
1532
|
-
value instanceof HeadersObj ||
|
|
1533
|
-
value instanceof Bytes) {
|
|
1534
|
-
const cursor = yield* self.iterate(value, node);
|
|
1535
|
-
if (!cursor)
|
|
1536
|
-
throw typeError("Built-in iterator is unavailable.", node);
|
|
1533
|
+
const cursor = self.builtinCursor(value);
|
|
1534
|
+
if (cursor !== undefined) {
|
|
1537
1535
|
while (true) {
|
|
1538
1536
|
const step = yield* cursor.next;
|
|
1539
1537
|
if (step.done)
|
|
@@ -1610,13 +1608,13 @@ class Frame {
|
|
|
1610
1608
|
const keyNode = property.key;
|
|
1611
1609
|
let key;
|
|
1612
1610
|
if (property.computed) {
|
|
1613
|
-
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode)
|
|
1611
|
+
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode));
|
|
1614
1612
|
}
|
|
1615
1613
|
else if (keyNode.type === "Identifier") {
|
|
1616
1614
|
key = keyNode.name;
|
|
1617
1615
|
}
|
|
1618
1616
|
else if (keyNode.type === "Literal") {
|
|
1619
|
-
key = self.toPropertyKey(keyNode
|
|
1617
|
+
key = self.toPropertyKey(literal(keyNode));
|
|
1620
1618
|
}
|
|
1621
1619
|
else {
|
|
1622
1620
|
throw typeError("Unsupported object property key shape.", keyNode);
|
|
@@ -1707,10 +1705,10 @@ class Frame {
|
|
|
1707
1705
|
if ((objectValue === null || objectValue === undefined) && node.optional)
|
|
1708
1706
|
return OptionalShortCircuit;
|
|
1709
1707
|
const key = node.computed
|
|
1710
|
-
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode)
|
|
1708
|
+
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode))
|
|
1711
1709
|
: propertyNode.type === "Identifier"
|
|
1712
1710
|
? propertyNode.name
|
|
1713
|
-
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode)
|
|
1711
|
+
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode));
|
|
1714
1712
|
if (objectValue instanceof ToolReference) {
|
|
1715
1713
|
if (typeof key !== "string") {
|
|
1716
1714
|
throw typeError("Tool paths must use string property names.", propertyNode);
|
|
@@ -1768,9 +1766,11 @@ class Frame {
|
|
|
1768
1766
|
}
|
|
1769
1767
|
evaluateDeleteExpression(argument) {
|
|
1770
1768
|
const target = argument.type === "ChainExpression" ? argument.expression : argument;
|
|
1771
|
-
if (target.type
|
|
1769
|
+
if (target.type === "Identifier")
|
|
1772
1770
|
throw typeError("Only data fields may be deleted.", argument);
|
|
1773
|
-
|
|
1771
|
+
// `delete <non-reference>` evaluates the operand and is true, as in JS.
|
|
1772
|
+
if (target.type !== "MemberExpression")
|
|
1773
|
+
return Effect.map(this.evaluateExpression(target), () => true);
|
|
1774
1774
|
return Effect.map(this.getMemberReference(target), (reference) => {
|
|
1775
1775
|
if (reference === OptionalShortCircuit)
|
|
1776
1776
|
return true;
|
|
@@ -1816,12 +1816,10 @@ class Frame {
|
|
|
1816
1816
|
throw rangeError("Invalid array length", node);
|
|
1817
1817
|
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
1818
1818
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
}
|
|
1823
|
-
if (value === AsyncIteratorSymbol || value === IteratorSymbol)
|
|
1819
|
+
// ToPropertyKey: anything else becomes its string form, so `counts[row.category]` works when the field is null.
|
|
1820
|
+
toPropertyKey(value) {
|
|
1821
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "symbol")
|
|
1824
1822
|
return value;
|
|
1825
|
-
|
|
1823
|
+
return coerceToString(value);
|
|
1826
1824
|
}
|
|
1827
1825
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ErrorObj, Obj } from "./objects.js";
|
|
1
|
+
import { ErrorObj, Obj, type Value } from "./objects.js";
|
|
2
2
|
export declare const errorTypes: readonly ["Error", "TypeError", "RangeError", "SyntaxError", "ReferenceError", "EvalError", "URIError", "AggregateError"];
|
|
3
3
|
export type ErrorType = (typeof errorTypes)[number];
|
|
4
4
|
export declare const isErrorType: (name: string) => name is ErrorType;
|
|
5
|
-
declare const builtins: readonly ["Object", "Function", "Array", "String", "Number", "Boolean", "Date", "RegExp", "Map", "Set", "URL", "URLSearchParams", "Headers", "Uint8Array", "TextEncoder", "TextDecoder", "Promise", "Iterator", "AsyncIterator", "Generator", "AsyncGenerator"];
|
|
5
|
+
declare const builtins: readonly ["Object", "Function", "Array", "String", "Number", "Boolean", "Date", "RegExp", "Map", "Set", "URL", "URLSearchParams", "Headers", "Uint8Array", "TextEncoder", "TextDecoder", "Promise", "Iterator", "IteratorHelper", "AsyncIterator", "Generator", "AsyncGenerator"];
|
|
6
6
|
/**
|
|
7
7
|
* The built-in prototype objects of one runtime, allocated empty in dependency order. The globals populate them
|
|
8
8
|
* and attach their constructors when the runtime is built.
|
|
@@ -10,6 +10,6 @@ declare const builtins: readonly ["Object", "Function", "Array", "String", "Numb
|
|
|
10
10
|
export type Builtins = Readonly<Record<(typeof builtins)[number] | ErrorType, Obj>>;
|
|
11
11
|
export declare const createErrorValue: (prototype: Obj, message: string | undefined) => ErrorObj;
|
|
12
12
|
/** The prototype a primitive reads its methods from without being boxed; none for null, undefined, and symbols. */
|
|
13
|
-
export declare const primitivePrototype: (builtins: Builtins, value:
|
|
13
|
+
export declare const primitivePrototype: (builtins: Builtins, value: Value) => Obj | undefined;
|
|
14
14
|
export declare const createBuiltins: () => Builtins;
|
|
15
15
|
export {};
|
|
@@ -30,6 +30,7 @@ const builtins = [
|
|
|
30
30
|
"TextDecoder",
|
|
31
31
|
"Promise",
|
|
32
32
|
"Iterator",
|
|
33
|
+
"IteratorHelper",
|
|
33
34
|
"AsyncIterator",
|
|
34
35
|
"Generator",
|
|
35
36
|
"AsyncGenerator",
|
|
@@ -85,6 +86,7 @@ export const createBuiltins = () => {
|
|
|
85
86
|
TextDecoder: plain(),
|
|
86
87
|
Promise: plain(),
|
|
87
88
|
Iterator: iterator,
|
|
89
|
+
IteratorHelper: new Obj(iterator),
|
|
88
90
|
AsyncIterator: asyncIterator,
|
|
89
91
|
Generator: new Obj(iterator),
|
|
90
92
|
AsyncGenerator: new Obj(asyncIterator),
|
|
@@ -2,7 +2,7 @@ import type { Node } from "acorn";
|
|
|
2
2
|
import { Context } from "effect";
|
|
3
3
|
import type { ErrorType } from "./intrinsics.js";
|
|
4
4
|
import type { DiagnosticKind } from "../codemode.js";
|
|
5
|
-
import type { ErrorObj } from "./objects.js";
|
|
5
|
+
import type { ErrorObj, Value } from "./objects.js";
|
|
6
6
|
/** Any parsed node; the interpreter narrows on `type` and reads `loc` for diagnostics. */
|
|
7
7
|
export type AstNode = Node;
|
|
8
8
|
/** The program call a built-in is running under: where to locate failures born inside it, and how deep the stack is there. */
|
|
@@ -12,14 +12,14 @@ export declare const CallSite: Context.Reference<{
|
|
|
12
12
|
}>;
|
|
13
13
|
export type Binding = {
|
|
14
14
|
mutable: boolean;
|
|
15
|
-
value:
|
|
15
|
+
value: Value;
|
|
16
16
|
initialized?: boolean;
|
|
17
17
|
};
|
|
18
18
|
export type StatementResult = {
|
|
19
19
|
kind: "none";
|
|
20
20
|
} | {
|
|
21
21
|
kind: "return";
|
|
22
|
-
value:
|
|
22
|
+
value: Value;
|
|
23
23
|
} | {
|
|
24
24
|
kind: "break";
|
|
25
25
|
label?: string;
|
|
@@ -32,12 +32,12 @@ export declare const AsyncIteratorSymbol: unique symbol;
|
|
|
32
32
|
export declare const IteratorSymbol: unique symbol;
|
|
33
33
|
export declare const IteratorSymbols: readonly [typeof AsyncIteratorSymbol, typeof IteratorSymbol];
|
|
34
34
|
export declare class Throw {
|
|
35
|
-
readonly value:
|
|
36
|
-
constructor(value:
|
|
35
|
+
readonly value: Value;
|
|
36
|
+
constructor(value: Value);
|
|
37
37
|
}
|
|
38
38
|
export declare class GeneratorReturn {
|
|
39
|
-
readonly value:
|
|
40
|
-
constructor(value:
|
|
39
|
+
readonly value: Value;
|
|
40
|
+
constructor(value: Value);
|
|
41
41
|
}
|
|
42
42
|
export declare const OptionalShortCircuit: unique symbol;
|
|
43
43
|
/**
|
|
@@ -64,7 +64,6 @@ export declare const syntaxError: (message: string, node?: AstNode) => PendingTh
|
|
|
64
64
|
export declare const uriError: (message: string, node?: AstNode) => PendingThrow;
|
|
65
65
|
export declare const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
66
66
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => PendingThrow;
|
|
67
|
-
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
68
67
|
export declare const sourceLocation: (node: AstNode) => {
|
|
69
68
|
readonly line: number;
|
|
70
69
|
readonly column: number;
|
|
@@ -51,7 +51,6 @@ export const uriError = failure("URIError");
|
|
|
51
51
|
// Orient the agent rather than enumerate JavaScript; interpreter-support.md is the full matrix.
|
|
52
52
|
export const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
53
53
|
export const unsupportedSyntax = (kind, node) => new PendingThrow("SyntaxError", `Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
54
|
-
export const isRecord = (value) => typeof value === "object" && value !== null;
|
|
55
54
|
// Acorn lines are 1-based and its columns are 0-based. Diagnostics use 1-based columns of the submitted source.
|
|
56
55
|
export const sourceLocation = (node) => ({
|
|
57
56
|
line: node.loc?.start.line ?? 1,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import type { Builtins } from "./intrinsics.js";
|
|
3
|
-
import { type Callable, Native, type NativeOptions, Obj } from "./objects.js";
|
|
4
|
-
/** A native function body: a
|
|
5
|
-
export type Impl = (thisValue:
|
|
3
|
+
import { type Callable, Native, type NativeOptions, Obj, type Value } from "./objects.js";
|
|
4
|
+
/** A native function body: a value, a thrown `PendingThrow`, or an Effect of a value. */
|
|
5
|
+
export type Impl = (thisValue: Value, args: Array<Value>) => Value | Effect.Effect<Value, unknown, unknown>;
|
|
6
6
|
export declare const native: <R>(builtins: Builtins, options: NativeOptions<R>) => Native<R>;
|
|
7
7
|
export declare const fn: <R>(builtins: Builtins, name: string, length: number, impl: Impl) => Native<R>;
|
|
8
8
|
export type Method = readonly [name: string, length: number, impl: Impl];
|
|
9
9
|
export declare const methods: (builtins: Builtins, target: Obj, table: ReadonlyArray<Method>) => void;
|
|
10
|
-
export declare const constants: (target: Obj, table: Record<string,
|
|
10
|
+
export declare const constants: (target: Obj, table: Record<string, Value>) => void;
|
|
11
11
|
/** A constructor wired to its prototype: `C.prototype === proto` and `proto.constructor === C`. */
|
|
12
12
|
export declare const constructor: <R>(builtins: Builtins, proto: Obj, options: NativeOptions<R>) => Native<R>;
|
|
13
13
|
/** The `call` of a constructor that JS requires to be invoked with `new`. */
|
|
@@ -15,4 +15,4 @@ export declare const requiresNew: (name: string) => () => Effect.Effect<never, u
|
|
|
15
15
|
/** The instance prototype for `new` via `newTarget.prototype`, falling back to the built-in's own. */
|
|
16
16
|
export declare const prototypeFrom: (newTarget: Callable, fallback: Obj) => Obj;
|
|
17
17
|
/** Narrows a method receiver to the built-in it belongs to, or throws the TypeError JS would. */
|
|
18
|
-
export declare const receiver: <T extends Obj>(cls: abstract new (...args: never) => T, thisValue:
|
|
18
|
+
export declare const receiver: <T extends Obj>(cls: abstract new (...args: never) => T, thisValue: Value, method: string) => T;
|