@opencode/codemode 0.0.0-dev-19530 → 2.0.0
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 -6
- package/dist/data.js +44 -47
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +3 -5
- package/dist/interpreter/errors.js +22 -51
- package/dist/interpreter/execute.js +3 -5
- package/dist/interpreter/globals.js +47 -69
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +4 -0
- package/dist/interpreter/methods.js +837 -0
- package/dist/interpreter/model.d.ts +36 -13
- package/dist/interpreter/model.js +45 -15
- package/dist/interpreter/objects.d.ts +13 -106
- package/dist/interpreter/objects.js +65 -192
- package/dist/interpreter/promises.d.ts +13 -12
- package/dist/interpreter/promises.js +54 -59
- package/dist/interpreter/references.d.ts +0 -1
- package/dist/interpreter/references.js +33 -20
- package/dist/interpreter/runner.d.ts +11 -15
- package/dist/interpreter/runner.js +21 -21
- package/dist/interpreter/runtime.d.ts +3 -3
- package/dist/interpreter/runtime.js +327 -165
- package/dist/interpreter/scope.js +6 -6
- package/dist/stdlib/array.d.ts +2 -4
- package/dist/stdlib/array.js +32 -424
- package/dist/stdlib/collections.d.ts +7 -3
- package/dist/stdlib/collections.js +119 -291
- package/dist/stdlib/console.d.ts +2 -3
- package/dist/stdlib/console.js +30 -35
- package/dist/stdlib/date.d.ts +7 -1
- package/dist/stdlib/date.js +188 -93
- package/dist/stdlib/json.d.ts +2 -2
- package/dist/stdlib/json.js +27 -27
- package/dist/stdlib/math.d.ts +2 -2
- package/dist/stdlib/math.js +76 -96
- package/dist/stdlib/number.d.ts +4 -3
- package/dist/stdlib/number.js +60 -95
- package/dist/stdlib/object.d.ts +4 -4
- package/dist/stdlib/object.js +54 -128
- package/dist/stdlib/regexp.d.ts +8 -6
- package/dist/stdlib/regexp.js +68 -76
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +50 -213
- package/dist/stdlib/url.d.ts +13 -5
- package/dist/stdlib/url.js +102 -202
- package/dist/stdlib/value.d.ts +9 -5
- package/dist/stdlib/value.js +38 -16
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +10 -12
- package/dist/tool-runtime.d.ts +1 -2
- package/dist/tool-runtime.js +2 -2
- package/dist/values.d.ts +37 -0
- package/dist/values.js +56 -0
- package/package.json +1 -1
- package/dist/interpreter/generators.d.ts +0 -4
- package/dist/interpreter/generators.js +0 -25
- package/dist/interpreter/intrinsics.d.ts +0 -13
- package/dist/interpreter/intrinsics.js +0 -82
- package/dist/interpreter/native.d.ts +0 -19
- package/dist/interpreter/native.js +0 -40
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { Effect, Exit, Scope } from "effect";
|
|
2
2
|
import type { Diagnostic } from "../codemode.js";
|
|
3
|
-
import { type AstNode, InterpreterRuntimeError } from "./model.js";
|
|
4
|
-
import {
|
|
3
|
+
import { type AstNode, InterpreterRuntimeError, PromiseInstanceMethodReference } from "./model.js";
|
|
4
|
+
import { HostFunction } from "./host.js";
|
|
5
|
+
import { Values } from "../values.js";
|
|
5
6
|
import { type Runner } from "./runner.js";
|
|
6
7
|
export declare class PromiseRuntime<R> {
|
|
7
8
|
private readonly scope;
|
|
8
|
-
private readonly proto;
|
|
9
9
|
private readonly active;
|
|
10
10
|
private readonly ids;
|
|
11
11
|
private readonly observed;
|
|
12
12
|
private readonly failures;
|
|
13
13
|
private nextID;
|
|
14
|
-
constructor(scope: Scope.Scope
|
|
14
|
+
constructor(scope: Scope.Scope);
|
|
15
15
|
createWithSelf(body: (self: {
|
|
16
|
-
promise?:
|
|
17
|
-
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<
|
|
18
|
-
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<
|
|
19
|
-
markObserved(promise:
|
|
20
|
-
await(promise:
|
|
16
|
+
promise?: Values.Promise;
|
|
17
|
+
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
18
|
+
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
19
|
+
markObserved(promise: Values.Promise): void;
|
|
20
|
+
await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
21
21
|
fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
|
|
22
22
|
diagnostics(): Array<Diagnostic>;
|
|
23
23
|
interrupt(): Effect.Effect<Array<Diagnostic>>;
|
|
24
24
|
}
|
|
25
25
|
export declare const selfResolutionError: (node?: AstNode) => InterpreterRuntimeError;
|
|
26
26
|
export declare const resolvePromiseValue: <R>(runner: Runner<R>, value: unknown, node: AstNode, own?: {
|
|
27
|
-
promise?:
|
|
27
|
+
promise?: Values.Promise;
|
|
28
28
|
}) => Effect.Effect<unknown, unknown, R>;
|
|
29
|
-
export declare const resolvePromise: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<
|
|
30
|
-
export declare const
|
|
29
|
+
export declare const resolvePromise: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
|
|
30
|
+
export declare const invokePromiseInstanceMethod: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, ref: PromiseInstanceMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
|
|
31
|
+
export declare const promiseGlobal: <R>(runner: Runner<R>, promises: PromiseRuntime<R>) => HostFunction<R>;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
|
|
2
|
-
import { InterpreterRuntimeError, ProgramThrow } from "./model.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { caughtErrorValue,
|
|
2
|
+
import { InterpreterRuntimeError, ProgramThrow, PromiseInstanceMethodReference } from "./model.js";
|
|
3
|
+
import { get, ProgramArray, ProgramFunction, ProgramObject, record } from "./objects.js";
|
|
4
|
+
import { HostFunction, requiresNew, sync } from "./host.js";
|
|
5
|
+
import { caughtErrorValue, normalizeError } from "./errors.js";
|
|
6
6
|
import { typeofValue } from "./references.js";
|
|
7
|
+
import { createAggregateErrorValue } from "../stdlib/value.js";
|
|
8
|
+
import { Values } from "../values.js";
|
|
7
9
|
import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
|
|
8
10
|
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
9
|
-
const capability = (
|
|
11
|
+
const capability = (name, settle) => sync(name, (args) => {
|
|
10
12
|
settle(args[0]);
|
|
11
13
|
return undefined;
|
|
12
14
|
});
|
|
13
15
|
// Observation only controls rejection reporting; program completion interrupts all promise work.
|
|
14
16
|
export class PromiseRuntime {
|
|
15
17
|
scope;
|
|
16
|
-
proto;
|
|
17
18
|
active = new Set();
|
|
18
19
|
ids = new WeakMap();
|
|
19
20
|
observed = new WeakSet();
|
|
20
21
|
failures = new Map();
|
|
21
22
|
nextID = 0;
|
|
22
|
-
constructor(scope
|
|
23
|
+
constructor(scope) {
|
|
23
24
|
this.scope = scope;
|
|
24
|
-
this.proto = proto;
|
|
25
25
|
}
|
|
26
26
|
// Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
|
|
27
27
|
createWithSelf(body) {
|
|
@@ -36,7 +36,7 @@ export class PromiseRuntime {
|
|
|
36
36
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
37
37
|
const id = this.nextID++;
|
|
38
38
|
return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
|
|
39
|
-
const promise = new
|
|
39
|
+
const promise = new Values.Promise(fiber);
|
|
40
40
|
this.active.add(promise);
|
|
41
41
|
this.ids.set(promise, id);
|
|
42
42
|
fiber.addObserver((exit) => {
|
|
@@ -83,11 +83,11 @@ export class PromiseRuntime {
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaining cycle detected: a promise cannot resolve with itself.", node);
|
|
86
|
+
export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaining cycle detected: a promise cannot resolve with itself.", node).as("TypeError");
|
|
87
87
|
export const resolvePromiseValue = (runner, value, node, own) => {
|
|
88
88
|
if (own?.promise !== undefined && value === own.promise)
|
|
89
89
|
return Effect.fail(selfResolutionError(node));
|
|
90
|
-
if (value instanceof
|
|
90
|
+
if (value instanceof Values.Promise)
|
|
91
91
|
return runner.settlePromise(value);
|
|
92
92
|
if (!(value instanceof ProgramObject))
|
|
93
93
|
return Effect.succeed(value);
|
|
@@ -98,9 +98,9 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
98
98
|
// Promise resolution invokes a thenable's method in a later job.
|
|
99
99
|
yield* Effect.yieldNow;
|
|
100
100
|
const deferred = Deferred.makeUnsafe();
|
|
101
|
-
const resolve = capability(
|
|
102
|
-
const reject = capability(
|
|
103
|
-
const executed = yield* Effect.exit(runner.invokeCallable(then,
|
|
101
|
+
const resolve = capability("resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
|
|
102
|
+
const reject = capability("reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason))));
|
|
103
|
+
const executed = yield* Effect.exit(runner.invokeCallable(then, [resolve, reject], node));
|
|
104
104
|
if (!Exit.isSuccess(executed)) {
|
|
105
105
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
106
106
|
return yield* Effect.failCause(executed.cause);
|
|
@@ -110,7 +110,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
110
110
|
});
|
|
111
111
|
};
|
|
112
112
|
export const resolvePromise = (runner, promises, value, node) => {
|
|
113
|
-
if (value instanceof
|
|
113
|
+
if (value instanceof Values.Promise)
|
|
114
114
|
return Effect.succeed(value);
|
|
115
115
|
return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
|
|
116
116
|
};
|
|
@@ -125,7 +125,7 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
125
125
|
return promises.create(Effect.gen(function* () {
|
|
126
126
|
const cursor = yield* runner.syncIterator(args[0], node);
|
|
127
127
|
if (cursor === undefined) {
|
|
128
|
-
throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node);
|
|
128
|
+
throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node).as("TypeError");
|
|
129
129
|
}
|
|
130
130
|
const items = [];
|
|
131
131
|
while (true) {
|
|
@@ -137,25 +137,22 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
137
137
|
items.push(item);
|
|
138
138
|
}
|
|
139
139
|
if (name === "all") {
|
|
140
|
-
return new ProgramArray(
|
|
140
|
+
return new ProgramArray(yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
|
|
141
141
|
}
|
|
142
142
|
if (name === "allSettled") {
|
|
143
143
|
const outcomes = [];
|
|
144
144
|
for (const item of items) {
|
|
145
145
|
const exit = yield* promises.await(item);
|
|
146
146
|
if (Exit.isSuccess(exit)) {
|
|
147
|
-
outcomes.push(record(
|
|
147
|
+
outcomes.push(record({ status: "fulfilled", value: exit.value }));
|
|
148
148
|
continue;
|
|
149
149
|
}
|
|
150
150
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
151
151
|
return yield* Effect.failCause(exit.cause);
|
|
152
|
-
outcomes.push(record(
|
|
153
|
-
status: "rejected",
|
|
154
|
-
reason: caughtErrorValue(runner, Cause.squash(exit.cause)),
|
|
155
|
-
}));
|
|
152
|
+
outcomes.push(record({ status: "rejected", reason: caughtErrorValue(Cause.squash(exit.cause)) }));
|
|
156
153
|
}
|
|
157
154
|
yield* Effect.yieldNow;
|
|
158
|
-
return new ProgramArray(
|
|
155
|
+
return new ProgramArray(outcomes);
|
|
159
156
|
}
|
|
160
157
|
if (name === "race") {
|
|
161
158
|
if (items.length === 0) {
|
|
@@ -168,32 +165,31 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
168
165
|
return Effect.fail(new PromiseAnyFulfilled(exit.value));
|
|
169
166
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
170
167
|
return Effect.failCause(exit.cause);
|
|
171
|
-
return Effect.succeed(caughtErrorValue(
|
|
168
|
+
return Effect.succeed(caughtErrorValue(Cause.squash(exit.cause)));
|
|
172
169
|
}));
|
|
173
|
-
return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new ProgramThrow(createAggregateErrorValue(
|
|
170
|
+
return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new ProgramThrow(createAggregateErrorValue(reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
|
|
174
171
|
}));
|
|
175
172
|
};
|
|
176
|
-
const
|
|
177
|
-
const method = `Promise.prototype.${name}`;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return chainFinally(runner, promises, promise, reactionHandler(args[0], method, node), method, node);
|
|
173
|
+
export const invokePromiseInstanceMethod = (runner, promises, ref, args, node) => {
|
|
174
|
+
const method = `Promise.prototype.${ref.name}`;
|
|
175
|
+
promises.markObserved(ref.promise);
|
|
176
|
+
if (ref.name === "finally") {
|
|
177
|
+
return chainFinally(runner, promises, ref.promise, reactionHandler(args[0], method, node), method, node);
|
|
182
178
|
}
|
|
183
|
-
const onFulfilled = name === "then" ? reactionHandler(args[0], method, node) : undefined;
|
|
184
|
-
const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method, node);
|
|
185
|
-
return chainReaction(runner, promises, promise, onFulfilled, onRejected, method, node);
|
|
179
|
+
const onFulfilled = ref.name === "then" ? reactionHandler(args[0], method, node) : undefined;
|
|
180
|
+
const onRejected = reactionHandler(ref.name === "then" ? args[1] : args[0], method, node);
|
|
181
|
+
return chainReaction(runner, promises, ref.promise, onFulfilled, onRejected, method, node);
|
|
186
182
|
};
|
|
187
183
|
const constructPromise = (runner, promises, executor, node) => {
|
|
188
184
|
if (!(executor instanceof ProgramFunction)) {
|
|
189
|
-
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node);
|
|
185
|
+
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node).as("TypeError");
|
|
190
186
|
}
|
|
191
187
|
return Effect.gen(function* () {
|
|
192
188
|
const deferred = Deferred.makeUnsafe();
|
|
193
189
|
const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
|
|
194
|
-
const resolve = capability(
|
|
195
|
-
const reject = capability(
|
|
196
|
-
const executed = yield* Effect.exit(runner.
|
|
190
|
+
const resolve = capability("resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
191
|
+
const reject = capability("reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
|
|
192
|
+
const executed = yield* Effect.exit(runner.invokeFunction(executor, [resolve, reject]));
|
|
197
193
|
if (!Exit.isSuccess(executed)) {
|
|
198
194
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
199
195
|
return yield* Effect.failCause(executed.cause);
|
|
@@ -232,7 +228,7 @@ const chainReaction = (runner, promises, source, onFulfilled, onRejected, method
|
|
|
232
228
|
const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
|
|
233
229
|
if (handler === undefined)
|
|
234
230
|
return yield* exit;
|
|
235
|
-
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(
|
|
231
|
+
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
|
|
236
232
|
const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
|
|
237
233
|
return yield* resolvePromiseValue(runner, result, node, self);
|
|
238
234
|
}));
|
|
@@ -250,27 +246,26 @@ const chainFinally = (runner, promises, source, cleanup, method, node) => promis
|
|
|
250
246
|
return yield* exit;
|
|
251
247
|
}));
|
|
252
248
|
export const promiseGlobal = (runner, promises) => {
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
249
|
+
// Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
|
|
250
|
+
const statics = new Map(promiseStatics.map((name) => [
|
|
251
|
+
name,
|
|
252
|
+
new HostFunction({
|
|
253
|
+
name: `Promise.${name}`,
|
|
254
|
+
call: (args, node) => invokePromiseMethod(runner, promises, name, args, node),
|
|
255
|
+
callback: false,
|
|
256
|
+
}),
|
|
257
|
+
]));
|
|
258
|
+
return new HostFunction({
|
|
256
259
|
name: "Promise",
|
|
257
|
-
length: 1,
|
|
258
260
|
call: requiresNew("Promise"),
|
|
259
|
-
construct: (args,
|
|
261
|
+
construct: (args, node) => constructPromise(runner, promises, args[0], node),
|
|
262
|
+
instanceOf: (value) => value instanceof Values.Promise,
|
|
263
|
+
// Unknown statics fail loudly so a missing await cannot hide behind `undefined`.
|
|
264
|
+
members: (key, node) => {
|
|
265
|
+
const method = typeof key === "string" ? statics.get(key) : undefined;
|
|
266
|
+
if (method !== undefined)
|
|
267
|
+
return method;
|
|
268
|
+
throw new InterpreterRuntimeError(`Promise.${String(key)} is not available. Available: Promise.all, Promise.allSettled, Promise.race, Promise.any, Promise.resolve, and Promise.reject; consume promises with await.`, node);
|
|
269
|
+
},
|
|
260
270
|
});
|
|
261
|
-
// Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
|
|
262
|
-
for (const name of promiseStatics) {
|
|
263
|
-
define(promise, name, native(protos, {
|
|
264
|
-
name,
|
|
265
|
-
length: 1,
|
|
266
|
-
call: (_, args, node) => invokePromiseMethod(runner, promises, name, args, node),
|
|
267
|
-
callback: false,
|
|
268
|
-
}), hidden);
|
|
269
|
-
}
|
|
270
|
-
methods(protos, proto, [
|
|
271
|
-
["then", 2, (thisValue, args, node) => instanceMethod(runner, promises, "then", thisValue, args, node)],
|
|
272
|
-
["catch", 1, (thisValue, args, node) => instanceMethod(runner, promises, "catch", thisValue, args, node)],
|
|
273
|
-
["finally", 1, (thisValue, args, node) => instanceMethod(runner, promises, "finally", thisValue, args, node)],
|
|
274
|
-
]);
|
|
275
|
-
return promise;
|
|
276
271
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type AstNode } from "./model.js";
|
|
2
|
-
/** Values that cannot cross the data boundary. */
|
|
3
2
|
export declare const isRuntimeReference: (value: unknown) => boolean;
|
|
4
3
|
export declare const containsRuntimeReference: (value: unknown) => boolean;
|
|
5
4
|
export declare const containsOpaqueReference: (value: unknown) => boolean;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { ToolReference } from "../tool-runtime.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { Values } from "../values.js";
|
|
3
|
+
import { HostFunction, HostNamespace } from "./host.js";
|
|
4
|
+
import { CodeModeGenerator, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, PromiseInstanceMethodReference, } from "./model.js";
|
|
5
|
+
import { getOwn, ownKeys, ProgramArray, ProgramFunction, ProgramObject } from "./objects.js";
|
|
6
|
+
export const isRuntimeReference = (value) => value instanceof HostFunction ||
|
|
7
|
+
value instanceof HostNamespace ||
|
|
8
|
+
value instanceof ProgramFunction ||
|
|
9
|
+
value instanceof CodeModeGenerator ||
|
|
10
|
+
value instanceof GeneratorMethodReference ||
|
|
7
11
|
value instanceof ToolReference ||
|
|
8
|
-
value instanceof
|
|
9
|
-
|
|
12
|
+
value instanceof IntrinsicReference ||
|
|
13
|
+
value instanceof PromiseInstanceMethodReference ||
|
|
14
|
+
value instanceof Values.Promise ||
|
|
15
|
+
Values.isValue(value);
|
|
10
16
|
function* childValues(value) {
|
|
11
17
|
if (!(value instanceof ProgramObject))
|
|
12
18
|
return;
|
|
@@ -34,8 +40,8 @@ const find = (value, match, skip, seen) => {
|
|
|
34
40
|
};
|
|
35
41
|
const never = () => false;
|
|
36
42
|
export const containsRuntimeReference = (value) => find(value, isRuntimeReference, never, new Set());
|
|
37
|
-
//
|
|
38
|
-
export const containsOpaqueReference = (value) => find(value, (current) => !
|
|
43
|
+
// CodeMode values are data here, not opaque interpreter references.
|
|
44
|
+
export const containsOpaqueReference = (value) => find(value, (current) => !Values.isValue(current) && isRuntimeReference(current), Values.isValue, new Set());
|
|
39
45
|
// Reject cycles before mutation so later boundary walks remain safe.
|
|
40
46
|
export const rejectCircularInsertion = (container, value, label, node, seen = new Set()) => {
|
|
41
47
|
if (find(value, (current) => current === container, isRuntimeReference, seen)) {
|
|
@@ -43,27 +49,27 @@ export const rejectCircularInsertion = (container, value, label, node, seen = ne
|
|
|
43
49
|
}
|
|
44
50
|
};
|
|
45
51
|
export const describeValue = (value) => {
|
|
46
|
-
if (value === null
|
|
47
|
-
return
|
|
52
|
+
if (value === null)
|
|
53
|
+
return "null";
|
|
48
54
|
if (value instanceof ProgramArray)
|
|
49
55
|
return "an array";
|
|
50
|
-
if (value instanceof
|
|
56
|
+
if (value instanceof Values.Promise)
|
|
51
57
|
return "an un-awaited Promise";
|
|
52
58
|
if (value instanceof ToolReference)
|
|
53
59
|
return "a tool reference";
|
|
54
|
-
if (value instanceof
|
|
60
|
+
if (value instanceof Values.Date)
|
|
55
61
|
return "a Date";
|
|
56
|
-
if (value instanceof
|
|
62
|
+
if (value instanceof Values.RegExp)
|
|
57
63
|
return "a RegExp";
|
|
58
|
-
if (value instanceof
|
|
64
|
+
if (value instanceof Values.Map)
|
|
59
65
|
return "a Map";
|
|
60
|
-
if (value instanceof
|
|
66
|
+
if (value instanceof Values.Set)
|
|
61
67
|
return "a Set";
|
|
62
|
-
if (value instanceof
|
|
68
|
+
if (value instanceof Values.URL)
|
|
63
69
|
return "a URL";
|
|
64
|
-
if (value instanceof
|
|
70
|
+
if (value instanceof Values.URLSearchParams)
|
|
65
71
|
return "a URLSearchParams";
|
|
66
|
-
if (value instanceof
|
|
72
|
+
if (value instanceof CodeModeGenerator)
|
|
67
73
|
return "a generator";
|
|
68
74
|
if (isRuntimeReference(value))
|
|
69
75
|
return "a function";
|
|
@@ -72,8 +78,15 @@ export const describeValue = (value) => {
|
|
|
72
78
|
return `a ${typeof value}`;
|
|
73
79
|
};
|
|
74
80
|
export const typeofValue = (value) => {
|
|
75
|
-
if (value instanceof
|
|
81
|
+
if (value instanceof HostFunction ||
|
|
82
|
+
value instanceof ProgramFunction ||
|
|
83
|
+
value instanceof GeneratorMethodReference ||
|
|
84
|
+
value instanceof IntrinsicReference ||
|
|
85
|
+
value instanceof PromiseInstanceMethodReference) {
|
|
76
86
|
return "function";
|
|
87
|
+
}
|
|
88
|
+
if (value instanceof HostNamespace)
|
|
89
|
+
return "object";
|
|
77
90
|
if (value instanceof ToolReference)
|
|
78
91
|
return value.path.length > 0 ? "function" : "object";
|
|
79
92
|
return typeof value;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { Values } from "../values.js";
|
|
3
|
+
import { HostFunction } from "./host.js";
|
|
4
|
+
import { type AstNode, IntrinsicReference } from "./model.js";
|
|
5
|
+
import { ProgramFunction } from "./objects.js";
|
|
5
6
|
export type IteratorCursor<R> = {
|
|
6
7
|
readonly next: Effect.Effect<{
|
|
7
8
|
readonly done: boolean;
|
|
@@ -9,20 +10,15 @@ export type IteratorCursor<R> = {
|
|
|
9
10
|
}, unknown, R>;
|
|
10
11
|
readonly close: Effect.Effect<void, unknown, R>;
|
|
11
12
|
};
|
|
12
|
-
/** Everything a
|
|
13
|
+
/** Everything a host function needs to call back into the program. */
|
|
13
14
|
export type Runner<R> = {
|
|
14
|
-
readonly
|
|
15
|
-
readonly
|
|
15
|
+
readonly invokeFunction: (fn: ProgramFunction, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
|
|
16
|
+
readonly invokeCallable: (callable: unknown, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
17
|
+
readonly settlePromise: (promise: Values.Promise) => Effect.Effect<unknown, unknown, never>;
|
|
16
18
|
readonly syncIterator: (value: unknown, node: AstNode) => Effect.Effect<IteratorCursor<R> | undefined, unknown, R>;
|
|
17
|
-
readonly prototypes: Prototypes;
|
|
18
19
|
};
|
|
19
20
|
export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
export declare const toPrimitive: <R>(runner: Runner<R>, value: unknown, hint: "number" | "string" | "default", node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
25
|
-
export declare const toPrimitiveString: <R>(runner: Runner<R>, value: unknown, node: AstNode) => Effect.Effect<string, unknown, R>;
|
|
26
|
-
export declare const toPrimitiveNumber: <R>(runner: Runner<R>, value: unknown, node: AstNode) => Effect.Effect<number, unknown, R>;
|
|
27
|
-
export declare const isSupportedCallback: (value: unknown) => value is Callable;
|
|
21
|
+
export declare const toPrimitive: <R>(runner: Runner<R>, value: unknown, hint: "number" | "string", node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
22
|
+
export type SupportedCallback = ProgramFunction | HostFunction<unknown> | IntrinsicReference;
|
|
23
|
+
export declare const isSupportedCallback: (value: unknown) => value is SupportedCallback;
|
|
28
24
|
export declare const applyCollectionCallback: <R>(runner: Runner<R>, callback: unknown, name: string, node: AstNode) => ((args: Array<unknown>) => Effect.Effect<unknown, unknown, R>);
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
import { Effect, Exit } from "effect";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { Values } from "../values.js";
|
|
3
|
+
import { coerceToString } from "../stdlib/value.js";
|
|
4
|
+
import { HostFunction } from "./host.js";
|
|
5
|
+
import { InterpreterRuntimeError, IntrinsicReference } from "./model.js";
|
|
6
|
+
import { get, has, ProgramFunction, ProgramObject } from "./objects.js";
|
|
5
7
|
import { typeofValue } from "./references.js";
|
|
6
8
|
export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
|
|
7
9
|
? Effect.succeed(exit.value)
|
|
8
10
|
: Effect.andThen(Effect.exit(cursor.close), Effect.failCause(exit.cause)));
|
|
9
|
-
/**
|
|
10
|
-
* ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
|
|
11
|
-
* default hint as "string", like their `Symbol.toPrimitive`.
|
|
12
|
-
*/
|
|
13
11
|
export const toPrimitive = (runner, value, hint, node) => {
|
|
12
|
+
if (value === null || typeof value !== "object")
|
|
13
|
+
return Effect.succeed(value);
|
|
14
|
+
if (Values.isValue(value)) {
|
|
15
|
+
return Effect.succeed(value instanceof Values.Date && hint === "number" ? value.time : coerceToString(value));
|
|
16
|
+
}
|
|
14
17
|
if (!(value instanceof ProgramObject))
|
|
15
18
|
return Effect.succeed(value);
|
|
16
|
-
const
|
|
17
|
-
const order = asString ? ["toString", "valueOf"] : ["valueOf", "toString"];
|
|
19
|
+
const order = hint === "number" ? ["valueOf", "toString"] : ["toString", "valueOf"];
|
|
18
20
|
return Effect.gen(function* () {
|
|
19
21
|
for (const method of order) {
|
|
22
|
+
if (method === "toString" && !has(value, "toString"))
|
|
23
|
+
return coerceToString(value);
|
|
20
24
|
const callable = get(value, method);
|
|
21
|
-
if (
|
|
25
|
+
if (typeofValue(callable) !== "function")
|
|
22
26
|
continue;
|
|
23
|
-
const result = yield* runner.invokeCallable(callable,
|
|
27
|
+
const result = yield* runner.invokeCallable(callable, [], node);
|
|
24
28
|
if (result === null || (typeof result !== "object" && typeof result !== "function"))
|
|
25
29
|
return result;
|
|
26
30
|
}
|
|
27
|
-
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node);
|
|
31
|
+
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
28
32
|
});
|
|
29
33
|
};
|
|
30
|
-
export const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Array.from mappers, and promise reactions all admit exactly these callables.
|
|
34
|
-
// Admission means dispatchable, not necessarily invocable: new-requiring
|
|
35
|
-
// constructors pass the gate and throw a TypeError on call, like JS.
|
|
36
|
-
export const isSupportedCallback = (value) => value instanceof Callable && !(value instanceof NativeFunction && !value.callback);
|
|
34
|
+
export const isSupportedCallback = (value) => value instanceof ProgramFunction ||
|
|
35
|
+
(value instanceof HostFunction && value.callback) ||
|
|
36
|
+
value instanceof IntrinsicReference;
|
|
37
37
|
export const applyCollectionCallback = (runner, callback, name, node) => {
|
|
38
38
|
if (!isSupportedCallback(callback)) {
|
|
39
39
|
if (typeofValue(callback) === "function") {
|
|
40
40
|
throw new InterpreterRuntimeError(`${name} cannot use this callable as a callback; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`, node);
|
|
41
41
|
}
|
|
42
|
-
throw new InterpreterRuntimeError(`${name} expects a function callback.`, node);
|
|
42
|
+
throw new InterpreterRuntimeError(`${name} expects a function callback.`, node).as("TypeError");
|
|
43
43
|
}
|
|
44
|
-
return (callbackArgs) => runner.invokeCallable(callback,
|
|
44
|
+
return (callbackArgs) => runner.invokeCallable(callback, callbackArgs, node);
|
|
45
45
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Program } from "acorn";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
-
import type { Prototypes } from "./intrinsics.js";
|
|
4
3
|
import { type Host } from "./globals.js";
|
|
5
4
|
import { type Runner } from "./runner.js";
|
|
6
5
|
import { PromiseRuntime } from "./promises.js";
|
|
@@ -10,10 +9,11 @@ export declare class Runtime<R> {
|
|
|
10
9
|
readonly search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
|
|
11
10
|
readonly toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
12
11
|
readonly promises: PromiseRuntime<R>;
|
|
13
|
-
readonly prototypes: Prototypes;
|
|
14
12
|
readonly logs: Array<string>;
|
|
15
13
|
readonly runner: Runner<R>;
|
|
14
|
+
/** Built-in globals by name, unaffected by program shadowing. */
|
|
15
|
+
readonly builtins: ReadonlyMap<string, unknown>;
|
|
16
16
|
private readonly root;
|
|
17
|
-
constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>,
|
|
17
|
+
constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, logs?: Array<string>, extraGlobals?: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]>);
|
|
18
18
|
run(program: Program): Effect.Effect<unknown, unknown, R>;
|
|
19
19
|
}
|