@opencode/codemode 0.0.0-dev-19942 → 0.0.0-dev-19959
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/interpreter/callback.d.ts +4 -9
- package/dist/interpreter/callback.js +15 -6
- package/dist/interpreter/globals.js +1 -1
- package/dist/interpreter/interpreter.d.ts +3 -8
- package/dist/interpreter/interpreter.js +36 -26
- package/dist/interpreter/intrinsics.d.ts +1 -1
- package/dist/interpreter/intrinsics.js +2 -0
- package/dist/interpreter/objects.d.ts +19 -5
- package/dist/interpreter/objects.js +18 -7
- package/dist/interpreter/promises.js +32 -11
- package/dist/stdlib/array.js +7 -7
- package/dist/stdlib/bytes.js +4 -4
- package/dist/stdlib/collections.js +22 -18
- package/dist/stdlib/headers.js +4 -13
- package/dist/stdlib/iterator.d.ts +1 -1
- package/dist/stdlib/iterator.js +294 -6
- package/dist/stdlib/math.js +1 -1
- package/dist/stdlib/object.js +1 -1
- package/dist/stdlib/string.js +2 -2
- package/dist/stdlib/url.js +6 -6
- package/dist/tool-runtime.js +11 -5
- package/package.json +1 -1
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import type { Interpreter } from "./interpreter.js";
|
|
3
|
-
import { Callable, type Value } from "./objects.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly value: Value;
|
|
8
|
-
}, unknown, R>;
|
|
9
|
-
readonly close: Effect.Effect<void, unknown, R>;
|
|
10
|
-
};
|
|
11
|
-
export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
|
|
3
|
+
import { Callable, type Cursor, type Value } from "./objects.js";
|
|
4
|
+
/** IteratorClose: a consumer failure closes the iterator and wins over any close failure, except that a generator's
|
|
5
|
+
* return() is a return completion, so a failing close wins over it, as after `break`. */
|
|
6
|
+
export declare const preserveConsumerError: <A, R>(close: Cursor<R>["close"], effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
|
|
12
7
|
/**
|
|
13
8
|
* ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
|
|
14
9
|
* default hint as "string", like their `Symbol.toPrimitive`.
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { Effect, Exit } from "effect";
|
|
1
|
+
import { Cause, Effect, Exit } from "effect";
|
|
2
2
|
import { primitivePrototype } from "./intrinsics.js";
|
|
3
|
-
import { typeError } from "./model.js";
|
|
4
|
-
import { Callable, get, Native, DateObj, Obj, coerceToNumber, coerceToString } from "./objects.js";
|
|
3
|
+
import { GeneratorReturn, typeError } from "./model.js";
|
|
4
|
+
import { Callable, get, Native, DateObj, Obj, coerceToNumber, coerceToString, } from "./objects.js";
|
|
5
5
|
import { typeofValue } from "./references.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/** IteratorClose: a consumer failure closes the iterator and wins over any close failure, except that a generator's
|
|
7
|
+
* return() is a return completion, so a failing close wins over it, as after `break`. */
|
|
8
|
+
export const preserveConsumerError = (close, effect) => Effect.flatMap(Effect.exit(effect), (exit) => {
|
|
9
|
+
if (Exit.isSuccess(exit))
|
|
10
|
+
return Effect.succeed(exit.value);
|
|
11
|
+
return Effect.flatMap(Effect.exit(close), (closed) => {
|
|
12
|
+
if (!Exit.isSuccess(closed) && Cause.squash(exit.cause) instanceof GeneratorReturn) {
|
|
13
|
+
return Effect.failCause(closed.cause);
|
|
14
|
+
}
|
|
15
|
+
return Effect.failCause(exit.cause);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
9
18
|
/**
|
|
10
19
|
* ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
|
|
11
20
|
* default hint as "string", like their `Symbol.toPrimitive`.
|
|
@@ -60,6 +60,7 @@ const table = {
|
|
|
60
60
|
console: (ctx) => consoleGlobal(ctx),
|
|
61
61
|
Promise: (ctx) => promiseGlobal(ctx),
|
|
62
62
|
Symbol: (ctx) => symbolGlobal(ctx),
|
|
63
|
+
Iterator: (ctx) => iteratorGlobals(ctx),
|
|
63
64
|
Number: (ctx) => numberGlobal(ctx),
|
|
64
65
|
String: (ctx) => stringGlobal(ctx),
|
|
65
66
|
Boolean: (ctx) => booleanGlobal(ctx),
|
|
@@ -91,6 +92,5 @@ export const globalNames = new Set(Object.keys(table));
|
|
|
91
92
|
/** The immutable global bindings of every program, in declaration order. */
|
|
92
93
|
export const globals = (ctx) => {
|
|
93
94
|
generatorGlobals(ctx);
|
|
94
|
-
iteratorGlobals(ctx);
|
|
95
95
|
return Object.entries(table).map(([name, factory]) => [name, factory(ctx)]);
|
|
96
96
|
};
|
|
@@ -3,7 +3,7 @@ import { Effect } from "effect";
|
|
|
3
3
|
import { type Json } from "../data.js";
|
|
4
4
|
import { type ToolRuntime } from "../tool-runtime.js";
|
|
5
5
|
import { type Builtins } from "./intrinsics.js";
|
|
6
|
-
import { PromiseObj, type Value } from "./objects.js";
|
|
6
|
+
import { type Cursor, PromiseObj, type Value } from "./objects.js";
|
|
7
7
|
import { Pending } from "./promises.js";
|
|
8
8
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
9
9
|
export declare class Interpreter<R> {
|
|
@@ -22,13 +22,8 @@ export declare class Interpreter<R> {
|
|
|
22
22
|
run(program: Program): Effect.Effect<Value, unknown, R>;
|
|
23
23
|
call(callable: Value, thisValue: Value, args: Array<Value>): Effect.Effect<Value, unknown, R>;
|
|
24
24
|
await(promise: PromiseObj): Effect.Effect<Value, unknown, never>;
|
|
25
|
-
iterate(value: Value): Effect.Effect<
|
|
26
|
-
|
|
27
|
-
done: boolean;
|
|
28
|
-
value: Value;
|
|
29
|
-
}, unknown, R>;
|
|
30
|
-
close: Effect.Effect<void, unknown, R>;
|
|
31
|
-
} | undefined, unknown, R>;
|
|
25
|
+
iterate(value: Value): Effect.Effect<Cursor<R> | undefined, unknown, R>;
|
|
26
|
+
iterateDirect(value: Value): Cursor<R>;
|
|
32
27
|
/** Runs one host tool: arguments cross as JSON and the result comes back as program values. */
|
|
33
28
|
tool(run: (args: Array<Json | undefined>) => Effect.Effect<Json | undefined, unknown, R>, args: Array<Value>): Effect.Effect<Value, unknown, R>;
|
|
34
29
|
}
|
|
@@ -6,7 +6,7 @@ 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, Fn, GeneratorObj, Obj, PromiseObj, record, remove, set, coerceToNumber, coerceToString, } from "./objects.js";
|
|
9
|
+
import { assign, Callable, define, get, hostCursor, IteratorObj, has, 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";
|
|
@@ -188,6 +188,9 @@ export class Interpreter {
|
|
|
188
188
|
iterate(value) {
|
|
189
189
|
return this.root.iterate(value);
|
|
190
190
|
}
|
|
191
|
+
iterateDirect(value) {
|
|
192
|
+
return this.root.iterateDirect(value);
|
|
193
|
+
}
|
|
191
194
|
/** Runs one host tool: arguments cross as JSON and the result comes back as program values. */
|
|
192
195
|
tool(run, args) {
|
|
193
196
|
const ctx = this;
|
|
@@ -492,7 +495,7 @@ class Frame {
|
|
|
492
495
|
if (declared?.lexical)
|
|
493
496
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
494
497
|
const right = yield* self.evaluateExpression(node.right);
|
|
495
|
-
const cursor = self.
|
|
498
|
+
const cursor = self.builtinCursor(right);
|
|
496
499
|
const iterator = cursor === undefined ? yield* self.customIterator(right, node, awaiting) : undefined;
|
|
497
500
|
if (iterator === undefined && cursor === undefined) {
|
|
498
501
|
throw invalidData(`${awaiting ? "for await...of" : "for...of"} requires an iterable value, received ${describeValue(right)}.`, node);
|
|
@@ -533,10 +536,9 @@ class Frame {
|
|
|
533
536
|
const bodyExit = yield* Effect.exit(evaluateBody(step.value));
|
|
534
537
|
if (!Exit.isSuccess(bodyExit)) {
|
|
535
538
|
// Process interruption must remain prompt; user cleanup cannot extend a timeout.
|
|
536
|
-
if (
|
|
537
|
-
yield* Effect.
|
|
538
|
-
|
|
539
|
-
return yield* Effect.failCause(bodyExit.cause);
|
|
539
|
+
if (Cause.hasInterruptsOnly(bodyExit.cause))
|
|
540
|
+
return yield* Effect.failCause(bodyExit.cause);
|
|
541
|
+
return yield* preserveConsumerError(close(), Effect.failCause(bodyExit.cause));
|
|
540
542
|
}
|
|
541
543
|
const exit = loopExit(bodyExit.value, labels);
|
|
542
544
|
if (exit !== undefined) {
|
|
@@ -565,32 +567,40 @@ class Frame {
|
|
|
565
567
|
});
|
|
566
568
|
}
|
|
567
569
|
iterate(value, node) {
|
|
568
|
-
const cursor = this.
|
|
570
|
+
const cursor = this.builtinCursor(value);
|
|
569
571
|
if (cursor !== undefined)
|
|
570
572
|
return Effect.succeed(cursor);
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
573
|
+
return Effect.map(this.customIterator(value, node, false), (iterator) => iterator === undefined ? undefined : this.customCursor(iterator, node));
|
|
574
|
+
}
|
|
575
|
+
/** GetIteratorDirect: drive an iterator by its own `next`, without asking for `[Symbol.iterator]`. */
|
|
576
|
+
iterateDirect(value, node) {
|
|
577
|
+
if (value instanceof IteratorObj)
|
|
578
|
+
return value.cursor;
|
|
579
|
+
if (!(value instanceof Obj)) {
|
|
580
|
+
throw typeError(`An iterator must be an object, received ${describeValue(value)}.`, node);
|
|
581
|
+
}
|
|
582
|
+
return this.customCursor({
|
|
583
|
+
iterator: value,
|
|
584
|
+
next: this.requireIteratorMethod(get(value, "next"), "Iterator next", node),
|
|
585
|
+
asynchronous: false,
|
|
586
|
+
}, node);
|
|
578
587
|
}
|
|
579
|
-
|
|
588
|
+
customCursor(iterator, node) {
|
|
589
|
+
return {
|
|
590
|
+
next: this.nextIteratorResult(iterator, node, false),
|
|
591
|
+
close: Effect.suspend(() => this.closeIterator(iterator, node, false)),
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
builtinCursor(value) {
|
|
595
|
+
// Natives build their cursors without knowing R, like `lift` in native.ts.
|
|
596
|
+
if (value instanceof IteratorObj)
|
|
597
|
+
return value.cursor;
|
|
580
598
|
const iterator = typeof value === "string"
|
|
581
599
|
? value[Symbol.iterator]()
|
|
582
600
|
: value instanceof Obj
|
|
583
601
|
? value.iterator(this.ctx.builtins)
|
|
584
602
|
: undefined;
|
|
585
|
-
|
|
586
|
-
return undefined;
|
|
587
|
-
return {
|
|
588
|
-
next: Effect.sync(() => {
|
|
589
|
-
const step = iterator.next();
|
|
590
|
-
return { done: Boolean(step.done), value: step.value };
|
|
591
|
-
}),
|
|
592
|
-
close: Effect.void,
|
|
593
|
-
};
|
|
603
|
+
return iterator === undefined ? undefined : hostCursor(iterator);
|
|
594
604
|
}
|
|
595
605
|
customIterator(value, node, allowAsync = true) {
|
|
596
606
|
if (!(value instanceof Obj))
|
|
@@ -933,7 +943,7 @@ class Frame {
|
|
|
933
943
|
return;
|
|
934
944
|
}
|
|
935
945
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
936
|
-
yield* step.done ? consumed : preserveConsumerError(cursor, consumed);
|
|
946
|
+
yield* step.done ? consumed : preserveConsumerError(cursor.close, consumed);
|
|
937
947
|
}
|
|
938
948
|
if (!done)
|
|
939
949
|
yield* cursor.close;
|
|
@@ -1505,7 +1515,7 @@ class Frame {
|
|
|
1505
1515
|
delegateYield(value, node) {
|
|
1506
1516
|
const self = this;
|
|
1507
1517
|
return Effect.gen(function* () {
|
|
1508
|
-
const cursor = self.
|
|
1518
|
+
const cursor = self.builtinCursor(value);
|
|
1509
1519
|
if (cursor !== undefined) {
|
|
1510
1520
|
while (true) {
|
|
1511
1521
|
const step = yield* cursor.next;
|
|
@@ -2,7 +2,7 @@ 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.
|
|
@@ -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),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlockStatement, Expression, Pattern } from "acorn";
|
|
2
|
-
import
|
|
2
|
+
import { Effect, type Fiber } from "effect";
|
|
3
3
|
import { ToolReference } from "../tool-runtime.js";
|
|
4
4
|
import type { Builtins } from "./intrinsics.js";
|
|
5
5
|
import { type Binding, type GeneratorRequestKind, type PendingThrow } from "./model.js";
|
|
@@ -73,6 +73,7 @@ export declare class ErrorObj extends Obj {
|
|
|
73
73
|
host?: PendingThrow;
|
|
74
74
|
/** Error.prototype.toString: "name: message", or just one when the other is empty. */
|
|
75
75
|
toString(): string;
|
|
76
|
+
inspect(): string;
|
|
76
77
|
}
|
|
77
78
|
/** Interpreter machinery a program can hold but never inspect, serialize, or hand to the host. */
|
|
78
79
|
export declare abstract class Opaque extends Obj {
|
|
@@ -122,14 +123,27 @@ export declare class GeneratorObj extends Opaque {
|
|
|
122
123
|
constructor(proto: Obj, asynchronous: boolean, request: (kind: GeneratorRequestKind, value: Value) => Effect.Effect<Value, unknown, unknown>);
|
|
123
124
|
get describe(): string;
|
|
124
125
|
}
|
|
125
|
-
/**
|
|
126
|
+
/** One pull from an iterator, as `for...of` sees it. */
|
|
127
|
+
export type Step = {
|
|
128
|
+
readonly done: boolean;
|
|
129
|
+
readonly value: Value;
|
|
130
|
+
};
|
|
131
|
+
/** How the interpreter drives any iterator: pull the next step, or close it early. */
|
|
132
|
+
export type Cursor<R = unknown> = {
|
|
133
|
+
readonly next: Effect.Effect<Step, unknown, R>;
|
|
134
|
+
readonly close: Effect.Effect<void, unknown, R>;
|
|
135
|
+
};
|
|
136
|
+
/** A cursor over a host iterator; there is nothing to close. */
|
|
137
|
+
export declare const hostCursor: (iterator: Iterator<Value, undefined>) => Cursor<never>;
|
|
138
|
+
/** A built-in iterator: a live cursor over a host collection or an iterator helper, yielding program values. */
|
|
126
139
|
export declare class IteratorObj extends Opaque {
|
|
127
|
-
readonly
|
|
140
|
+
readonly cursor: Cursor;
|
|
128
141
|
readonly tag = "Iterator";
|
|
129
|
-
constructor(proto: Obj,
|
|
142
|
+
constructor(proto: Obj, cursor: Cursor);
|
|
130
143
|
get describe(): string;
|
|
131
|
-
iterator(): IteratorObject<Value, undefined, unknown>;
|
|
132
144
|
}
|
|
145
|
+
/** A built-in iterator over a host iterator, e.g. `array.values()`. */
|
|
146
|
+
export declare const hostIterator: (builtins: Builtins, iterator: Iterator<Value, undefined>) => IteratorObj;
|
|
133
147
|
/** A built-in object around a host value: data-like, so it prints as itself and crosses to extensions as a copy. */
|
|
134
148
|
export declare abstract class Wrapper extends Obj {
|
|
135
149
|
inspect(item: (value: Value) => string): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
1
2
|
import { ToolReference } from "../tool-runtime.js";
|
|
2
3
|
import { checkArrayLength } from "./limits.js";
|
|
3
4
|
import { AsyncIteratorSymbol, IteratorSymbol, } from "./model.js";
|
|
@@ -96,6 +97,9 @@ export class ErrorObj extends Obj {
|
|
|
96
97
|
return shownMessage;
|
|
97
98
|
return `${shownName}: ${shownMessage}`;
|
|
98
99
|
}
|
|
100
|
+
inspect() {
|
|
101
|
+
return this.toString();
|
|
102
|
+
}
|
|
99
103
|
}
|
|
100
104
|
/** Interpreter machinery a program can hold but never inspect, serialize, or hand to the host. */
|
|
101
105
|
export class Opaque extends Obj {
|
|
@@ -168,21 +172,28 @@ export class GeneratorObj extends Opaque {
|
|
|
168
172
|
return "a generator";
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
|
-
/** A
|
|
175
|
+
/** A cursor over a host iterator; there is nothing to close. */
|
|
176
|
+
export const hostCursor = (iterator) => ({
|
|
177
|
+
next: Effect.sync(() => {
|
|
178
|
+
const step = iterator.next();
|
|
179
|
+
return { done: Boolean(step.done), value: step.value };
|
|
180
|
+
}),
|
|
181
|
+
close: Effect.void,
|
|
182
|
+
});
|
|
183
|
+
/** A built-in iterator: a live cursor over a host collection or an iterator helper, yielding program values. */
|
|
172
184
|
export class IteratorObj extends Opaque {
|
|
173
|
-
|
|
185
|
+
cursor;
|
|
174
186
|
tag = "Iterator";
|
|
175
|
-
constructor(proto,
|
|
187
|
+
constructor(proto, cursor) {
|
|
176
188
|
super(proto);
|
|
177
|
-
this.
|
|
189
|
+
this.cursor = cursor;
|
|
178
190
|
}
|
|
179
191
|
get describe() {
|
|
180
192
|
return "an iterator";
|
|
181
193
|
}
|
|
182
|
-
iterator() {
|
|
183
|
-
return this.source;
|
|
184
|
-
}
|
|
185
194
|
}
|
|
195
|
+
/** A built-in iterator over a host iterator, e.g. `array.values()`. */
|
|
196
|
+
export const hostIterator = (builtins, iterator) => new IteratorObj(builtins.Iterator, hostCursor(iterator));
|
|
186
197
|
/** A built-in object around a host value: data-like, so it prints as itself and crosses to extensions as a copy. */
|
|
187
198
|
export class Wrapper extends Obj {
|
|
188
199
|
inspect(item) {
|
|
@@ -4,7 +4,7 @@ import { CallSite, Throw, rangeError, typeError } from "./model.js";
|
|
|
4
4
|
import { Callable, define, get, hidden, Arr, Fn, Obj, PromiseObj, record } from "./objects.js";
|
|
5
5
|
import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
|
|
6
6
|
import { createAggregateErrorValue, locate, materialize, normalizeError } from "./errors.js";
|
|
7
|
-
import { typeofValue } from "./references.js";
|
|
7
|
+
import { describeValue, typeofValue } from "./references.js";
|
|
8
8
|
import { applyCollectionCallback, isSupportedCallback } from "./callback.js";
|
|
9
9
|
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
10
10
|
const capability = (ctx, name, settle) => fn(ctx.builtins, name, 1, (_, args) => {
|
|
@@ -119,7 +119,7 @@ export const resolvePromise = (ctx, value) => {
|
|
|
119
119
|
return Effect.succeed(value);
|
|
120
120
|
return ctx.pending.createWithSelf((self) => resolvePromiseValue(ctx, value, self));
|
|
121
121
|
};
|
|
122
|
-
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
|
|
122
|
+
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject", "withResolvers", "try"];
|
|
123
123
|
const invokePromiseMethod = (ctx, name, args) => {
|
|
124
124
|
if (name === "resolve") {
|
|
125
125
|
return resolvePromise(ctx, args[0]);
|
|
@@ -127,10 +127,26 @@ const invokePromiseMethod = (ctx, name, args) => {
|
|
|
127
127
|
if (name === "reject") {
|
|
128
128
|
return ctx.pending.create(Effect.fail(new Throw(args[0])));
|
|
129
129
|
}
|
|
130
|
+
if (name === "withResolvers") {
|
|
131
|
+
return Effect.map(promiseCapability(ctx), (made) => record(ctx.builtins.Object, { promise: made.promise, resolve: made.resolve, reject: made.reject }));
|
|
132
|
+
}
|
|
133
|
+
if (name === "try") {
|
|
134
|
+
if (typeofValue(args[0]) !== "function") {
|
|
135
|
+
throw typeError(`Promise.try expects a function, received ${describeValue(args[0])}.`);
|
|
136
|
+
}
|
|
137
|
+
return Effect.flatMap(Effect.exit(ctx.call(args[0], undefined, args.slice(1))), (called) => {
|
|
138
|
+
if (Exit.isSuccess(called))
|
|
139
|
+
return resolvePromise(ctx, called.value);
|
|
140
|
+
if (Cause.hasInterruptsOnly(called.cause))
|
|
141
|
+
return Effect.failCause(called.cause);
|
|
142
|
+
return ctx.pending.create(Effect.fail(Cause.squash(called.cause)));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
130
145
|
return ctx.pending.create(Effect.gen(function* () {
|
|
131
146
|
const cursor = yield* ctx.iterate(args[0]);
|
|
132
|
-
if (cursor === undefined)
|
|
133
|
-
throw typeError(`Promise.${name} expects
|
|
147
|
+
if (cursor === undefined) {
|
|
148
|
+
throw typeError(`Promise.${name} expects a synchronous iterable, received ${describeValue(args[0])}.`);
|
|
149
|
+
}
|
|
134
150
|
const items = [];
|
|
135
151
|
while (true) {
|
|
136
152
|
const step = yield* cursor.next;
|
|
@@ -188,22 +204,27 @@ const instanceMethod = (ctx, name, thisValue, args) => {
|
|
|
188
204
|
const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method);
|
|
189
205
|
return chainReaction(ctx, promise, onFulfilled, onRejected, method);
|
|
190
206
|
};
|
|
207
|
+
/** NewPromiseCapability: a pending promise with the resolve/reject callables that settle it exactly once. */
|
|
208
|
+
const promiseCapability = (ctx) => Effect.gen(function* () {
|
|
209
|
+
const deferred = Deferred.makeUnsafe();
|
|
210
|
+
const promise = yield* ctx.pending.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(ctx, value, self)));
|
|
211
|
+
const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
212
|
+
const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
|
|
213
|
+
return { promise, resolve, reject, deferred };
|
|
214
|
+
});
|
|
191
215
|
const constructPromise = (ctx, executor) => {
|
|
192
216
|
if (!(executor instanceof Fn)) {
|
|
193
217
|
throw typeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).");
|
|
194
218
|
}
|
|
195
219
|
return Effect.gen(function* () {
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
199
|
-
const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
|
|
200
|
-
const executed = yield* Effect.exit(ctx.call(executor, undefined, [resolve, reject]));
|
|
220
|
+
const made = yield* promiseCapability(ctx);
|
|
221
|
+
const executed = yield* Effect.exit(ctx.call(executor, undefined, [made.resolve, made.reject]));
|
|
201
222
|
if (!Exit.isSuccess(executed)) {
|
|
202
223
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
203
224
|
return yield* Effect.failCause(executed.cause);
|
|
204
|
-
Deferred.doneUnsafe(deferred, Exit.fail(Cause.squash(executed.cause)));
|
|
225
|
+
Deferred.doneUnsafe(made.deferred, Exit.fail(Cause.squash(executed.cause)));
|
|
205
226
|
}
|
|
206
|
-
return promise;
|
|
227
|
+
return made.promise;
|
|
207
228
|
});
|
|
208
229
|
};
|
|
209
230
|
// Settle one reaction turn after the deciding member, after its existing reactions.
|
package/dist/stdlib/array.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
|
|
3
3
|
import { checkArrayLength, checkStringLength, MAX_ARRAY_LENGTH } from "../interpreter/limits.js";
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, get, hidden, Arr, GeneratorObj,
|
|
5
|
+
import { define, get, hidden, Arr, GeneratorObj, hostIterator, Obj, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { describeValue, rejectCircularInsertion } from "../interpreter/references.js";
|
|
7
7
|
import { applyCollectionCallback, invoke, preserveConsumerError } from "../interpreter/callback.js";
|
|
8
8
|
import { compareText } from "../tool-runtime.js";
|
|
@@ -13,7 +13,7 @@ const arrayLikeSource = (source) => {
|
|
|
13
13
|
checkArrayLength(normalized);
|
|
14
14
|
return { length: normalized, source };
|
|
15
15
|
}
|
|
16
|
-
throw invalidData(`Array.from expects an
|
|
16
|
+
throw invalidData(`Array.from expects an iterable or array-like value, received ${describeValue(source)}.`);
|
|
17
17
|
};
|
|
18
18
|
const arrayFrom = (ctx, args) => {
|
|
19
19
|
const source = args[0];
|
|
@@ -23,7 +23,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
23
23
|
const cursor = yield* ctx.iterate(source);
|
|
24
24
|
if (cursor === undefined) {
|
|
25
25
|
if (source instanceof GeneratorObj) {
|
|
26
|
-
throw typeError(
|
|
26
|
+
throw typeError(`Array.from expects a synchronous iterable or array-like value, received ${describeValue(source)}.`);
|
|
27
27
|
}
|
|
28
28
|
const arrayLike = arrayLikeSource(source);
|
|
29
29
|
const values = [];
|
|
@@ -39,7 +39,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
39
39
|
const step = yield* cursor.next;
|
|
40
40
|
if (step.done)
|
|
41
41
|
return new Arr(proto, values);
|
|
42
|
-
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
|
|
42
|
+
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor.close, apply([step.value, index])));
|
|
43
43
|
index += 1;
|
|
44
44
|
}
|
|
45
45
|
});
|
|
@@ -323,12 +323,12 @@ export const arrayGlobal = (ctx) => {
|
|
|
323
323
|
? Effect.succeed("")
|
|
324
324
|
: Effect.map(invoke(ctx, item, "toLocaleString", "Array.prototype.toLocaleString"), coerceToString)), (parts) => parts.join(",")),
|
|
325
325
|
],
|
|
326
|
-
["keys", 0, (thisValue) =>
|
|
327
|
-
["values", 0, (thisValue) =>
|
|
326
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").items.keys())],
|
|
327
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").items.values())],
|
|
328
328
|
[
|
|
329
329
|
"entries",
|
|
330
330
|
0,
|
|
331
|
-
(thisValue) =>
|
|
331
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
332
332
|
.items.entries()
|
|
333
333
|
.map(([index, item]) => wrap([index, item]))),
|
|
334
334
|
],
|
package/dist/stdlib/bytes.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
3
3
|
import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
4
4
|
import { IteratorSymbol, rangeError, syntaxError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, defineAccessor, get, hidden, Arr, Bytes,
|
|
5
|
+
import { define, defineAccessor, get, hidden, Arr, Bytes, hostIterator, Obj, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { describeValue } from "../interpreter/references.js";
|
|
7
7
|
/** The bytes a Uint8Array, array, or other iterable of numbers describes; the host array clamps each value. */
|
|
8
8
|
const collectBytes = (ctx, source, name) => {
|
|
@@ -151,12 +151,12 @@ export const uint8ArrayGlobal = (ctx) => {
|
|
|
151
151
|
["toString", 0, (thisValue) => self(thisValue, "toString").bytes.join(",")],
|
|
152
152
|
["toBase64", 0, (thisValue) => self(thisValue, "toBase64").bytes.toBase64()],
|
|
153
153
|
["toHex", 0, (thisValue) => self(thisValue, "toHex").bytes.toHex()],
|
|
154
|
-
["keys", 0, (thisValue) =>
|
|
155
|
-
["values", 0, (thisValue) =>
|
|
154
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").bytes.keys())],
|
|
155
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").bytes.values())],
|
|
156
156
|
[
|
|
157
157
|
"entries",
|
|
158
158
|
0,
|
|
159
|
-
(thisValue) =>
|
|
159
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
160
160
|
.bytes.entries()
|
|
161
161
|
.map(([index, byte]) => wrapAll([index, byte]))),
|
|
162
162
|
],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { invalidData, IteratorSymbol, typeError } from "../interpreter/model.js";
|
|
4
|
-
import { define, defineAccessor, get, getOwn, hidden, Arr, coerceToString,
|
|
4
|
+
import { define, defineAccessor, get, getOwn, hidden, Arr, coerceToString, hostCursor, hostIterator, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
|
|
5
5
|
import { describeValue, isOpaque } from "../interpreter/references.js";
|
|
6
6
|
import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/callback.js";
|
|
7
7
|
const coerceGroupByPropertyKey = (ctx, value) => {
|
|
@@ -33,7 +33,7 @@ export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, ar
|
|
|
33
33
|
if (step.done)
|
|
34
34
|
return result;
|
|
35
35
|
const item = step.value;
|
|
36
|
-
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
36
|
+
const key = yield* preserveConsumerError(cursor.close, apply([item, index]));
|
|
37
37
|
const group = result.map.get(key);
|
|
38
38
|
if (group === undefined)
|
|
39
39
|
result.map.set(key, new Arr(builtins.Array, [item]));
|
|
@@ -50,7 +50,7 @@ export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, ar
|
|
|
50
50
|
if (step.done)
|
|
51
51
|
return result;
|
|
52
52
|
const item = step.value;
|
|
53
|
-
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(ctx, value)));
|
|
53
|
+
const key = yield* preserveConsumerError(cursor.close, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(ctx, value)));
|
|
54
54
|
const group = getOwn(result, key);
|
|
55
55
|
if (group === undefined)
|
|
56
56
|
define(result, key, new Arr(builtins.Array, [item]));
|
|
@@ -67,13 +67,13 @@ const constructMap = (ctx, init, proto) => {
|
|
|
67
67
|
return Effect.gen(function* () {
|
|
68
68
|
const cursor = yield* ctx.iterate(init);
|
|
69
69
|
if (cursor === undefined) {
|
|
70
|
-
throw typeError(
|
|
70
|
+
throw typeError(`new Map(...) expects an iterable of [key, value] pairs, received ${describeValue(init)}.`);
|
|
71
71
|
}
|
|
72
72
|
while (true) {
|
|
73
73
|
const step = yield* cursor.next;
|
|
74
74
|
if (step.done)
|
|
75
75
|
return target;
|
|
76
|
-
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
76
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
77
77
|
if (!(step.value instanceof Obj)) {
|
|
78
78
|
throw typeError("new Map(...) expects [key, value] pairs as entry objects.");
|
|
79
79
|
}
|
|
@@ -89,7 +89,7 @@ const constructSet = (ctx, init, proto) => {
|
|
|
89
89
|
return Effect.gen(function* () {
|
|
90
90
|
const cursor = yield* ctx.iterate(init);
|
|
91
91
|
if (cursor === undefined) {
|
|
92
|
-
throw typeError(
|
|
92
|
+
throw typeError(`new Set(...) expects a synchronous iterable, received ${describeValue(init)}.`);
|
|
93
93
|
}
|
|
94
94
|
while (true) {
|
|
95
95
|
const step = yield* cursor.next;
|
|
@@ -156,9 +156,9 @@ export const mapGlobal = (ctx) => {
|
|
|
156
156
|
return undefined;
|
|
157
157
|
},
|
|
158
158
|
],
|
|
159
|
-
["keys", 0, (thisValue) =>
|
|
160
|
-
["values", 0, (thisValue) =>
|
|
161
|
-
["entries", 0, (thisValue) =>
|
|
159
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").map.keys())],
|
|
160
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").map.values())],
|
|
161
|
+
["entries", 0, (thisValue) => hostIterator(builtins, self(thisValue, "entries").iterator(builtins))],
|
|
162
162
|
[
|
|
163
163
|
"forEach",
|
|
164
164
|
1,
|
|
@@ -207,12 +207,16 @@ const loadSetRecord = (ctx, source, name) => {
|
|
|
207
207
|
return {
|
|
208
208
|
size: Math.max(Math.trunc(size), 0),
|
|
209
209
|
has: (item) => Effect.map(ctx.call(has, source, [item]), Boolean),
|
|
210
|
-
keys: () => Effect.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
keys: () => Effect.gen(function* () {
|
|
211
|
+
const result = yield* ctx.call(keys, source, []);
|
|
212
|
+
const cursor = result instanceof Arr ? hostCursor(result.items.values()) : ctx.iterateDirect(result);
|
|
213
|
+
const items = [];
|
|
214
|
+
while (true) {
|
|
215
|
+
const step = yield* cursor.next;
|
|
216
|
+
if (step.done)
|
|
217
|
+
return items;
|
|
218
|
+
items.push(step.value);
|
|
219
|
+
}
|
|
216
220
|
}),
|
|
217
221
|
};
|
|
218
222
|
});
|
|
@@ -336,12 +340,12 @@ export const setGlobal = (ctx) => {
|
|
|
336
340
|
return undefined;
|
|
337
341
|
},
|
|
338
342
|
],
|
|
339
|
-
["keys", 0, (thisValue) =>
|
|
340
|
-
["values", 0, (thisValue) =>
|
|
343
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").set.values())],
|
|
344
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").set.values())],
|
|
341
345
|
[
|
|
342
346
|
"entries",
|
|
343
347
|
0,
|
|
344
|
-
(thisValue) =>
|
|
348
|
+
(thisValue) => hostIterator(builtins, self(thisValue, "entries")
|
|
345
349
|
.set.values()
|
|
346
350
|
.map((item) => wrap([item, item]))),
|
|
347
351
|
],
|
package/dist/stdlib/headers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { IteratorSymbol, typeError } from "../interpreter/model.js";
|
|
4
|
-
import { define, entries, get, hidden, Arr, HeadersObj,
|
|
4
|
+
import { define, entries, get, hidden, Arr, HeadersObj, hostIterator, Obj, coerceToString, isRuntimeReference, } from "../interpreter/objects.js";
|
|
5
5
|
import { applyCollectionCallback } from "../interpreter/callback.js";
|
|
6
6
|
import { readPairs } from "./url.js";
|
|
7
7
|
// The host validates header names and values and throws its own TypeError; the program gets one of its own.
|
|
@@ -92,18 +92,9 @@ export const headersGlobal = (ctx) => {
|
|
|
92
92
|
return undefined;
|
|
93
93
|
},
|
|
94
94
|
],
|
|
95
|
-
|
|
96
|
-
[
|
|
97
|
-
|
|
98
|
-
0,
|
|
99
|
-
(thisValue) => new IteratorObj(builtins.Iterator, Iterator.from(self(thisValue, "keys").headers.keys())),
|
|
100
|
-
],
|
|
101
|
-
[
|
|
102
|
-
"values",
|
|
103
|
-
0,
|
|
104
|
-
(thisValue) => new IteratorObj(builtins.Iterator, Iterator.from(self(thisValue, "values").headers.values())),
|
|
105
|
-
],
|
|
106
|
-
["entries", 0, (thisValue) => new IteratorObj(builtins.Iterator, self(thisValue, "entries").iterator(builtins))],
|
|
95
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").headers.keys())],
|
|
96
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").headers.values())],
|
|
97
|
+
["entries", 0, (thisValue) => hostIterator(builtins, self(thisValue, "entries").iterator(builtins))],
|
|
107
98
|
[
|
|
108
99
|
"forEach",
|
|
109
100
|
1,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Interpreter } from "../interpreter/interpreter.js";
|
|
2
|
-
export declare const iteratorGlobals: <R>(ctx: Interpreter<R>) =>
|
|
2
|
+
export declare const iteratorGlobals: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
|
package/dist/stdlib/iterator.js
CHANGED
|
@@ -1,17 +1,305 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Cause, Effect, Exit } from "effect";
|
|
2
|
+
import { applyCollectionCallback } from "../interpreter/callback.js";
|
|
3
|
+
import { rangeError, typeError } from "../interpreter/model.js";
|
|
4
|
+
import { constructor, fn, methods, receiver, requiresNew } from "../interpreter/native.js";
|
|
5
|
+
import { Arr, coerceToNumber, define, hasPrototype, hidden, IteratorObj, Obj, record, } from "../interpreter/objects.js";
|
|
6
|
+
import { describeValue } from "../interpreter/references.js";
|
|
7
|
+
const finished = { done: true, value: undefined };
|
|
8
|
+
// Every built-in iterator and helper shares the Iterator prototype; JS gives each collection its own, which is only
|
|
4
9
|
// observable through getPrototypeOf.
|
|
5
10
|
export const iteratorGlobals = (ctx) => {
|
|
6
11
|
const builtins = ctx.builtins;
|
|
7
|
-
|
|
12
|
+
const proto = builtins.Iterator;
|
|
13
|
+
const method = (name) => `Iterator.prototype.${name}`;
|
|
14
|
+
// A step that runs program code: when it throws, close the source first, as IteratorClose does.
|
|
15
|
+
const guarded = (source, body) => Effect.flatMap(Effect.exit(body), (exit) => {
|
|
16
|
+
if (Exit.isSuccess(exit))
|
|
17
|
+
return Effect.succeed(exit.value);
|
|
18
|
+
if (Cause.hasInterruptsOnly(exit.cause))
|
|
19
|
+
return Effect.failCause(exit.cause);
|
|
20
|
+
return Effect.andThen(Effect.exit(source.close), Effect.failCause(exit.cause));
|
|
21
|
+
});
|
|
22
|
+
// A lazy helper: `pull` advances it once. Once it reports done, throws, or is closed, it stays done. A callback
|
|
23
|
+
// that re-enters its own helper is a TypeError, as for a running generator.
|
|
24
|
+
const helper = (source, pull, close = source.close) => {
|
|
25
|
+
let done = false;
|
|
26
|
+
let running = false;
|
|
27
|
+
const enter = () => {
|
|
28
|
+
if (running)
|
|
29
|
+
throw typeError("Iterator helper is already running.");
|
|
30
|
+
running = true;
|
|
31
|
+
};
|
|
32
|
+
return new IteratorObj(builtins.IteratorHelper, {
|
|
33
|
+
next: Effect.suspend(() => {
|
|
34
|
+
if (done)
|
|
35
|
+
return Effect.succeed(finished);
|
|
36
|
+
enter();
|
|
37
|
+
return Effect.flatMap(Effect.exit(pull), (exit) => {
|
|
38
|
+
running = false;
|
|
39
|
+
done = Exit.isSuccess(exit) ? exit.value.done : true;
|
|
40
|
+
return exit;
|
|
41
|
+
});
|
|
42
|
+
}),
|
|
43
|
+
close: Effect.suspend(() => {
|
|
44
|
+
if (done)
|
|
45
|
+
return Effect.void;
|
|
46
|
+
enter();
|
|
47
|
+
done = true;
|
|
48
|
+
return Effect.ensuring(close, Effect.sync(() => {
|
|
49
|
+
running = false;
|
|
50
|
+
}));
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
// GetIteratorFlattenable: an iterable by `[Symbol.iterator]`, otherwise the object itself as an iterator.
|
|
55
|
+
const flattenable = (value, name, strings) => Effect.gen(function* () {
|
|
56
|
+
if (typeof value === "string" ? !strings : !(value instanceof Obj)) {
|
|
57
|
+
throw typeError(`${name} expects an iterable or iterator, received ${describeValue(value)}.`);
|
|
58
|
+
}
|
|
59
|
+
return (yield* ctx.iterate(value)) ?? ctx.iterateDirect(value);
|
|
60
|
+
});
|
|
61
|
+
const limit = (value, name) => {
|
|
62
|
+
const count = Math.trunc(coerceToNumber(value));
|
|
63
|
+
if (Number.isNaN(count) || count < 0) {
|
|
64
|
+
throw rangeError(`${method(name)} expects a non-negative count, received ${count}.`);
|
|
65
|
+
}
|
|
66
|
+
return count;
|
|
67
|
+
};
|
|
68
|
+
methods(builtins, proto, [
|
|
8
69
|
[
|
|
9
70
|
"next",
|
|
10
71
|
0,
|
|
72
|
+
(thisValue) => Effect.map(receiver(IteratorObj, thisValue, method("next")).cursor.next, (step) => record(builtins.Object, { value: step.value, done: step.done })),
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
"map",
|
|
76
|
+
1,
|
|
77
|
+
(thisValue, args) => {
|
|
78
|
+
const source = ctx.iterateDirect(thisValue);
|
|
79
|
+
const apply = applyCollectionCallback(ctx, args[0], method("map"));
|
|
80
|
+
let counter = 0;
|
|
81
|
+
return helper(source, Effect.gen(function* () {
|
|
82
|
+
const step = yield* source.next;
|
|
83
|
+
if (step.done)
|
|
84
|
+
return finished;
|
|
85
|
+
return { done: false, value: yield* guarded(source, apply([step.value, counter++])) };
|
|
86
|
+
}));
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
"filter",
|
|
91
|
+
1,
|
|
92
|
+
(thisValue, args) => {
|
|
93
|
+
const source = ctx.iterateDirect(thisValue);
|
|
94
|
+
const apply = applyCollectionCallback(ctx, args[0], method("filter"));
|
|
95
|
+
let counter = 0;
|
|
96
|
+
return helper(source, Effect.gen(function* () {
|
|
97
|
+
while (true) {
|
|
98
|
+
const step = yield* source.next;
|
|
99
|
+
if (step.done)
|
|
100
|
+
return finished;
|
|
101
|
+
if (yield* guarded(source, apply([step.value, counter++])))
|
|
102
|
+
return step;
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"take",
|
|
109
|
+
1,
|
|
110
|
+
(thisValue, args) => {
|
|
111
|
+
const source = ctx.iterateDirect(thisValue);
|
|
112
|
+
let remaining = limit(args[0], "take");
|
|
113
|
+
return helper(source, Effect.gen(function* () {
|
|
114
|
+
if (remaining === 0) {
|
|
115
|
+
yield* source.close;
|
|
116
|
+
return finished;
|
|
117
|
+
}
|
|
118
|
+
remaining -= 1;
|
|
119
|
+
return yield* source.next;
|
|
120
|
+
}));
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"drop",
|
|
125
|
+
1,
|
|
126
|
+
(thisValue, args) => {
|
|
127
|
+
const source = ctx.iterateDirect(thisValue);
|
|
128
|
+
let remaining = limit(args[0], "drop");
|
|
129
|
+
return helper(source, Effect.gen(function* () {
|
|
130
|
+
while (remaining > 0) {
|
|
131
|
+
remaining -= 1;
|
|
132
|
+
const step = yield* source.next;
|
|
133
|
+
if (step.done)
|
|
134
|
+
return finished;
|
|
135
|
+
}
|
|
136
|
+
return yield* source.next;
|
|
137
|
+
}));
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
[
|
|
141
|
+
"flatMap",
|
|
142
|
+
1,
|
|
143
|
+
(thisValue, args) => {
|
|
144
|
+
const source = ctx.iterateDirect(thisValue);
|
|
145
|
+
const apply = applyCollectionCallback(ctx, args[0], method("flatMap"));
|
|
146
|
+
let counter = 0;
|
|
147
|
+
let inner;
|
|
148
|
+
return helper(source, Effect.gen(function* () {
|
|
149
|
+
while (true) {
|
|
150
|
+
if (inner !== undefined) {
|
|
151
|
+
const step = yield* guarded(source, inner.next);
|
|
152
|
+
if (!step.done)
|
|
153
|
+
return step;
|
|
154
|
+
inner = undefined;
|
|
155
|
+
}
|
|
156
|
+
const step = yield* source.next;
|
|
157
|
+
if (step.done)
|
|
158
|
+
return finished;
|
|
159
|
+
inner = yield* guarded(source, Effect.flatMap(apply([step.value, counter++]), (mapped) => flattenable(mapped, method("flatMap"), false)));
|
|
160
|
+
}
|
|
161
|
+
}), Effect.suspend(() => (inner === undefined ? source.close : Effect.andThen(inner.close, source.close))));
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
"reduce",
|
|
166
|
+
1,
|
|
167
|
+
(thisValue, args) => {
|
|
168
|
+
const source = ctx.iterateDirect(thisValue);
|
|
169
|
+
const apply = applyCollectionCallback(ctx, args[0], method("reduce"));
|
|
170
|
+
return Effect.gen(function* () {
|
|
171
|
+
let counter = 0;
|
|
172
|
+
let accumulator = args[1];
|
|
173
|
+
if (args.length < 2) {
|
|
174
|
+
const first = yield* source.next;
|
|
175
|
+
if (first.done)
|
|
176
|
+
throw typeError("Iterator.prototype.reduce of an empty iterator with no initial value.");
|
|
177
|
+
accumulator = first.value;
|
|
178
|
+
counter = 1;
|
|
179
|
+
}
|
|
180
|
+
while (true) {
|
|
181
|
+
const step = yield* source.next;
|
|
182
|
+
if (step.done)
|
|
183
|
+
return accumulator;
|
|
184
|
+
accumulator = yield* guarded(source, apply([accumulator, step.value, counter++]));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
"toArray",
|
|
191
|
+
0,
|
|
11
192
|
(thisValue) => {
|
|
12
|
-
const
|
|
13
|
-
return
|
|
193
|
+
const source = ctx.iterateDirect(thisValue);
|
|
194
|
+
return Effect.gen(function* () {
|
|
195
|
+
const items = [];
|
|
196
|
+
while (true) {
|
|
197
|
+
const step = yield* source.next;
|
|
198
|
+
if (step.done)
|
|
199
|
+
return new Arr(builtins.Array, items);
|
|
200
|
+
items.push(step.value);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
[
|
|
206
|
+
"forEach",
|
|
207
|
+
1,
|
|
208
|
+
(thisValue, args) => {
|
|
209
|
+
const source = ctx.iterateDirect(thisValue);
|
|
210
|
+
const apply = applyCollectionCallback(ctx, args[0], method("forEach"));
|
|
211
|
+
return Effect.gen(function* () {
|
|
212
|
+
let counter = 0;
|
|
213
|
+
while (true) {
|
|
214
|
+
const step = yield* source.next;
|
|
215
|
+
if (step.done)
|
|
216
|
+
return undefined;
|
|
217
|
+
yield* guarded(source, apply([step.value, counter++]));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
"some",
|
|
224
|
+
1,
|
|
225
|
+
(thisValue, args) => {
|
|
226
|
+
const source = ctx.iterateDirect(thisValue);
|
|
227
|
+
const apply = applyCollectionCallback(ctx, args[0], method("some"));
|
|
228
|
+
return Effect.gen(function* () {
|
|
229
|
+
let counter = 0;
|
|
230
|
+
while (true) {
|
|
231
|
+
const step = yield* source.next;
|
|
232
|
+
if (step.done)
|
|
233
|
+
return false;
|
|
234
|
+
if (yield* guarded(source, apply([step.value, counter++]))) {
|
|
235
|
+
yield* source.close;
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
[
|
|
243
|
+
"every",
|
|
244
|
+
1,
|
|
245
|
+
(thisValue, args) => {
|
|
246
|
+
const source = ctx.iterateDirect(thisValue);
|
|
247
|
+
const apply = applyCollectionCallback(ctx, args[0], method("every"));
|
|
248
|
+
return Effect.gen(function* () {
|
|
249
|
+
let counter = 0;
|
|
250
|
+
while (true) {
|
|
251
|
+
const step = yield* source.next;
|
|
252
|
+
if (step.done)
|
|
253
|
+
return true;
|
|
254
|
+
if (!(yield* guarded(source, apply([step.value, counter++])))) {
|
|
255
|
+
yield* source.close;
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
[
|
|
263
|
+
"find",
|
|
264
|
+
1,
|
|
265
|
+
(thisValue, args) => {
|
|
266
|
+
const source = ctx.iterateDirect(thisValue);
|
|
267
|
+
const apply = applyCollectionCallback(ctx, args[0], method("find"));
|
|
268
|
+
return Effect.gen(function* () {
|
|
269
|
+
let counter = 0;
|
|
270
|
+
while (true) {
|
|
271
|
+
const step = yield* source.next;
|
|
272
|
+
if (step.done)
|
|
273
|
+
return undefined;
|
|
274
|
+
if (yield* guarded(source, apply([step.value, counter++]))) {
|
|
275
|
+
yield* source.close;
|
|
276
|
+
return step.value;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
14
280
|
},
|
|
15
281
|
],
|
|
16
282
|
]);
|
|
283
|
+
// Helpers and `Iterator.from` wrappers can be closed; collection iterators, as in JS, cannot.
|
|
284
|
+
methods(builtins, builtins.IteratorHelper, [
|
|
285
|
+
[
|
|
286
|
+
"return",
|
|
287
|
+
0,
|
|
288
|
+
(thisValue) => Effect.map(receiver(IteratorObj, thisValue, "Iterator.prototype.return").cursor.close, () => record(builtins.Object, { value: undefined, done: true })),
|
|
289
|
+
],
|
|
290
|
+
]);
|
|
291
|
+
const iterator = constructor(builtins, proto, {
|
|
292
|
+
name: "Iterator",
|
|
293
|
+
length: 0,
|
|
294
|
+
call: requiresNew("Iterator"),
|
|
295
|
+
construct: () => Effect.sync(() => {
|
|
296
|
+
throw typeError("Iterator is abstract; use Iterator.from(...) or a built-in iterator.");
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
define(iterator, "from", fn(builtins, "from", 1, (_, args) => Effect.gen(function* () {
|
|
300
|
+
if (args[0] instanceof Obj && hasPrototype(args[0], proto))
|
|
301
|
+
return args[0];
|
|
302
|
+
return new IteratorObj(builtins.IteratorHelper, yield* flattenable(args[0], "Iterator.from", true));
|
|
303
|
+
})), hidden);
|
|
304
|
+
return iterator;
|
|
17
305
|
};
|
package/dist/stdlib/math.js
CHANGED
|
@@ -91,7 +91,7 @@ export const mathGlobal = (ctx) => {
|
|
|
91
91
|
const step = yield* cursor.next;
|
|
92
92
|
if (step.done)
|
|
93
93
|
return Math.sumPrecise(numbers);
|
|
94
|
-
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
94
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
95
95
|
if (typeof step.value !== "number") {
|
|
96
96
|
throw typeError("Math.sumPrecise expects an iterable of numbers.");
|
|
97
97
|
}
|
package/dist/stdlib/object.js
CHANGED
|
@@ -56,7 +56,7 @@ const objectFromEntries = (ctx, source) => {
|
|
|
56
56
|
const step = yield* cursor.next;
|
|
57
57
|
if (step.done)
|
|
58
58
|
return out;
|
|
59
|
-
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
59
|
+
yield* preserveConsumerError(cursor.close, Effect.sync(() => {
|
|
60
60
|
if (!(step.value instanceof Obj) || containsOpaqueReference(step.value)) {
|
|
61
61
|
throw typeError("Object.fromEntries expects [key, value] entry objects.");
|
|
62
62
|
}
|
package/dist/stdlib/string.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constructor, fn, methods } from "../interpreter/native.js";
|
|
3
3
|
import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, hidden, Arr,
|
|
5
|
+
import { define, hidden, Arr, hostIterator, RegExpObj, record, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { containsOpaqueReference, typeofValue } from "../interpreter/references.js";
|
|
7
7
|
import { applyCollectionCallback, isSupportedCallback } from "../interpreter/callback.js";
|
|
8
8
|
import { matchToValue, toHostRegex } from "./regexp.js";
|
|
@@ -229,6 +229,6 @@ export const stringGlobal = (ctx) => {
|
|
|
229
229
|
return joined;
|
|
230
230
|
}),
|
|
231
231
|
]);
|
|
232
|
-
define(builtins.String, IteratorSymbol, fn(builtins, "[Symbol.iterator]", 0, (thisValue) =>
|
|
232
|
+
define(builtins.String, IteratorSymbol, fn(builtins, "[Symbol.iterator]", 0, (thisValue) => hostIterator(builtins, self(thisValue, "[Symbol.iterator]")[Symbol.iterator]())), hidden);
|
|
233
233
|
return string;
|
|
234
234
|
};
|
package/dist/stdlib/url.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
|
|
3
3
|
import { IteratorSymbol, PendingThrow, typeError, uriError } from "../interpreter/model.js";
|
|
4
|
-
import { define, defineAccessor, entries, get, hidden, Arr,
|
|
4
|
+
import { define, defineAccessor, entries, get, hidden, Arr, hostIterator, Obj, URLObj, URLSearchParamsObj, coerceToString, isRuntimeReference, } from "../interpreter/objects.js";
|
|
5
5
|
import { applyCollectionCallback, preserveConsumerError } from "../interpreter/callback.js";
|
|
6
6
|
const urlProperties = [
|
|
7
7
|
"href",
|
|
@@ -105,7 +105,7 @@ const readPair = (ctx, value, label) => Effect.gen(function* () {
|
|
|
105
105
|
const step = yield* cursor.next;
|
|
106
106
|
if (step.done)
|
|
107
107
|
return items;
|
|
108
|
-
items.push(yield* preserveConsumerError(cursor, Effect.sync(() => coerceToString(step.value))));
|
|
108
|
+
items.push(yield* preserveConsumerError(cursor.close, Effect.sync(() => coerceToString(step.value))));
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
111
|
/**
|
|
@@ -124,7 +124,7 @@ export const readPairs = (ctx, init, label) => Effect.gen(function* () {
|
|
|
124
124
|
throw typeError(`${label} expects iterable [name, value] pairs.`);
|
|
125
125
|
return pairs;
|
|
126
126
|
}
|
|
127
|
-
pairs.push(yield* preserveConsumerError(cursor, readPair(ctx, step.value, label)));
|
|
127
|
+
pairs.push(yield* preserveConsumerError(cursor.close, readPair(ctx, step.value, label)));
|
|
128
128
|
}
|
|
129
129
|
});
|
|
130
130
|
const constructURLSearchParams = (ctx, init, proto) => {
|
|
@@ -233,9 +233,9 @@ export const urlSearchParamsGlobal = (ctx) => {
|
|
|
233
233
|
return undefined;
|
|
234
234
|
},
|
|
235
235
|
],
|
|
236
|
-
["keys", 0, (thisValue) =>
|
|
237
|
-
["values", 0, (thisValue) =>
|
|
238
|
-
["entries", 0, (thisValue) =>
|
|
236
|
+
["keys", 0, (thisValue) => hostIterator(builtins, self(thisValue, "keys").params.keys())],
|
|
237
|
+
["values", 0, (thisValue) => hostIterator(builtins, self(thisValue, "values").params.values())],
|
|
238
|
+
["entries", 0, (thisValue) => hostIterator(builtins, self(thisValue, "entries").iterator(builtins))],
|
|
239
239
|
["toString", 0, (thisValue) => self(thisValue, "toString").params.toString()],
|
|
240
240
|
[
|
|
241
241
|
"forEach",
|
package/dist/tool-runtime.js
CHANGED
|
@@ -90,7 +90,7 @@ const describeTool = (visible) => {
|
|
|
90
90
|
// Joining the final fragments avoids retaining the rendering's intermediate string ropes in JSC.
|
|
91
91
|
return (signature ??= [
|
|
92
92
|
toolExpression(visible.path),
|
|
93
|
-
isEmptyInput(visible.tool) ? "()" : `(
|
|
93
|
+
isEmptyInput(visible.tool) ? "()" : `(${inputTypeScript(visible.tool, true)})`,
|
|
94
94
|
`: Promise<${outputTypeScript(visible.tool, true)}>`,
|
|
95
95
|
].join(""));
|
|
96
96
|
},
|
|
@@ -118,10 +118,16 @@ const makeSearchTool = (searchIndex) => ({
|
|
|
118
118
|
const request = input;
|
|
119
119
|
const query = request.query ?? "";
|
|
120
120
|
const offset = request.offset ?? 0;
|
|
121
|
-
|
|
121
|
+
let ns = request.namespace;
|
|
122
|
+
if (ns !== undefined && !searchIndex.some((entry) => entry.description.path.startsWith("tools."))) {
|
|
123
|
+
if (ns === "tools")
|
|
124
|
+
ns = undefined;
|
|
125
|
+
else if (ns.startsWith("tools."))
|
|
126
|
+
ns = ns.slice("tools.".length);
|
|
127
|
+
}
|
|
128
|
+
const scoped = ns === undefined
|
|
122
129
|
? searchIndex
|
|
123
|
-
: searchIndex.filter((entry) => entry.description.path ===
|
|
124
|
-
entry.description.path.startsWith(`${request.namespace}.`));
|
|
130
|
+
: searchIndex.filter((entry) => entry.description.path === ns || entry.description.path.startsWith(`${ns}.`));
|
|
125
131
|
const trimmed = query.trim();
|
|
126
132
|
const pathQuery = trimmed.startsWith("tools.") ? trimmed.slice("tools.".length) : trimmed;
|
|
127
133
|
const exact = pathQuery === ""
|
|
@@ -160,7 +166,7 @@ const makeSearchTool = (searchIndex) => ({
|
|
|
160
166
|
/** Exact callable signature of the built-in `search` function, for host-owned instructions. */
|
|
161
167
|
export const searchSignature = (() => {
|
|
162
168
|
const tool = makeSearchTool([]);
|
|
163
|
-
return `search(
|
|
169
|
+
return `search(${inputTypeScript(tool, true)}): ${outputTypeScript(tool, true)}`;
|
|
164
170
|
})();
|
|
165
171
|
const toSearchEntry = (visible) => ({
|
|
166
172
|
description: describeTool(visible),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode/codemode",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-19959",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|