@opencode/codemode 2.0.0 → 2.0.2
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 +6 -5
- package/dist/data.js +47 -44
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/interpreter/errors.d.ts +5 -3
- package/dist/interpreter/errors.js +51 -22
- package/dist/interpreter/execute.js +5 -3
- package/dist/interpreter/generators.d.ts +4 -0
- package/dist/interpreter/generators.js +25 -0
- package/dist/interpreter/globals.js +69 -47
- package/dist/interpreter/intrinsics.d.ts +13 -0
- package/dist/interpreter/intrinsics.js +82 -0
- package/dist/interpreter/model.d.ts +13 -36
- package/dist/interpreter/model.js +15 -45
- package/dist/interpreter/native.d.ts +19 -0
- package/dist/interpreter/native.js +40 -0
- package/dist/interpreter/objects.d.ts +106 -13
- package/dist/interpreter/objects.js +192 -65
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +59 -54
- package/dist/interpreter/references.d.ts +1 -0
- package/dist/interpreter/references.js +20 -33
- package/dist/interpreter/runner.d.ts +15 -11
- package/dist/interpreter/runner.js +21 -21
- package/dist/interpreter/runtime.d.ts +3 -3
- package/dist/interpreter/runtime.js +165 -327
- package/dist/interpreter/scope.js +6 -6
- package/dist/stdlib/array.d.ts +4 -2
- package/dist/stdlib/array.js +424 -32
- package/dist/stdlib/collections.d.ts +3 -7
- package/dist/stdlib/collections.js +291 -119
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +35 -30
- package/dist/stdlib/date.d.ts +1 -7
- package/dist/stdlib/date.js +93 -188
- 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 +96 -76
- package/dist/stdlib/number.d.ts +3 -4
- package/dist/stdlib/number.js +95 -60
- package/dist/stdlib/object.d.ts +4 -4
- package/dist/stdlib/object.js +128 -54
- package/dist/stdlib/regexp.d.ts +6 -8
- package/dist/stdlib/regexp.js +76 -68
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +213 -50
- package/dist/stdlib/url.d.ts +5 -13
- package/dist/stdlib/url.js +202 -102
- package/dist/stdlib/value.d.ts +5 -9
- package/dist/stdlib/value.js +16 -38
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +12 -10
- package/dist/tool-runtime.d.ts +2 -1
- package/dist/tool-runtime.js +2 -2
- package/package.json +1 -1
- package/dist/interpreter/host.d.ts +0 -41
- package/dist/interpreter/host.js +0 -44
- package/dist/interpreter/methods.d.ts +0 -4
- package/dist/interpreter/methods.js +0 -837
- package/dist/values.d.ts +0 -37
- package/dist/values.js +0 -56
|
@@ -1,46 +1,124 @@
|
|
|
1
1
|
import { AsyncIteratorSymbol, IteratorSymbol } from "./model.js";
|
|
2
|
+
/** Ordinary assignment: writable, enumerable, configurable. */
|
|
3
|
+
export const data = { writable: true, enumerable: true, configurable: true };
|
|
4
|
+
/** Built-in methods and `constructor`: writable and configurable but hidden from enumeration. */
|
|
5
|
+
export const hidden = { writable: true, enumerable: false, configurable: true };
|
|
6
|
+
/** Function `name` and `length`: read-only but deletable. */
|
|
7
|
+
export const readonly = { writable: false, enumerable: false, configurable: true };
|
|
8
|
+
/** Constants such as `Math.PI` and a constructor's `prototype`. */
|
|
9
|
+
export const frozen = { writable: false, enumerable: false, configurable: false };
|
|
2
10
|
/** An object owned by the program: own properties plus a prototype link. */
|
|
3
11
|
export class ProgramObject {
|
|
4
12
|
proto;
|
|
5
13
|
props = new Map();
|
|
6
|
-
constructor(proto
|
|
14
|
+
constructor(proto) {
|
|
7
15
|
this.proto = proto;
|
|
8
16
|
}
|
|
9
17
|
}
|
|
10
18
|
export class ProgramArray extends ProgramObject {
|
|
11
19
|
items;
|
|
12
|
-
constructor(items = []) {
|
|
13
|
-
super();
|
|
20
|
+
constructor(proto, items = []) {
|
|
21
|
+
super(proto);
|
|
14
22
|
this.items = items;
|
|
15
23
|
}
|
|
16
24
|
}
|
|
25
|
+
/** An object with the [[ErrorData]] slot: what `Error.prototype.toString` and the host boundary recognize as an error. */
|
|
17
26
|
export class ProgramError extends ProgramObject {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
}
|
|
28
|
+
export class Callable extends ProgramObject {
|
|
29
|
+
constructor(proto, name, length) {
|
|
30
|
+
super(proto);
|
|
31
|
+
define(this, "length", length, readonly);
|
|
32
|
+
define(this, "name", name, readonly);
|
|
22
33
|
}
|
|
23
34
|
}
|
|
24
|
-
export class ProgramFunction extends
|
|
25
|
-
name;
|
|
35
|
+
export class ProgramFunction extends Callable {
|
|
26
36
|
parameters;
|
|
27
37
|
body;
|
|
28
38
|
capturedScopes;
|
|
29
39
|
async;
|
|
30
40
|
generator;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
super();
|
|
34
|
-
this.name = name;
|
|
41
|
+
constructor(proto, name, parameters, body, capturedScopes, async, generator) {
|
|
42
|
+
const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement");
|
|
43
|
+
super(proto, name, optional === -1 ? parameters.length : optional);
|
|
35
44
|
this.parameters = parameters;
|
|
36
45
|
this.body = body;
|
|
37
46
|
this.capturedScopes = capturedScopes;
|
|
38
47
|
this.async = async;
|
|
39
48
|
this.generator = generator;
|
|
40
|
-
const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement");
|
|
41
|
-
this.length = optional === -1 ? parameters.length : optional;
|
|
42
49
|
}
|
|
43
50
|
}
|
|
51
|
+
export class NativeFunction extends Callable {
|
|
52
|
+
call;
|
|
53
|
+
construct;
|
|
54
|
+
callback;
|
|
55
|
+
constructor(proto, options) {
|
|
56
|
+
super(proto, options.name, options.length ?? 0);
|
|
57
|
+
this.call = options.call;
|
|
58
|
+
this.construct = options.construct;
|
|
59
|
+
this.callback = options.callback ?? true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export class ProgramPromise extends ProgramObject {
|
|
63
|
+
fiber;
|
|
64
|
+
constructor(proto, fiber) {
|
|
65
|
+
super(proto);
|
|
66
|
+
this.fiber = fiber;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export class ProgramGenerator extends ProgramObject {
|
|
70
|
+
asynchronous;
|
|
71
|
+
request;
|
|
72
|
+
constructor(proto, asynchronous, request) {
|
|
73
|
+
super(proto);
|
|
74
|
+
this.asynchronous = asynchronous;
|
|
75
|
+
this.request = request;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export class ProgramDate extends ProgramObject {
|
|
79
|
+
time;
|
|
80
|
+
constructor(proto, time) {
|
|
81
|
+
super(proto);
|
|
82
|
+
this.time = time;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export class ProgramRegExp extends ProgramObject {
|
|
86
|
+
regex;
|
|
87
|
+
constructor(proto, pattern, flags) {
|
|
88
|
+
super(proto);
|
|
89
|
+
this.regex = new RegExp(pattern, flags);
|
|
90
|
+
define(this, "lastIndex", 0, { writable: true, enumerable: false, configurable: false });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class ProgramMap extends ProgramObject {
|
|
94
|
+
map = new Map();
|
|
95
|
+
}
|
|
96
|
+
export class ProgramSet extends ProgramObject {
|
|
97
|
+
set = new Set();
|
|
98
|
+
}
|
|
99
|
+
export class ProgramURLSearchParams extends ProgramObject {
|
|
100
|
+
params;
|
|
101
|
+
constructor(proto, params) {
|
|
102
|
+
super(proto);
|
|
103
|
+
this.params = params;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export class ProgramURL extends ProgramObject {
|
|
107
|
+
url;
|
|
108
|
+
searchParams;
|
|
109
|
+
constructor(proto, searchParamsProto, url) {
|
|
110
|
+
super(proto);
|
|
111
|
+
this.url = url;
|
|
112
|
+
this.searchParams = new ProgramURLSearchParams(searchParamsProto, url.searchParams);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Built-in objects that wrap a host value; data-like, but never plain data. */
|
|
116
|
+
export const isWrapper = (value) => value instanceof ProgramDate ||
|
|
117
|
+
value instanceof ProgramRegExp ||
|
|
118
|
+
value instanceof ProgramMap ||
|
|
119
|
+
value instanceof ProgramSet ||
|
|
120
|
+
value instanceof ProgramURL ||
|
|
121
|
+
value instanceof ProgramURLSearchParams;
|
|
44
122
|
const MAX_ARRAY_LENGTH = 4_294_967_295;
|
|
45
123
|
export const parseArrayIndex = (key) => {
|
|
46
124
|
const property = String(key);
|
|
@@ -51,72 +129,119 @@ export const parseArrayIndex = (key) => {
|
|
|
51
129
|
};
|
|
52
130
|
const canonical = (key) => (typeof key === "symbol" ? key : String(key));
|
|
53
131
|
const index = (target, key) => target instanceof ProgramArray && typeof key === "string" ? parseArrayIndex(key) : undefined;
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
((name === "name" || name === "length") && target instanceof ProgramFunction);
|
|
57
|
-
export const hasOwn = (target, key) => {
|
|
132
|
+
/** The own property under `key`, including an array's live indexes and `length`. */
|
|
133
|
+
export const own = (target, key) => {
|
|
58
134
|
const name = canonical(key);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
135
|
+
if (target instanceof ProgramArray) {
|
|
136
|
+
const at = index(target, name);
|
|
137
|
+
if (at !== undefined) {
|
|
138
|
+
return at in target.items ? { value: target.items[at], ...data } : undefined;
|
|
139
|
+
}
|
|
140
|
+
if (name === "length")
|
|
141
|
+
return { value: target.items.length, writable: true, enumerable: false, configurable: false };
|
|
142
|
+
}
|
|
143
|
+
return target.props.get(name);
|
|
63
144
|
};
|
|
145
|
+
const read = (slot, receiver) => "value" in slot ? slot.value : slot.get === undefined ? undefined : slot.get(receiver);
|
|
146
|
+
export const hasOwn = (target, key) => own(target, key) !== undefined;
|
|
64
147
|
export const getOwn = (target, key) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
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);
|
|
148
|
+
const slot = own(target, key);
|
|
149
|
+
return slot === undefined ? undefined : read(slot, target);
|
|
76
150
|
};
|
|
77
|
-
|
|
151
|
+
/** [[Get]]: walks the prototype chain; accessors see `receiver`, which is the primitive for wrapper prototypes. */
|
|
152
|
+
export const get = (target, key, receiver = target) => {
|
|
78
153
|
for (let current = target; current !== null; current = current.proto) {
|
|
79
|
-
|
|
80
|
-
|
|
154
|
+
const slot = own(current, key);
|
|
155
|
+
if (slot !== undefined)
|
|
156
|
+
return read(slot, receiver);
|
|
81
157
|
}
|
|
82
158
|
return undefined;
|
|
83
159
|
};
|
|
84
160
|
export const has = (target, key) => {
|
|
85
161
|
for (let current = target; current !== null; current = current.proto) {
|
|
86
|
-
if (
|
|
162
|
+
if (own(current, key) !== undefined)
|
|
87
163
|
return true;
|
|
88
164
|
}
|
|
89
165
|
return false;
|
|
90
166
|
};
|
|
91
|
-
export const
|
|
92
|
-
|
|
167
|
+
export const hasPrototype = (value, proto) => {
|
|
168
|
+
for (let current = value instanceof ProgramObject ? value.proto : null; current !== null; current = current.proto) {
|
|
169
|
+
if (current === proto)
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
};
|
|
174
|
+
const writeArray = (target, name, value) => {
|
|
93
175
|
const at = index(target, name);
|
|
94
176
|
if (at !== undefined) {
|
|
95
|
-
;
|
|
96
177
|
target.items[at] = value;
|
|
97
178
|
return true;
|
|
98
179
|
}
|
|
99
|
-
if (name
|
|
100
|
-
|
|
101
|
-
|
|
180
|
+
if (name !== "length")
|
|
181
|
+
return undefined;
|
|
182
|
+
const length = typeof value === "number" ? value : Number(value);
|
|
183
|
+
if (!Number.isInteger(length) || length < 0 || length > MAX_ARRAY_LENGTH)
|
|
184
|
+
return false;
|
|
185
|
+
target.items.length = length;
|
|
186
|
+
return true;
|
|
187
|
+
};
|
|
188
|
+
/** [[Set]]: an inherited setter or read-only property decides before an own data property is created. */
|
|
189
|
+
export const set = (target, key, value) => {
|
|
190
|
+
const name = canonical(key);
|
|
191
|
+
for (let current = target; current !== null; current = current.proto) {
|
|
192
|
+
const slot = own(current, name);
|
|
193
|
+
if (slot === undefined)
|
|
194
|
+
continue;
|
|
195
|
+
if (!("value" in slot)) {
|
|
196
|
+
if (slot.set === undefined)
|
|
197
|
+
return false;
|
|
198
|
+
slot.set(target, value);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (!slot.writable)
|
|
102
202
|
return false;
|
|
103
|
-
|
|
203
|
+
if (current !== target)
|
|
204
|
+
break;
|
|
205
|
+
if (target instanceof ProgramArray) {
|
|
206
|
+
const written = writeArray(target, name, value);
|
|
207
|
+
if (written !== undefined)
|
|
208
|
+
return written;
|
|
209
|
+
}
|
|
210
|
+
slot.value = value;
|
|
104
211
|
return true;
|
|
105
212
|
}
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
213
|
+
if (target instanceof ProgramArray) {
|
|
214
|
+
const written = writeArray(target, name, value);
|
|
215
|
+
if (written !== undefined)
|
|
216
|
+
return written;
|
|
217
|
+
}
|
|
218
|
+
target.props.set(name, { value, ...data });
|
|
109
219
|
return true;
|
|
110
220
|
};
|
|
221
|
+
/** [[DefineOwnProperty]] for a data property, ignoring the chain. */
|
|
222
|
+
export const define = (target, key, value, attrs = data) => {
|
|
223
|
+
const name = canonical(key);
|
|
224
|
+
if (target instanceof ProgramArray && writeArray(target, name, value) !== undefined)
|
|
225
|
+
return;
|
|
226
|
+
target.props.set(name, { value, ...attrs });
|
|
227
|
+
};
|
|
228
|
+
export const defineAccessor = (target, key, get, set) => {
|
|
229
|
+
target.props.set(canonical(key), { get, set, enumerable: false, configurable: true });
|
|
230
|
+
};
|
|
111
231
|
export const remove = (target, key) => {
|
|
112
232
|
const name = canonical(key);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
233
|
+
if (target instanceof ProgramArray) {
|
|
234
|
+
const at = index(target, name);
|
|
235
|
+
if (at !== undefined)
|
|
236
|
+
return delete target.items[at];
|
|
237
|
+
if (name === "length")
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
const slot = target.props.get(name);
|
|
241
|
+
if (slot === undefined)
|
|
119
242
|
return true;
|
|
243
|
+
if (!slot.configurable)
|
|
244
|
+
return false;
|
|
120
245
|
target.props.delete(name);
|
|
121
246
|
return true;
|
|
122
247
|
};
|
|
@@ -125,27 +250,29 @@ export const ownKeys = (target) => {
|
|
|
125
250
|
const strings = [...target.props.keys()].filter((key) => typeof key === "string");
|
|
126
251
|
const symbols = [...target.props.keys()].filter((key) => typeof key === "symbol");
|
|
127
252
|
return [
|
|
128
|
-
...(target instanceof ProgramArray ? Object.keys(target.items) : []),
|
|
253
|
+
...(target instanceof ProgramArray ? [...Object.keys(target.items), "length"] : []),
|
|
129
254
|
...strings.filter((key) => parseArrayIndex(key) !== undefined).sort((a, b) => Number(a) - Number(b)),
|
|
130
255
|
...strings.filter((key) => parseArrayIndex(key) === undefined),
|
|
131
256
|
...symbols,
|
|
132
257
|
];
|
|
133
258
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
259
|
+
const enumerable = (target, key) => own(target, key)?.enumerable === true;
|
|
260
|
+
/** Own enumerable keys, including the iterator symbols; what spread and `Object.assign` copy. */
|
|
261
|
+
export const enumerableKeys = (target) => ownKeys(target).filter((key) => (typeof key === "string" || key === IteratorSymbol || key === AsyncIteratorSymbol) && enumerable(target, key));
|
|
262
|
+
/** Own enumerable string keys: `Object.keys`. */
|
|
263
|
+
export const keys = (target) => ownKeys(target).filter((key) => typeof key === "string" && enumerable(target, key));
|
|
264
|
+
/** Own enumerable string entries: `Object.entries` and serialization. */
|
|
265
|
+
export const entries = (target) => keys(target).map((key) => [key, getOwn(target, key)]);
|
|
266
|
+
export const record = (proto, fields) => {
|
|
267
|
+
const target = new ProgramObject(proto);
|
|
268
|
+
for (const [key, value] of Object.entries(fields))
|
|
269
|
+
define(target, key, value);
|
|
141
270
|
return target;
|
|
142
271
|
};
|
|
143
272
|
export const assign = (target, source, skip) => {
|
|
144
|
-
for (const key of
|
|
273
|
+
for (const key of enumerableKeys(source)) {
|
|
145
274
|
if (skip?.has(key))
|
|
146
275
|
continue;
|
|
147
|
-
if (typeof key === "symbol" && key !== IteratorSymbol && key !== AsyncIteratorSymbol)
|
|
148
|
-
continue;
|
|
149
276
|
set(target, key, getOwn(source, key));
|
|
150
277
|
}
|
|
151
278
|
};
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
import { Effect, Exit, Scope } from "effect";
|
|
2
2
|
import type { Diagnostic } from "../codemode.js";
|
|
3
|
-
import { type AstNode, InterpreterRuntimeError
|
|
4
|
-
import {
|
|
5
|
-
import { Values } from "../values.js";
|
|
3
|
+
import { type AstNode, InterpreterRuntimeError } from "./model.js";
|
|
4
|
+
import { ProgramObject, ProgramPromise } from "./objects.js";
|
|
6
5
|
import { type Runner } from "./runner.js";
|
|
7
6
|
export declare class PromiseRuntime<R> {
|
|
8
7
|
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, proto: ProgramObject);
|
|
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?: ProgramPromise;
|
|
17
|
+
}) => Effect.Effect<unknown, unknown, R>): Effect.Effect<ProgramPromise, never, R>;
|
|
18
|
+
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<ProgramPromise, never, R>;
|
|
19
|
+
markObserved(promise: ProgramPromise): void;
|
|
20
|
+
await(promise: ProgramPromise): 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?: ProgramPromise;
|
|
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
|
|
31
|
-
export declare const promiseGlobal: <R>(runner: Runner<R>, promises: PromiseRuntime<R>) => HostFunction<R>;
|
|
29
|
+
export declare const resolvePromise: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<ProgramPromise, never, R>;
|
|
30
|
+
export declare const promiseGlobal: <R>(runner: Runner<R>, promises: PromiseRuntime<R>) => import("./objects.js").NativeFunction<R>;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
|
|
2
|
-
import { InterpreterRuntimeError, ProgramThrow
|
|
3
|
-
import { get, ProgramArray, ProgramFunction, ProgramObject, record } from "./objects.js";
|
|
4
|
-
import {
|
|
5
|
-
import { caughtErrorValue, normalizeError } from "./errors.js";
|
|
2
|
+
import { InterpreterRuntimeError, ProgramThrow } from "./model.js";
|
|
3
|
+
import { Callable, define, get, hidden, ProgramArray, ProgramFunction, ProgramObject, ProgramPromise, record, } from "./objects.js";
|
|
4
|
+
import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
|
|
5
|
+
import { caughtErrorValue, createAggregateErrorValue, normalizeError } from "./errors.js";
|
|
6
6
|
import { typeofValue } from "./references.js";
|
|
7
|
-
import { createAggregateErrorValue } from "../stdlib/value.js";
|
|
8
|
-
import { Values } from "../values.js";
|
|
9
7
|
import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
|
|
10
8
|
// A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
|
|
11
|
-
const capability = (name, settle) =>
|
|
9
|
+
const capability = (runner, name, settle) => fn(runner.prototypes, name, 1, (_, args) => {
|
|
12
10
|
settle(args[0]);
|
|
13
11
|
return undefined;
|
|
14
12
|
});
|
|
15
13
|
// Observation only controls rejection reporting; program completion interrupts all promise work.
|
|
16
14
|
export class PromiseRuntime {
|
|
17
15
|
scope;
|
|
16
|
+
proto;
|
|
18
17
|
active = new Set();
|
|
19
18
|
ids = new WeakMap();
|
|
20
19
|
observed = new WeakSet();
|
|
21
20
|
failures = new Map();
|
|
22
21
|
nextID = 0;
|
|
23
|
-
constructor(scope) {
|
|
22
|
+
constructor(scope, proto) {
|
|
24
23
|
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 ProgramPromise(this.proto, 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);
|
|
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 ProgramPromise)
|
|
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("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));
|
|
101
|
+
const resolve = capability(runner, "resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
|
|
102
|
+
const reject = capability(runner, "reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason))));
|
|
103
|
+
const executed = yield* Effect.exit(runner.invokeCallable(then, value, [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 ProgramPromise)
|
|
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);
|
|
129
129
|
}
|
|
130
130
|
const items = [];
|
|
131
131
|
while (true) {
|
|
@@ -137,22 +137,25 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
137
137
|
items.push(item);
|
|
138
138
|
}
|
|
139
139
|
if (name === "all") {
|
|
140
|
-
return new ProgramArray(yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
|
|
140
|
+
return new ProgramArray(runner.prototypes.Array, 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({ status: "fulfilled", value: exit.value }));
|
|
147
|
+
outcomes.push(record(runner.prototypes.Object, { 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(
|
|
152
|
+
outcomes.push(record(runner.prototypes.Object, {
|
|
153
|
+
status: "rejected",
|
|
154
|
+
reason: caughtErrorValue(runner, Cause.squash(exit.cause)),
|
|
155
|
+
}));
|
|
153
156
|
}
|
|
154
157
|
yield* Effect.yieldNow;
|
|
155
|
-
return new ProgramArray(outcomes);
|
|
158
|
+
return new ProgramArray(runner.prototypes.Array, outcomes);
|
|
156
159
|
}
|
|
157
160
|
if (name === "race") {
|
|
158
161
|
if (items.length === 0) {
|
|
@@ -165,31 +168,32 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
|
|
|
165
168
|
return Effect.fail(new PromiseAnyFulfilled(exit.value));
|
|
166
169
|
if (Cause.hasInterruptsOnly(exit.cause))
|
|
167
170
|
return Effect.failCause(exit.cause);
|
|
168
|
-
return Effect.succeed(caughtErrorValue(Cause.squash(exit.cause)));
|
|
171
|
+
return Effect.succeed(caughtErrorValue(runner, Cause.squash(exit.cause)));
|
|
169
172
|
}));
|
|
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))));
|
|
173
|
+
return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new ProgramThrow(createAggregateErrorValue(runner, reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
|
|
171
174
|
}));
|
|
172
175
|
};
|
|
173
|
-
|
|
174
|
-
const method = `Promise.prototype.${
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
const instanceMethod = (runner, promises, name, thisValue, args, node) => {
|
|
177
|
+
const method = `Promise.prototype.${name}`;
|
|
178
|
+
const promise = receiver(ProgramPromise, thisValue, method, node);
|
|
179
|
+
promises.markObserved(promise);
|
|
180
|
+
if (name === "finally") {
|
|
181
|
+
return chainFinally(runner, promises, promise, reactionHandler(args[0], method, node), method, node);
|
|
178
182
|
}
|
|
179
|
-
const onFulfilled =
|
|
180
|
-
const onRejected = reactionHandler(
|
|
181
|
-
return chainReaction(runner, promises,
|
|
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);
|
|
182
186
|
};
|
|
183
187
|
const constructPromise = (runner, promises, executor, node) => {
|
|
184
188
|
if (!(executor instanceof ProgramFunction)) {
|
|
185
|
-
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node)
|
|
189
|
+
throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node);
|
|
186
190
|
}
|
|
187
191
|
return Effect.gen(function* () {
|
|
188
192
|
const deferred = Deferred.makeUnsafe();
|
|
189
193
|
const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
|
|
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.
|
|
194
|
+
const resolve = capability(runner, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
|
|
195
|
+
const reject = capability(runner, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
|
|
196
|
+
const executed = yield* Effect.exit(runner.invokeCallable(executor, undefined, [resolve, reject], node));
|
|
193
197
|
if (!Exit.isSuccess(executed)) {
|
|
194
198
|
if (Cause.hasInterruptsOnly(executed.cause))
|
|
195
199
|
return yield* Effect.failCause(executed.cause);
|
|
@@ -228,7 +232,7 @@ const chainReaction = (runner, promises, source, onFulfilled, onRejected, method
|
|
|
228
232
|
const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
|
|
229
233
|
if (handler === undefined)
|
|
230
234
|
return yield* exit;
|
|
231
|
-
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
|
|
235
|
+
const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(runner, Cause.squash(exit.cause));
|
|
232
236
|
const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
|
|
233
237
|
return yield* resolvePromiseValue(runner, result, node, self);
|
|
234
238
|
}));
|
|
@@ -246,26 +250,27 @@ const chainFinally = (runner, promises, source, cleanup, method, node) => promis
|
|
|
246
250
|
return yield* exit;
|
|
247
251
|
}));
|
|
248
252
|
export const promiseGlobal = (runner, promises) => {
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
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({
|
|
253
|
+
const protos = runner.prototypes;
|
|
254
|
+
const proto = protos.Promise;
|
|
255
|
+
const promise = constructor(protos, proto, {
|
|
259
256
|
name: "Promise",
|
|
257
|
+
length: 1,
|
|
260
258
|
call: requiresNew("Promise"),
|
|
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
|
-
},
|
|
259
|
+
construct: (args, _, node) => constructPromise(runner, promises, args[0], node),
|
|
270
260
|
});
|
|
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;
|
|
271
276
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AstNode } from "./model.js";
|
|
2
|
+
/** Values that cannot cross the data boundary. */
|
|
2
3
|
export declare const isRuntimeReference: (value: unknown) => boolean;
|
|
3
4
|
export declare const containsRuntimeReference: (value: unknown) => boolean;
|
|
4
5
|
export declare const containsOpaqueReference: (value: unknown) => boolean;
|