@opencode/codemode 0.0.0-beta-19425 → 0.0.0-beta-19507
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codemode.d.ts +1 -1
- package/dist/codemode.js +1 -1
- package/dist/data.d.ts +4 -6
- package/dist/data.js +44 -18
- package/dist/interpreter/errors.js +3 -4
- package/dist/interpreter/execute.d.ts +2 -1
- package/dist/interpreter/execute.js +2 -2
- package/dist/interpreter/globals.js +4 -0
- package/dist/interpreter/methods.js +64 -55
- package/dist/interpreter/model.d.ts +3 -11
- package/dist/interpreter/model.js +0 -14
- package/dist/interpreter/objects.d.ts +37 -0
- package/dist/interpreter/objects.js +151 -0
- package/dist/interpreter/promises.d.ts +3 -0
- package/dist/interpreter/promises.js +22 -27
- package/dist/interpreter/references.js +9 -11
- package/dist/interpreter/runner.d.ts +4 -3
- package/dist/interpreter/runner.js +9 -6
- package/dist/interpreter/runtime.d.ts +2 -1
- package/dist/interpreter/runtime.js +234 -241
- package/dist/stdlib/array.js +12 -14
- package/dist/stdlib/collections.js +10 -9
- package/dist/stdlib/console.js +16 -14
- package/dist/stdlib/date.js +6 -0
- package/dist/stdlib/json.js +21 -36
- package/dist/stdlib/object.d.ts +2 -0
- package/dist/stdlib/object.js +38 -62
- package/dist/stdlib/regexp.d.ts +2 -1
- package/dist/stdlib/regexp.js +14 -20
- package/dist/stdlib/string.js +5 -0
- package/dist/stdlib/url.js +3 -3
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +25 -26
- package/dist/stdlib/web.d.ts +4 -0
- package/dist/stdlib/web.js +20 -0
- package/dist/tool-runtime.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { BlockStatement, Expression, Pattern } from "acorn";
|
|
2
|
+
import { type Binding } from "./model.js";
|
|
3
|
+
/** An object owned by the program: own properties plus a prototype link. */
|
|
4
|
+
export declare class ProgramObject {
|
|
5
|
+
proto: ProgramObject | null;
|
|
6
|
+
readonly props: Map<PropertyKey, unknown>;
|
|
7
|
+
constructor(proto?: ProgramObject | null);
|
|
8
|
+
}
|
|
9
|
+
export declare class ProgramArray extends ProgramObject {
|
|
10
|
+
readonly items: Array<unknown>;
|
|
11
|
+
constructor(items?: Array<unknown>);
|
|
12
|
+
}
|
|
13
|
+
export declare class ProgramError extends ProgramObject {
|
|
14
|
+
readonly errorName: string;
|
|
15
|
+
constructor(errorName: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class ProgramFunction extends ProgramObject {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly parameters: ReadonlyArray<Pattern>;
|
|
20
|
+
readonly body: BlockStatement | Expression;
|
|
21
|
+
readonly capturedScopes: ReadonlyArray<Map<string, Binding>>;
|
|
22
|
+
readonly async: boolean;
|
|
23
|
+
readonly generator: boolean;
|
|
24
|
+
readonly length: number;
|
|
25
|
+
constructor(name: string, parameters: ReadonlyArray<Pattern>, body: BlockStatement | Expression, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
|
|
26
|
+
}
|
|
27
|
+
export declare const parseArrayIndex: (key: string | number) => number | undefined;
|
|
28
|
+
export declare const hasOwn: (target: ProgramObject, key: PropertyKey) => boolean;
|
|
29
|
+
export declare const getOwn: (target: ProgramObject, key: PropertyKey) => unknown;
|
|
30
|
+
export declare const get: (target: ProgramObject, key: PropertyKey) => unknown;
|
|
31
|
+
export declare const has: (target: ProgramObject, key: PropertyKey) => boolean;
|
|
32
|
+
export declare const set: (target: ProgramObject, key: PropertyKey, value: unknown) => boolean;
|
|
33
|
+
export declare const remove: (target: ProgramObject, key: PropertyKey) => boolean;
|
|
34
|
+
export declare const ownKeys: (target: ProgramObject) => Array<string | symbol>;
|
|
35
|
+
export declare const ownEntries: (target: ProgramObject) => Array<[string, unknown]>;
|
|
36
|
+
export declare const record: (entries: Record<string, unknown>) => ProgramObject;
|
|
37
|
+
export declare const assign: (target: ProgramObject, source: ProgramObject, skip?: ReadonlySet<PropertyKey>) => void;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { AsyncIteratorSymbol, IteratorSymbol } from "./model.js";
|
|
2
|
+
/** An object owned by the program: own properties plus a prototype link. */
|
|
3
|
+
export class ProgramObject {
|
|
4
|
+
proto;
|
|
5
|
+
props = new Map();
|
|
6
|
+
constructor(proto = null) {
|
|
7
|
+
this.proto = proto;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class ProgramArray extends ProgramObject {
|
|
11
|
+
items;
|
|
12
|
+
constructor(items = []) {
|
|
13
|
+
super();
|
|
14
|
+
this.items = items;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class ProgramError extends ProgramObject {
|
|
18
|
+
errorName;
|
|
19
|
+
constructor(errorName) {
|
|
20
|
+
super();
|
|
21
|
+
this.errorName = errorName;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class ProgramFunction extends ProgramObject {
|
|
25
|
+
name;
|
|
26
|
+
parameters;
|
|
27
|
+
body;
|
|
28
|
+
capturedScopes;
|
|
29
|
+
async;
|
|
30
|
+
generator;
|
|
31
|
+
length;
|
|
32
|
+
constructor(name, parameters, body, capturedScopes, async, generator) {
|
|
33
|
+
super();
|
|
34
|
+
this.name = name;
|
|
35
|
+
this.parameters = parameters;
|
|
36
|
+
this.body = body;
|
|
37
|
+
this.capturedScopes = capturedScopes;
|
|
38
|
+
this.async = async;
|
|
39
|
+
this.generator = generator;
|
|
40
|
+
const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement");
|
|
41
|
+
this.length = optional === -1 ? parameters.length : optional;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const MAX_ARRAY_LENGTH = 4_294_967_295;
|
|
45
|
+
export const parseArrayIndex = (key) => {
|
|
46
|
+
const property = String(key);
|
|
47
|
+
if (!/^(0|[1-9]\d*)$/.test(property))
|
|
48
|
+
return undefined;
|
|
49
|
+
const index = Number(property);
|
|
50
|
+
return index < MAX_ARRAY_LENGTH ? index : undefined;
|
|
51
|
+
};
|
|
52
|
+
const canonical = (key) => (typeof key === "symbol" ? key : String(key));
|
|
53
|
+
const index = (target, key) => target instanceof ProgramArray && typeof key === "string" ? parseArrayIndex(key) : undefined;
|
|
54
|
+
// Non-enumerable built-in properties: array length, function name and length.
|
|
55
|
+
const builtin = (target, name) => (name === "length" && target instanceof ProgramArray) ||
|
|
56
|
+
((name === "name" || name === "length") && target instanceof ProgramFunction);
|
|
57
|
+
export const hasOwn = (target, key) => {
|
|
58
|
+
const name = canonical(key);
|
|
59
|
+
const at = index(target, name);
|
|
60
|
+
if (at !== undefined)
|
|
61
|
+
return at in target.items;
|
|
62
|
+
return builtin(target, name) || target.props.has(name);
|
|
63
|
+
};
|
|
64
|
+
export const getOwn = (target, key) => {
|
|
65
|
+
const name = canonical(key);
|
|
66
|
+
const at = index(target, name);
|
|
67
|
+
if (at !== undefined)
|
|
68
|
+
return target.items[at];
|
|
69
|
+
if (target instanceof ProgramArray && name === "length")
|
|
70
|
+
return target.items.length;
|
|
71
|
+
if (target instanceof ProgramFunction && name === "name")
|
|
72
|
+
return target.name;
|
|
73
|
+
if (target instanceof ProgramFunction && name === "length")
|
|
74
|
+
return target.length;
|
|
75
|
+
return target.props.get(name);
|
|
76
|
+
};
|
|
77
|
+
export const get = (target, key) => {
|
|
78
|
+
for (let current = target; current !== null; current = current.proto) {
|
|
79
|
+
if (hasOwn(current, key))
|
|
80
|
+
return getOwn(current, key);
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
};
|
|
84
|
+
export const has = (target, key) => {
|
|
85
|
+
for (let current = target; current !== null; current = current.proto) {
|
|
86
|
+
if (hasOwn(current, key))
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
};
|
|
91
|
+
export const set = (target, key, value) => {
|
|
92
|
+
const name = canonical(key);
|
|
93
|
+
const at = index(target, name);
|
|
94
|
+
if (at !== undefined) {
|
|
95
|
+
;
|
|
96
|
+
target.items[at] = value;
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (name === "length" && target instanceof ProgramArray) {
|
|
100
|
+
const length = typeof value === "number" ? value : Number(value);
|
|
101
|
+
if (!Number.isInteger(length) || length < 0 || length > 4_294_967_295)
|
|
102
|
+
return false;
|
|
103
|
+
target.items.length = length;
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (builtin(target, name))
|
|
107
|
+
return false;
|
|
108
|
+
target.props.set(name, value);
|
|
109
|
+
return true;
|
|
110
|
+
};
|
|
111
|
+
export const remove = (target, key) => {
|
|
112
|
+
const name = canonical(key);
|
|
113
|
+
const at = index(target, name);
|
|
114
|
+
if (at !== undefined)
|
|
115
|
+
return delete target.items[at];
|
|
116
|
+
if (name === "length" && target instanceof ProgramArray)
|
|
117
|
+
return false;
|
|
118
|
+
if (builtin(target, name))
|
|
119
|
+
return true;
|
|
120
|
+
target.props.delete(name);
|
|
121
|
+
return true;
|
|
122
|
+
};
|
|
123
|
+
// JS order: array indexes, integer-like keys ascending, other strings, then symbols.
|
|
124
|
+
export const ownKeys = (target) => {
|
|
125
|
+
const strings = [...target.props.keys()].filter((key) => typeof key === "string");
|
|
126
|
+
const symbols = [...target.props.keys()].filter((key) => typeof key === "symbol");
|
|
127
|
+
return [
|
|
128
|
+
...(target instanceof ProgramArray ? Object.keys(target.items) : []),
|
|
129
|
+
...strings.filter((key) => parseArrayIndex(key) !== undefined).sort((a, b) => Number(a) - Number(b)),
|
|
130
|
+
...strings.filter((key) => parseArrayIndex(key) === undefined),
|
|
131
|
+
...symbols,
|
|
132
|
+
];
|
|
133
|
+
};
|
|
134
|
+
export const ownEntries = (target) => ownKeys(target)
|
|
135
|
+
.filter((key) => typeof key === "string")
|
|
136
|
+
.map((key) => [key, getOwn(target, key)]);
|
|
137
|
+
export const record = (entries) => {
|
|
138
|
+
const target = new ProgramObject();
|
|
139
|
+
for (const [key, value] of Object.entries(entries))
|
|
140
|
+
set(target, key, value);
|
|
141
|
+
return target;
|
|
142
|
+
};
|
|
143
|
+
export const assign = (target, source, skip) => {
|
|
144
|
+
for (const key of ownKeys(source)) {
|
|
145
|
+
if (skip?.has(key))
|
|
146
|
+
continue;
|
|
147
|
+
if (typeof key === "symbol" && key !== IteratorSymbol && key !== AsyncIteratorSymbol)
|
|
148
|
+
continue;
|
|
149
|
+
set(target, key, getOwn(source, key));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
@@ -12,6 +12,9 @@ export declare class PromiseRuntime<R> {
|
|
|
12
12
|
private readonly failures;
|
|
13
13
|
private nextID;
|
|
14
14
|
constructor(scope: Scope.Scope);
|
|
15
|
+
createWithSelf(body: (self: {
|
|
16
|
+
promise?: Values.Promise;
|
|
17
|
+
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
15
18
|
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
16
19
|
markObserved(promise: Values.Promise): void;
|
|
17
20
|
await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { InterpreterRuntimeError, ProgramThrow, PromiseInstanceMethodReference } from "./model.js";
|
|
3
|
+
import { get, ProgramArray, ProgramFunction, ProgramObject, record } from "./objects.js";
|
|
3
4
|
import { HostFunction, requiresNew, sync } from "./host.js";
|
|
4
5
|
import { caughtErrorValue, normalizeError } from "./errors.js";
|
|
5
6
|
import { typeofValue } from "./references.js";
|
|
@@ -22,6 +23,14 @@ export class PromiseRuntime {
|
|
|
22
23
|
constructor(scope) {
|
|
23
24
|
this.scope = scope;
|
|
24
25
|
}
|
|
26
|
+
// Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
|
|
27
|
+
createWithSelf(body) {
|
|
28
|
+
const self = {};
|
|
29
|
+
return Effect.map(this.create(body(self)), (promise) => {
|
|
30
|
+
self.promise = promise;
|
|
31
|
+
return promise;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
25
34
|
create(effect) {
|
|
26
35
|
return Effect.suspend(() => {
|
|
27
36
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
@@ -80,9 +89,9 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
80
89
|
return Effect.fail(selfResolutionError(node));
|
|
81
90
|
if (value instanceof Values.Promise)
|
|
82
91
|
return runner.settlePromise(value);
|
|
83
|
-
if (
|
|
92
|
+
if (!(value instanceof ProgramObject))
|
|
84
93
|
return Effect.succeed(value);
|
|
85
|
-
const then = value
|
|
94
|
+
const then = get(value, "then");
|
|
86
95
|
if (typeofValue(then) !== "function")
|
|
87
96
|
return Effect.succeed(value);
|
|
88
97
|
return Effect.gen(function* () {
|
|
@@ -103,11 +112,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
103
112
|
export const resolvePromise = (runner, promises, value, node) => {
|
|
104
113
|
if (value instanceof Values.Promise)
|
|
105
114
|
return Effect.succeed(value);
|
|
106
|
-
|
|
107
|
-
return Effect.map(promises.create(resolvePromiseValue(runner, value, node, box)), (promise) => {
|
|
108
|
-
box.promise = promise;
|
|
109
|
-
return promise;
|
|
110
|
-
});
|
|
115
|
+
return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
|
|
111
116
|
};
|
|
112
117
|
const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
|
|
113
118
|
const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
@@ -132,25 +137,22 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
132
137
|
items.push(item);
|
|
133
138
|
}
|
|
134
139
|
if (name === "all") {
|
|
135
|
-
return yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" }));
|
|
140
|
+
return new ProgramArray(yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
|
|
136
141
|
}
|
|
137
142
|
if (name === "allSettled") {
|
|
138
143
|
const outcomes = [];
|
|
139
144
|
for (const item of items) {
|
|
140
145
|
const exit = yield* promises.await(item);
|
|
141
146
|
if (Exit.isSuccess(exit)) {
|
|
142
|
-
outcomes.push(
|
|
147
|
+
outcomes.push(record({ status: "fulfilled", value: exit.value }));
|
|
143
148
|
continue;
|
|
144
149
|
}
|
|
145
150
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
146
151
|
return yield* Effect.failCause(exit.cause);
|
|
147
|
-
outcomes.push(
|
|
148
|
-
status: "rejected",
|
|
149
|
-
reason: caughtErrorValue(Cause.squash(exit.cause)),
|
|
150
|
-
}));
|
|
152
|
+
outcomes.push(record({ status: "rejected", reason: caughtErrorValue(Cause.squash(exit.cause)) }));
|
|
151
153
|
}
|
|
152
154
|
yield* Effect.yieldNow;
|
|
153
|
-
return outcomes;
|
|
155
|
+
return new ProgramArray(outcomes);
|
|
154
156
|
}
|
|
155
157
|
if (name === "race") {
|
|
156
158
|
if (items.length === 0) {
|
|
@@ -179,14 +181,12 @@ export const invokePromiseInstanceMethod = (runner, promises, ref, args, node) =
|
|
|
179
181
|
return chainReaction(runner, promises, ref.promise, onFulfilled, onRejected, method, node);
|
|
180
182
|
};
|
|
181
183
|
const constructPromise = (runner, promises, executor, node) => {
|
|
182
|
-
if (!(executor instanceof
|
|
184
|
+
if (!(executor instanceof ProgramFunction)) {
|
|
183
185
|
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node).as("TypeError");
|
|
184
186
|
}
|
|
185
187
|
return Effect.gen(function* () {
|
|
186
188
|
const deferred = Deferred.makeUnsafe();
|
|
187
|
-
const
|
|
188
|
-
const promise = yield* promises.create(Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, box)));
|
|
189
|
-
box.promise = promise;
|
|
189
|
+
const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
|
|
190
190
|
const resolve = capability("resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
191
191
|
const reject = capability("reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
|
|
192
192
|
const executed = yield* Effect.exit(runner.invokeFunction(executor, [resolve, reject]));
|
|
@@ -223,20 +223,15 @@ const reactionExit = (promises, source) => Effect.gen(function* () {
|
|
|
223
223
|
return exit;
|
|
224
224
|
});
|
|
225
225
|
const chainReaction = (runner, promises, source, onFulfilled, onRejected, method, node) => {
|
|
226
|
-
|
|
227
|
-
const body = Effect.gen(function* () {
|
|
226
|
+
return promises.createWithSelf((self) => Effect.gen(function* () {
|
|
228
227
|
const exit = yield* reactionExit(promises, source);
|
|
229
228
|
const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
|
|
230
229
|
if (handler === undefined)
|
|
231
230
|
return yield* exit;
|
|
232
231
|
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
|
|
233
232
|
const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
|
|
234
|
-
return yield* resolvePromiseValue(runner, result, node,
|
|
235
|
-
});
|
|
236
|
-
return Effect.map(promises.create(body), (derived) => {
|
|
237
|
-
box.promise = derived;
|
|
238
|
-
return derived;
|
|
239
|
-
});
|
|
233
|
+
return yield* resolvePromiseValue(runner, result, node, self);
|
|
234
|
+
}));
|
|
240
235
|
};
|
|
241
236
|
const chainFinally = (runner, promises, source, cleanup, method, node) => promises.create(Effect.gen(function* () {
|
|
242
237
|
const exit = yield* reactionExit(promises, source);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ToolReference } from "../tool-runtime.js";
|
|
2
2
|
import { Values } from "../values.js";
|
|
3
3
|
import { HostFunction, HostNamespace } from "./host.js";
|
|
4
|
-
import {
|
|
4
|
+
import { CodeModeGenerator, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, PromiseInstanceMethodReference, } from "./model.js";
|
|
5
|
+
import { getOwn, ownKeys, ProgramArray, ProgramFunction, ProgramObject } from "./objects.js";
|
|
5
6
|
export const isRuntimeReference = (value) => value instanceof HostFunction ||
|
|
6
7
|
value instanceof HostNamespace ||
|
|
7
|
-
value instanceof
|
|
8
|
+
value instanceof ProgramFunction ||
|
|
8
9
|
value instanceof CodeModeGenerator ||
|
|
9
10
|
value instanceof GeneratorMethodReference ||
|
|
10
11
|
value instanceof ToolReference ||
|
|
@@ -13,13 +14,10 @@ export const isRuntimeReference = (value) => value instanceof HostFunction ||
|
|
|
13
14
|
value instanceof Values.Promise ||
|
|
14
15
|
Values.isValue(value);
|
|
15
16
|
function* childValues(value) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
continue;
|
|
21
|
-
yield Reflect.get(value, key);
|
|
22
|
-
}
|
|
17
|
+
if (!(value instanceof ProgramObject))
|
|
18
|
+
return;
|
|
19
|
+
for (const key of ownKeys(value))
|
|
20
|
+
yield getOwn(value, key);
|
|
23
21
|
}
|
|
24
22
|
// Depth-first search over a value tree. `match` stops the walk; `skip` prunes a subtree without matching it.
|
|
25
23
|
const find = (value, match, skip, seen) => {
|
|
@@ -53,7 +51,7 @@ export const rejectCircularInsertion = (container, value, label, node, seen = ne
|
|
|
53
51
|
export const describeValue = (value) => {
|
|
54
52
|
if (value === null)
|
|
55
53
|
return "null";
|
|
56
|
-
if (
|
|
54
|
+
if (value instanceof ProgramArray)
|
|
57
55
|
return "an array";
|
|
58
56
|
if (value instanceof Values.Promise)
|
|
59
57
|
return "an un-awaited Promise";
|
|
@@ -81,7 +79,7 @@ export const describeValue = (value) => {
|
|
|
81
79
|
};
|
|
82
80
|
export const typeofValue = (value) => {
|
|
83
81
|
if (value instanceof HostFunction ||
|
|
84
|
-
value instanceof
|
|
82
|
+
value instanceof ProgramFunction ||
|
|
85
83
|
value instanceof GeneratorMethodReference ||
|
|
86
84
|
value instanceof IntrinsicReference ||
|
|
87
85
|
value instanceof PromiseInstanceMethodReference) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Values } from "../values.js";
|
|
3
3
|
import { HostFunction } from "./host.js";
|
|
4
|
-
import { type AstNode,
|
|
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;
|
|
@@ -11,13 +12,13 @@ export type IteratorCursor<R> = {
|
|
|
11
12
|
};
|
|
12
13
|
/** Everything a host function needs to call back into the program. */
|
|
13
14
|
export type Runner<R> = {
|
|
14
|
-
readonly invokeFunction: (fn:
|
|
15
|
+
readonly invokeFunction: (fn: ProgramFunction, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
|
|
15
16
|
readonly invokeCallable: (callable: unknown, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
16
17
|
readonly settlePromise: (promise: Values.Promise) => Effect.Effect<unknown, unknown, never>;
|
|
17
18
|
readonly syncIterator: (value: unknown, node: AstNode) => Effect.Effect<IteratorCursor<R> | undefined, unknown, R>;
|
|
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
|
export declare const toPrimitive: <R>(runner: Runner<R>, value: unknown, hint: "number" | "string", node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
21
|
-
export type SupportedCallback =
|
|
22
|
+
export type SupportedCallback = ProgramFunction | HostFunction<unknown> | IntrinsicReference;
|
|
22
23
|
export declare const isSupportedCallback: (value: unknown) => value is SupportedCallback;
|
|
23
24
|
export declare const applyCollectionCallback: <R>(runner: Runner<R>, callback: unknown, name: string, node: AstNode) => ((args: Array<unknown>) => Effect.Effect<unknown, unknown, R>);
|
|
@@ -2,7 +2,8 @@ import { Effect, Exit } from "effect";
|
|
|
2
2
|
import { Values } from "../values.js";
|
|
3
3
|
import { coerceToString } from "../stdlib/value.js";
|
|
4
4
|
import { HostFunction } from "./host.js";
|
|
5
|
-
import {
|
|
5
|
+
import { InterpreterRuntimeError, IntrinsicReference } from "./model.js";
|
|
6
|
+
import { get, has, ProgramFunction, ProgramObject } from "./objects.js";
|
|
6
7
|
import { typeofValue } from "./references.js";
|
|
7
8
|
export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
|
|
8
9
|
? Effect.succeed(exit.value)
|
|
@@ -13,22 +14,24 @@ export const toPrimitive = (runner, value, hint, node) => {
|
|
|
13
14
|
if (Values.isValue(value)) {
|
|
14
15
|
return Effect.succeed(value instanceof Values.Date && hint === "number" ? value.time : coerceToString(value));
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
if (!(value instanceof ProgramObject))
|
|
18
|
+
return Effect.succeed(value);
|
|
17
19
|
const order = hint === "number" ? ["valueOf", "toString"] : ["toString", "valueOf"];
|
|
18
20
|
return Effect.gen(function* () {
|
|
19
21
|
for (const method of order) {
|
|
20
|
-
if (method === "toString" && !
|
|
22
|
+
if (method === "toString" && !has(value, "toString"))
|
|
21
23
|
return coerceToString(value);
|
|
22
|
-
|
|
24
|
+
const callable = get(value, method);
|
|
25
|
+
if (typeofValue(callable) !== "function")
|
|
23
26
|
continue;
|
|
24
|
-
const result = yield* runner.invokeCallable(
|
|
27
|
+
const result = yield* runner.invokeCallable(callable, [], node);
|
|
25
28
|
if (result === null || (typeof result !== "object" && typeof result !== "function"))
|
|
26
29
|
return result;
|
|
27
30
|
}
|
|
28
31
|
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
29
32
|
});
|
|
30
33
|
};
|
|
31
|
-
export const isSupportedCallback = (value) => value instanceof
|
|
34
|
+
export const isSupportedCallback = (value) => value instanceof ProgramFunction ||
|
|
32
35
|
(value instanceof HostFunction && value.callback) ||
|
|
33
36
|
value instanceof IntrinsicReference;
|
|
34
37
|
export const applyCollectionCallback = (runner, callback, name, node) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Program } from "acorn";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
+
import { type Host } from "./globals.js";
|
|
3
4
|
import { type Runner } from "./runner.js";
|
|
4
5
|
import { PromiseRuntime } from "./promises.js";
|
|
5
6
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
@@ -13,6 +14,6 @@ export declare class Runtime<R> {
|
|
|
13
14
|
/** Built-in globals by name, unaffected by program shadowing. */
|
|
14
15
|
readonly builtins: ReadonlyMap<string, unknown>;
|
|
15
16
|
private readonly root;
|
|
16
|
-
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>);
|
|
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]>);
|
|
17
18
|
run(program: Program): Effect.Effect<unknown, unknown, R>;
|
|
18
19
|
}
|