@opencode/codemode 2.0.1 → 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 (61) hide show
  1. package/dist/data.d.ts +6 -5
  2. package/dist/data.js +44 -46
  3. package/dist/index.d.ts +0 -1
  4. package/dist/index.js +0 -1
  5. package/dist/interpreter/errors.d.ts +3 -4
  6. package/dist/interpreter/errors.js +40 -17
  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 +67 -46
  11. package/dist/interpreter/intrinsics.d.ts +8 -5
  12. package/dist/interpreter/intrinsics.js +59 -18
  13. package/dist/interpreter/model.d.ts +2 -32
  14. package/dist/interpreter/model.js +4 -38
  15. package/dist/interpreter/native.d.ts +19 -0
  16. package/dist/interpreter/native.js +40 -0
  17. package/dist/interpreter/objects.d.ts +105 -12
  18. package/dist/interpreter/objects.js +190 -66
  19. package/dist/interpreter/promises.d.ts +12 -13
  20. package/dist/interpreter/promises.js +52 -46
  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 -13
  24. package/dist/interpreter/runner.js +19 -19
  25. package/dist/interpreter/runtime.d.ts +3 -3
  26. package/dist/interpreter/runtime.js +150 -314
  27. package/dist/stdlib/array.d.ts +4 -2
  28. package/dist/stdlib/array.js +423 -31
  29. package/dist/stdlib/collections.d.ts +3 -7
  30. package/dist/stdlib/collections.js +286 -114
  31. package/dist/stdlib/console.d.ts +3 -2
  32. package/dist/stdlib/console.js +35 -30
  33. package/dist/stdlib/date.d.ts +1 -7
  34. package/dist/stdlib/date.js +93 -188
  35. package/dist/stdlib/json.d.ts +2 -2
  36. package/dist/stdlib/json.js +24 -24
  37. package/dist/stdlib/math.d.ts +2 -2
  38. package/dist/stdlib/math.js +96 -76
  39. package/dist/stdlib/number.d.ts +3 -4
  40. package/dist/stdlib/number.js +94 -59
  41. package/dist/stdlib/object.d.ts +4 -4
  42. package/dist/stdlib/object.js +123 -49
  43. package/dist/stdlib/regexp.d.ts +6 -8
  44. package/dist/stdlib/regexp.js +71 -63
  45. package/dist/stdlib/string.d.ts +2 -2
  46. package/dist/stdlib/string.js +213 -50
  47. package/dist/stdlib/url.d.ts +5 -13
  48. package/dist/stdlib/url.js +196 -96
  49. package/dist/stdlib/value.d.ts +5 -4
  50. package/dist/stdlib/value.js +16 -16
  51. package/dist/stdlib/web.d.ts +4 -4
  52. package/dist/stdlib/web.js +8 -7
  53. package/dist/tool-runtime.d.ts +2 -1
  54. package/dist/tool-runtime.js +2 -2
  55. package/package.json +1 -1
  56. package/dist/interpreter/host.d.ts +0 -41
  57. package/dist/interpreter/host.js +0 -44
  58. package/dist/interpreter/methods.d.ts +0 -4
  59. package/dist/interpreter/methods.js +0 -837
  60. package/dist/values.d.ts +0 -37
  61. package/dist/values.js +0 -56
@@ -1,42 +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
  }
17
25
  /** An object with the [[ErrorData]] slot: what `Error.prototype.toString` and the host boundary recognize as an error. */
18
26
  export class ProgramError extends ProgramObject {
19
27
  }
20
- export class ProgramFunction extends ProgramObject {
21
- name;
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);
33
+ }
34
+ }
35
+ export class ProgramFunction extends Callable {
22
36
  parameters;
23
37
  body;
24
38
  capturedScopes;
25
39
  async;
26
40
  generator;
27
- length;
28
- constructor(name, parameters, body, capturedScopes, async, generator) {
29
- super();
30
- 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);
31
44
  this.parameters = parameters;
32
45
  this.body = body;
33
46
  this.capturedScopes = capturedScopes;
34
47
  this.async = async;
35
48
  this.generator = generator;
36
- const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement");
37
- this.length = optional === -1 ? parameters.length : optional;
38
49
  }
39
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;
40
122
  const MAX_ARRAY_LENGTH = 4_294_967_295;
41
123
  export const parseArrayIndex = (key) => {
42
124
  const property = String(key);
@@ -47,79 +129,119 @@ export const parseArrayIndex = (key) => {
47
129
  };
48
130
  const canonical = (key) => (typeof key === "symbol" ? key : String(key));
49
131
  const index = (target, key) => target instanceof ProgramArray && typeof key === "string" ? parseArrayIndex(key) : undefined;
50
- // Non-enumerable built-in properties: array length, function name and length.
51
- const builtin = (target, name) => (name === "length" && target instanceof ProgramArray) ||
52
- ((name === "name" || name === "length") && target instanceof ProgramFunction);
53
- 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) => {
54
134
  const name = canonical(key);
55
- const at = index(target, name);
56
- if (at !== undefined)
57
- return at in target.items;
58
- 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);
59
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;
60
147
  export const getOwn = (target, key) => {
61
- const name = canonical(key);
62
- const at = index(target, name);
63
- if (at !== undefined)
64
- return target.items[at];
65
- if (target instanceof ProgramArray && name === "length")
66
- return target.items.length;
67
- if (target instanceof ProgramFunction && name === "name")
68
- return target.name;
69
- if (target instanceof ProgramFunction && name === "length")
70
- return target.length;
71
- return target.props.get(name);
148
+ const slot = own(target, key);
149
+ return slot === undefined ? undefined : read(slot, target);
72
150
  };
73
- 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) => {
74
153
  for (let current = target; current !== null; current = current.proto) {
75
- if (hasOwn(current, key))
76
- return getOwn(current, key);
154
+ const slot = own(current, key);
155
+ if (slot !== undefined)
156
+ return read(slot, receiver);
77
157
  }
78
158
  return undefined;
79
159
  };
80
- export const hasPrototype = (value, proto) => {
81
- for (let current = value instanceof ProgramObject ? value.proto : null; current !== null; current = current.proto) {
82
- if (current === proto)
160
+ export const has = (target, key) => {
161
+ for (let current = target; current !== null; current = current.proto) {
162
+ if (own(current, key) !== undefined)
83
163
  return true;
84
164
  }
85
165
  return false;
86
166
  };
87
- export const has = (target, key) => {
88
- for (let current = target; current !== null; current = current.proto) {
89
- if (hasOwn(current, 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)
90
170
  return true;
91
171
  }
92
172
  return false;
93
173
  };
94
- export const set = (target, key, value) => {
95
- const name = canonical(key);
174
+ const writeArray = (target, name, value) => {
96
175
  const at = index(target, name);
97
176
  if (at !== undefined) {
98
- ;
99
177
  target.items[at] = value;
100
178
  return true;
101
179
  }
102
- if (name === "length" && target instanceof ProgramArray) {
103
- const length = typeof value === "number" ? value : Number(value);
104
- 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)
105
202
  return false;
106
- 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;
107
211
  return true;
108
212
  }
109
- if (builtin(target, name))
110
- return false;
111
- 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 });
112
219
  return true;
113
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
+ };
114
231
  export const remove = (target, key) => {
115
232
  const name = canonical(key);
116
- const at = index(target, name);
117
- if (at !== undefined)
118
- return delete target.items[at];
119
- if (name === "length" && target instanceof ProgramArray)
120
- return false;
121
- 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)
122
242
  return true;
243
+ if (!slot.configurable)
244
+ return false;
123
245
  target.props.delete(name);
124
246
  return true;
125
247
  };
@@ -128,27 +250,29 @@ export const ownKeys = (target) => {
128
250
  const strings = [...target.props.keys()].filter((key) => typeof key === "string");
129
251
  const symbols = [...target.props.keys()].filter((key) => typeof key === "symbol");
130
252
  return [
131
- ...(target instanceof ProgramArray ? Object.keys(target.items) : []),
253
+ ...(target instanceof ProgramArray ? [...Object.keys(target.items), "length"] : []),
132
254
  ...strings.filter((key) => parseArrayIndex(key) !== undefined).sort((a, b) => Number(a) - Number(b)),
133
255
  ...strings.filter((key) => parseArrayIndex(key) === undefined),
134
256
  ...symbols,
135
257
  ];
136
258
  };
137
- export const ownEntries = (target) => ownKeys(target)
138
- .filter((key) => typeof key === "string")
139
- .map((key) => [key, getOwn(target, key)]);
140
- export const record = (entries) => {
141
- const target = new ProgramObject();
142
- for (const [key, value] of Object.entries(entries))
143
- 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);
144
270
  return target;
145
271
  };
146
272
  export const assign = (target, source, skip) => {
147
- for (const key of ownKeys(source)) {
273
+ for (const key of enumerableKeys(source)) {
148
274
  if (skip?.has(key))
149
275
  continue;
150
- if (typeof key === "symbol" && key !== IteratorSymbol && key !== AsyncIteratorSymbol)
151
- continue;
152
276
  set(target, key, getOwn(source, key));
153
277
  }
154
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,26 +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";
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
5
  import { caughtErrorValue, createAggregateErrorValue, normalizeError } from "./errors.js";
6
6
  import { typeofValue } from "./references.js";
7
- import { Values } from "../values.js";
8
7
  import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
9
8
  // A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
10
- const capability = (name, settle) => sync(name, (args) => {
9
+ const capability = (runner, name, settle) => fn(runner.prototypes, name, 1, (_, args) => {
11
10
  settle(args[0]);
12
11
  return undefined;
13
12
  });
14
13
  // Observation only controls rejection reporting; program completion interrupts all promise work.
15
14
  export class PromiseRuntime {
16
15
  scope;
16
+ proto;
17
17
  active = new Set();
18
18
  ids = new WeakMap();
19
19
  observed = new WeakSet();
20
20
  failures = new Map();
21
21
  nextID = 0;
22
- constructor(scope) {
22
+ constructor(scope, proto) {
23
23
  this.scope = scope;
24
+ this.proto = proto;
24
25
  }
25
26
  // Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
26
27
  createWithSelf(body) {
@@ -35,7 +36,7 @@ export class PromiseRuntime {
35
36
  // Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
36
37
  const id = this.nextID++;
37
38
  return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
38
- const promise = new Values.Promise(fiber);
39
+ const promise = new ProgramPromise(this.proto, fiber);
39
40
  this.active.add(promise);
40
41
  this.ids.set(promise, id);
41
42
  fiber.addObserver((exit) => {
@@ -86,7 +87,7 @@ export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaini
86
87
  export const resolvePromiseValue = (runner, value, node, own) => {
87
88
  if (own?.promise !== undefined && value === own.promise)
88
89
  return Effect.fail(selfResolutionError(node));
89
- if (value instanceof Values.Promise)
90
+ if (value instanceof ProgramPromise)
90
91
  return runner.settlePromise(value);
91
92
  if (!(value instanceof ProgramObject))
92
93
  return Effect.succeed(value);
@@ -97,9 +98,9 @@ export const resolvePromiseValue = (runner, value, node, own) => {
97
98
  // Promise resolution invokes a thenable's method in a later job.
98
99
  yield* Effect.yieldNow;
99
100
  const deferred = Deferred.makeUnsafe();
100
- const resolve = capability("resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
101
- const reject = capability("reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason))));
102
- 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));
103
104
  if (!Exit.isSuccess(executed)) {
104
105
  if (Cause.hasInterruptsOnly(executed.cause))
105
106
  return yield* Effect.failCause(executed.cause);
@@ -109,7 +110,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
109
110
  });
110
111
  };
111
112
  export const resolvePromise = (runner, promises, value, node) => {
112
- if (value instanceof Values.Promise)
113
+ if (value instanceof ProgramPromise)
113
114
  return Effect.succeed(value);
114
115
  return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
115
116
  };
@@ -136,22 +137,25 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
136
137
  items.push(item);
137
138
  }
138
139
  if (name === "all") {
139
- 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" })));
140
141
  }
141
142
  if (name === "allSettled") {
142
143
  const outcomes = [];
143
144
  for (const item of items) {
144
145
  const exit = yield* promises.await(item);
145
146
  if (Exit.isSuccess(exit)) {
146
- outcomes.push(record({ status: "fulfilled", value: exit.value }));
147
+ outcomes.push(record(runner.prototypes.Object, { status: "fulfilled", value: exit.value }));
147
148
  continue;
148
149
  }
149
150
  if (Cause.hasInterruptsOnly(exit.cause))
150
151
  return yield* Effect.failCause(exit.cause);
151
- outcomes.push(record({ status: "rejected", reason: caughtErrorValue(runner, Cause.squash(exit.cause)) }));
152
+ outcomes.push(record(runner.prototypes.Object, {
153
+ status: "rejected",
154
+ reason: caughtErrorValue(runner, Cause.squash(exit.cause)),
155
+ }));
152
156
  }
153
157
  yield* Effect.yieldNow;
154
- return new ProgramArray(outcomes);
158
+ return new ProgramArray(runner.prototypes.Array, outcomes);
155
159
  }
156
160
  if (name === "race") {
157
161
  if (items.length === 0) {
@@ -169,15 +173,16 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
169
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))));
170
174
  }));
171
175
  };
172
- export const invokePromiseInstanceMethod = (runner, promises, ref, args, node) => {
173
- const method = `Promise.prototype.${ref.name}`;
174
- promises.markObserved(ref.promise);
175
- if (ref.name === "finally") {
176
- 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);
177
182
  }
178
- const onFulfilled = ref.name === "then" ? reactionHandler(args[0], method, node) : undefined;
179
- const onRejected = reactionHandler(ref.name === "then" ? args[1] : args[0], method, node);
180
- 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);
181
186
  };
182
187
  const constructPromise = (runner, promises, executor, node) => {
183
188
  if (!(executor instanceof ProgramFunction)) {
@@ -186,9 +191,9 @@ const constructPromise = (runner, promises, executor, node) => {
186
191
  return Effect.gen(function* () {
187
192
  const deferred = Deferred.makeUnsafe();
188
193
  const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
189
- const resolve = capability("resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
190
- const reject = capability("reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
191
- 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));
192
197
  if (!Exit.isSuccess(executed)) {
193
198
  if (Cause.hasInterruptsOnly(executed.cause))
194
199
  return yield* Effect.failCause(executed.cause);
@@ -245,26 +250,27 @@ const chainFinally = (runner, promises, source, cleanup, method, node) => promis
245
250
  return yield* exit;
246
251
  }));
247
252
  export const promiseGlobal = (runner, promises) => {
248
- // Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
249
- const statics = new Map(promiseStatics.map((name) => [
250
- name,
251
- new HostFunction({
252
- name: `Promise.${name}`,
253
- call: (args, node) => invokePromiseMethod(runner, promises, name, args, node),
254
- callback: false,
255
- }),
256
- ]));
257
- return new HostFunction({
253
+ const protos = runner.prototypes;
254
+ const proto = protos.Promise;
255
+ const promise = constructor(protos, proto, {
258
256
  name: "Promise",
257
+ length: 1,
259
258
  call: requiresNew("Promise"),
260
- construct: (args, node) => constructPromise(runner, promises, args[0], node),
261
- instanceOf: (value) => value instanceof Values.Promise,
262
- // Unknown statics fail loudly so a missing await cannot hide behind `undefined`.
263
- members: (key, node) => {
264
- const method = typeof key === "string" ? statics.get(key) : undefined;
265
- if (method !== undefined)
266
- return method;
267
- 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);
268
- },
259
+ construct: (args, _, node) => constructPromise(runner, promises, args[0], node),
269
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;
270
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;