@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.
Files changed (62) hide show
  1. package/dist/data.d.ts +6 -5
  2. package/dist/data.js +47 -44
  3. package/dist/index.d.ts +0 -1
  4. package/dist/index.js +0 -1
  5. package/dist/interpreter/errors.d.ts +5 -3
  6. package/dist/interpreter/errors.js +51 -22
  7. package/dist/interpreter/execute.js +5 -3
  8. package/dist/interpreter/generators.d.ts +4 -0
  9. package/dist/interpreter/generators.js +25 -0
  10. package/dist/interpreter/globals.js +69 -47
  11. package/dist/interpreter/intrinsics.d.ts +13 -0
  12. package/dist/interpreter/intrinsics.js +82 -0
  13. package/dist/interpreter/model.d.ts +13 -36
  14. package/dist/interpreter/model.js +15 -45
  15. package/dist/interpreter/native.d.ts +19 -0
  16. package/dist/interpreter/native.js +40 -0
  17. package/dist/interpreter/objects.d.ts +106 -13
  18. package/dist/interpreter/objects.js +192 -65
  19. package/dist/interpreter/promises.d.ts +12 -13
  20. package/dist/interpreter/promises.js +59 -54
  21. package/dist/interpreter/references.d.ts +1 -0
  22. package/dist/interpreter/references.js +20 -33
  23. package/dist/interpreter/runner.d.ts +15 -11
  24. package/dist/interpreter/runner.js +21 -21
  25. package/dist/interpreter/runtime.d.ts +3 -3
  26. package/dist/interpreter/runtime.js +165 -327
  27. package/dist/interpreter/scope.js +6 -6
  28. package/dist/stdlib/array.d.ts +4 -2
  29. package/dist/stdlib/array.js +424 -32
  30. package/dist/stdlib/collections.d.ts +3 -7
  31. package/dist/stdlib/collections.js +291 -119
  32. package/dist/stdlib/console.d.ts +3 -2
  33. package/dist/stdlib/console.js +35 -30
  34. package/dist/stdlib/date.d.ts +1 -7
  35. package/dist/stdlib/date.js +93 -188
  36. package/dist/stdlib/json.d.ts +2 -2
  37. package/dist/stdlib/json.js +27 -27
  38. package/dist/stdlib/math.d.ts +2 -2
  39. package/dist/stdlib/math.js +96 -76
  40. package/dist/stdlib/number.d.ts +3 -4
  41. package/dist/stdlib/number.js +95 -60
  42. package/dist/stdlib/object.d.ts +4 -4
  43. package/dist/stdlib/object.js +128 -54
  44. package/dist/stdlib/regexp.d.ts +6 -8
  45. package/dist/stdlib/regexp.js +76 -68
  46. package/dist/stdlib/string.d.ts +2 -2
  47. package/dist/stdlib/string.js +213 -50
  48. package/dist/stdlib/url.d.ts +5 -13
  49. package/dist/stdlib/url.js +202 -102
  50. package/dist/stdlib/value.d.ts +5 -9
  51. package/dist/stdlib/value.js +16 -38
  52. package/dist/stdlib/web.d.ts +4 -4
  53. package/dist/stdlib/web.js +12 -10
  54. package/dist/tool-runtime.d.ts +2 -1
  55. package/dist/tool-runtime.js +2 -2
  56. package/package.json +1 -1
  57. package/dist/interpreter/host.d.ts +0 -41
  58. package/dist/interpreter/host.js +0 -44
  59. package/dist/interpreter/methods.d.ts +0 -4
  60. package/dist/interpreter/methods.js +0 -837
  61. package/dist/values.d.ts +0 -37
  62. 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 = null) {
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
- errorName;
19
- constructor(errorName) {
20
- super();
21
- this.errorName = errorName;
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 ProgramObject {
25
- name;
35
+ export class ProgramFunction extends Callable {
26
36
  parameters;
27
37
  body;
28
38
  capturedScopes;
29
39
  async;
30
40
  generator;
31
- length;
32
- constructor(name, parameters, body, capturedScopes, async, generator) {
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
- // 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) => {
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
- const at = index(target, name);
60
- if (at !== undefined)
61
- return at in target.items;
62
- return builtin(target, name) || target.props.has(name);
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 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);
148
+ const slot = own(target, key);
149
+ return slot === undefined ? undefined : read(slot, target);
76
150
  };
77
- export const get = (target, key) => {
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
- if (hasOwn(current, key))
80
- return getOwn(current, key);
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 (hasOwn(current, key))
162
+ if (own(current, key) !== undefined)
87
163
  return true;
88
164
  }
89
165
  return false;
90
166
  };
91
- export const set = (target, key, value) => {
92
- const name = canonical(key);
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 === "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)
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
- target.items.length = length;
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 (builtin(target, name))
107
- return false;
108
- target.props.set(name, value);
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
- 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))
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
- 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);
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 ownKeys(source)) {
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, PromiseInstanceMethodReference } from "./model.js";
4
- import { HostFunction } from "./host.js";
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?: 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>>;
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?: Values.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<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>;
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, 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";
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) => sync(name, (args) => {
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 Values.Promise(fiber);
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).as("TypeError");
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 Values.Promise)
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 Values.Promise)
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).as("TypeError");
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({ status: "rejected", reason: caughtErrorValue(Cause.squash(exit.cause)) }));
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
- 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);
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 = 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);
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).as("TypeError");
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.invokeFunction(executor, [resolve, reject]));
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
- // 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({
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;