@opencode/codemode 2.0.3 → 2.0.4

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 (71) hide show
  1. package/dist/codemode.d.ts +3 -0
  2. package/dist/codemode.js +12 -1
  3. package/dist/data.d.ts +14 -21
  4. package/dist/data.js +72 -140
  5. package/dist/extension.d.ts +11 -0
  6. package/dist/extension.js +9 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/interpreter/callback.d.ts +20 -0
  10. package/dist/interpreter/{runner.js → callback.js} +14 -14
  11. package/dist/interpreter/errors.d.ts +12 -5
  12. package/dist/interpreter/errors.js +66 -54
  13. package/dist/interpreter/execute.d.ts +2 -2
  14. package/dist/interpreter/execute.js +15 -15
  15. package/dist/interpreter/extensions.d.ts +8 -0
  16. package/dist/interpreter/extensions.js +155 -0
  17. package/dist/interpreter/generators.d.ts +2 -3
  18. package/dist/interpreter/generators.js +10 -10
  19. package/dist/interpreter/globals.d.ts +4 -12
  20. package/dist/interpreter/globals.js +56 -49
  21. package/dist/interpreter/interpreter.d.ts +34 -0
  22. package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
  23. package/dist/interpreter/intrinsics.d.ts +5 -5
  24. package/dist/interpreter/intrinsics.js +16 -10
  25. package/dist/interpreter/limits.d.ts +10 -0
  26. package/dist/interpreter/limits.js +19 -0
  27. package/dist/interpreter/model.d.ts +27 -14
  28. package/dist/interpreter/model.js +22 -14
  29. package/dist/interpreter/native.d.ts +12 -13
  30. package/dist/interpreter/native.js +17 -16
  31. package/dist/interpreter/objects.d.ts +55 -48
  32. package/dist/interpreter/objects.js +64 -44
  33. package/dist/interpreter/promises.d.ts +13 -15
  34. package/dist/interpreter/promises.js +89 -85
  35. package/dist/interpreter/references.d.ts +1 -2
  36. package/dist/interpreter/references.js +18 -16
  37. package/dist/interpreter/scope.js +6 -6
  38. package/dist/openapi/types.d.ts +1 -1
  39. package/dist/stdlib/array.d.ts +3 -4
  40. package/dist/stdlib/array.js +115 -110
  41. package/dist/stdlib/bytes.d.ts +10 -0
  42. package/dist/stdlib/bytes.js +228 -0
  43. package/dist/stdlib/collections.d.ts +4 -4
  44. package/dist/stdlib/collections.js +89 -89
  45. package/dist/stdlib/console.d.ts +5 -3
  46. package/dist/stdlib/console.js +30 -37
  47. package/dist/stdlib/date.d.ts +2 -2
  48. package/dist/stdlib/date.js +35 -35
  49. package/dist/stdlib/json.d.ts +3 -3
  50. package/dist/stdlib/json.js +29 -67
  51. package/dist/stdlib/math.d.ts +3 -3
  52. package/dist/stdlib/math.js +17 -21
  53. package/dist/stdlib/number.d.ts +3 -3
  54. package/dist/stdlib/number.js +32 -36
  55. package/dist/stdlib/object.d.ts +5 -5
  56. package/dist/stdlib/object.js +59 -62
  57. package/dist/stdlib/regexp.d.ts +7 -8
  58. package/dist/stdlib/regexp.js +40 -48
  59. package/dist/stdlib/string.d.ts +2 -2
  60. package/dist/stdlib/string.js +110 -88
  61. package/dist/stdlib/url.d.ts +4 -6
  62. package/dist/stdlib/url.js +86 -90
  63. package/dist/stdlib/value.d.ts +3 -3
  64. package/dist/stdlib/value.js +26 -24
  65. package/dist/stdlib/web.d.ts +4 -4
  66. package/dist/stdlib/web.js +22 -8
  67. package/dist/tool-runtime.d.ts +12 -5
  68. package/dist/tool-runtime.js +25 -11
  69. package/package.json +1 -1
  70. package/dist/interpreter/runner.d.ts +0 -28
  71. package/dist/interpreter/runtime.d.ts +0 -19
@@ -1,4 +1,5 @@
1
- import { AsyncIteratorSymbol, IteratorSymbol } from "./model.js";
1
+ import { checkArrayLength } from "./limits.js";
2
+ import { AsyncIteratorSymbol, IteratorSymbol, } from "./model.js";
2
3
  /** Ordinary assignment: writable, enumerable, configurable. */
3
4
  export const data = { writable: true, enumerable: true, configurable: true };
4
5
  /** Built-in methods and `constructor`: writable and configurable but hidden from enumeration. */
@@ -8,14 +9,14 @@ export const readonly = { writable: false, enumerable: false, configurable: true
8
9
  /** Constants such as `Math.PI` and a constructor's `prototype`. */
9
10
  export const frozen = { writable: false, enumerable: false, configurable: false };
10
11
  /** An object owned by the program: own properties plus a prototype link. */
11
- export class ProgramObject {
12
+ export class Obj {
12
13
  proto;
13
14
  props = new Map();
14
15
  constructor(proto) {
15
16
  this.proto = proto;
16
17
  }
17
18
  }
18
- export class ProgramArray extends ProgramObject {
19
+ export class Arr extends Obj {
19
20
  items;
20
21
  constructor(proto, items = []) {
21
22
  super(proto);
@@ -23,16 +24,18 @@ export class ProgramArray extends ProgramObject {
23
24
  }
24
25
  }
25
26
  /** An object with the [[ErrorData]] slot: what `Error.prototype.toString` and the host boundary recognize as an error. */
26
- export class ProgramError extends ProgramObject {
27
+ export class ErrorObj extends Obj {
28
+ /** The interpreter failure this error materialized from, so rethrowing it keeps the diagnostic kind and location. */
29
+ host;
27
30
  }
28
- export class Callable extends ProgramObject {
31
+ export class Callable extends Obj {
29
32
  constructor(proto, name, length) {
30
33
  super(proto);
31
34
  define(this, "length", length, readonly);
32
35
  define(this, "name", name, readonly);
33
36
  }
34
37
  }
35
- export class ProgramFunction extends Callable {
38
+ export class Fn extends Callable {
36
39
  parameters;
37
40
  body;
38
41
  capturedScopes;
@@ -48,7 +51,7 @@ export class ProgramFunction extends Callable {
48
51
  this.generator = generator;
49
52
  }
50
53
  }
51
- export class NativeFunction extends Callable {
54
+ export class Native extends Callable {
52
55
  call;
53
56
  construct;
54
57
  callback;
@@ -59,14 +62,14 @@ export class NativeFunction extends Callable {
59
62
  this.callback = options.callback ?? true;
60
63
  }
61
64
  }
62
- export class ProgramPromise extends ProgramObject {
65
+ export class PromiseObj extends Obj {
63
66
  fiber;
64
67
  constructor(proto, fiber) {
65
68
  super(proto);
66
69
  this.fiber = fiber;
67
70
  }
68
71
  }
69
- export class ProgramGenerator extends ProgramObject {
72
+ export class GeneratorObj extends Obj {
70
73
  asynchronous;
71
74
  request;
72
75
  constructor(proto, asynchronous, request) {
@@ -75,70 +78,82 @@ export class ProgramGenerator extends ProgramObject {
75
78
  this.request = request;
76
79
  }
77
80
  }
78
- export class ProgramDate extends ProgramObject {
81
+ export class DateObj extends Obj {
79
82
  time;
80
83
  constructor(proto, time) {
81
84
  super(proto);
82
85
  this.time = time;
83
86
  }
84
87
  }
85
- export class ProgramRegExp extends ProgramObject {
88
+ export class RegExpObj extends Obj {
86
89
  regex;
87
90
  constructor(proto, pattern, flags) {
88
91
  super(proto);
89
92
  this.regex = new RegExp(pattern, flags);
90
- define(this, "lastIndex", 0, { writable: true, enumerable: false, configurable: false });
91
93
  }
92
94
  }
93
- export class ProgramMap extends ProgramObject {
95
+ export class MapObj extends Obj {
94
96
  map = new Map();
95
97
  }
96
- export class ProgramSet extends ProgramObject {
98
+ export class SetObj extends Obj {
97
99
  set = new Set();
98
100
  }
99
- export class ProgramURLSearchParams extends ProgramObject {
101
+ export class URLSearchParamsObj extends Obj {
100
102
  params;
101
103
  constructor(proto, params) {
102
104
  super(proto);
103
105
  this.params = params;
104
106
  }
105
107
  }
106
- export class ProgramURL extends ProgramObject {
108
+ export class URLObj extends Obj {
107
109
  url;
108
110
  searchParams;
109
111
  constructor(proto, searchParamsProto, url) {
110
112
  super(proto);
111
113
  this.url = url;
112
- this.searchParams = new ProgramURLSearchParams(searchParamsProto, url.searchParams);
114
+ this.searchParams = new URLSearchParamsObj(searchParamsProto, url.searchParams);
115
+ }
116
+ }
117
+ /** A `Uint8Array`: the host array does the byte clamping and ignores out-of-range writes, as JS does. */
118
+ export class Bytes extends Obj {
119
+ bytes;
120
+ constructor(proto, bytes) {
121
+ super(proto);
122
+ this.bytes = bytes;
113
123
  }
114
124
  }
115
125
  /** 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;
122
- const MAX_ARRAY_LENGTH = 4_294_967_295;
126
+ export const isWrapper = (value) => value instanceof DateObj ||
127
+ value instanceof RegExpObj ||
128
+ value instanceof MapObj ||
129
+ value instanceof SetObj ||
130
+ value instanceof URLObj ||
131
+ value instanceof URLSearchParamsObj ||
132
+ value instanceof Bytes;
133
+ const MAX_ARRAY_INDEX = 4_294_967_295;
123
134
  export const parseArrayIndex = (key) => {
124
135
  const property = String(key);
125
136
  if (!/^(0|[1-9]\d*)$/.test(property))
126
137
  return undefined;
127
138
  const index = Number(property);
128
- return index < MAX_ARRAY_LENGTH ? index : undefined;
139
+ return index < MAX_ARRAY_INDEX ? index : undefined;
129
140
  };
130
141
  const canonical = (key) => (typeof key === "symbol" ? key : String(key));
131
- const index = (target, key) => target instanceof ProgramArray && typeof key === "string" ? parseArrayIndex(key) : undefined;
142
+ const isIndexed = (target) => target instanceof Arr || target instanceof Bytes;
143
+ const elements = (target) => (target instanceof Arr ? target.items : target.bytes);
144
+ const index = (target, key) => isIndexed(target) && typeof key === "string" ? parseArrayIndex(key) : undefined;
132
145
  /** The own property under `key`, including an array's live indexes and `length`. */
133
146
  export const own = (target, key) => {
134
147
  const name = canonical(key);
135
- if (target instanceof ProgramArray) {
148
+ if (isIndexed(target)) {
136
149
  const at = index(target, name);
137
150
  if (at !== undefined) {
138
- return at in target.items ? { value: target.items[at], ...data } : undefined;
151
+ const items = elements(target);
152
+ return at in items ? { value: items[at], ...data } : undefined;
139
153
  }
140
- if (name === "length")
154
+ if (target instanceof Arr && name === "length") {
141
155
  return { value: target.items.length, writable: true, enumerable: false, configurable: false };
156
+ }
142
157
  }
143
158
  return target.props.get(name);
144
159
  };
@@ -165,23 +180,27 @@ export const has = (target, key) => {
165
180
  return false;
166
181
  };
167
182
  export const hasPrototype = (value, proto) => {
168
- for (let current = value instanceof ProgramObject ? value.proto : null; current !== null; current = current.proto) {
183
+ for (let current = value instanceof Obj ? value.proto : null; current !== null; current = current.proto) {
169
184
  if (current === proto)
170
185
  return true;
171
186
  }
172
187
  return false;
173
188
  };
174
- const writeArray = (target, name, value) => {
189
+ const writeElement = (target, name, value) => {
175
190
  const at = index(target, name);
176
191
  if (at !== undefined) {
177
- target.items[at] = value;
192
+ if (target instanceof Bytes)
193
+ target.bytes[at] = typeof value === "number" ? value : Number(value);
194
+ else
195
+ target.items[at] = value;
178
196
  return true;
179
197
  }
180
- if (name !== "length")
198
+ if (!(target instanceof Arr) || name !== "length")
181
199
  return undefined;
182
200
  const length = typeof value === "number" ? value : Number(value);
183
- if (!Number.isInteger(length) || length < 0 || length > MAX_ARRAY_LENGTH)
201
+ if (!Number.isInteger(length) || length < 0)
184
202
  return false;
203
+ checkArrayLength(length);
185
204
  target.items.length = length;
186
205
  return true;
187
206
  };
@@ -202,16 +221,16 @@ export const set = (target, key, value) => {
202
221
  return false;
203
222
  if (current !== target)
204
223
  break;
205
- if (target instanceof ProgramArray) {
206
- const written = writeArray(target, name, value);
224
+ if (isIndexed(target)) {
225
+ const written = writeElement(target, name, value);
207
226
  if (written !== undefined)
208
227
  return written;
209
228
  }
210
229
  slot.value = value;
211
230
  return true;
212
231
  }
213
- if (target instanceof ProgramArray) {
214
- const written = writeArray(target, name, value);
232
+ if (isIndexed(target)) {
233
+ const written = writeElement(target, name, value);
215
234
  if (written !== undefined)
216
235
  return written;
217
236
  }
@@ -221,7 +240,7 @@ export const set = (target, key, value) => {
221
240
  /** [[DefineOwnProperty]] for a data property, ignoring the chain. */
222
241
  export const define = (target, key, value, attrs = data) => {
223
242
  const name = canonical(key);
224
- if (target instanceof ProgramArray && writeArray(target, name, value) !== undefined)
243
+ if (isIndexed(target) && writeElement(target, name, value) !== undefined)
225
244
  return;
226
245
  target.props.set(name, { value, ...attrs });
227
246
  };
@@ -230,11 +249,11 @@ export const defineAccessor = (target, key, get, set) => {
230
249
  };
231
250
  export const remove = (target, key) => {
232
251
  const name = canonical(key);
233
- if (target instanceof ProgramArray) {
252
+ if (isIndexed(target)) {
234
253
  const at = index(target, name);
235
254
  if (at !== undefined)
236
- return delete target.items[at];
237
- if (name === "length")
255
+ return target instanceof Bytes ? !(at in target.bytes) : delete target.items[at];
256
+ if (target instanceof Arr && name === "length")
238
257
  return false;
239
258
  }
240
259
  const slot = target.props.get(name);
@@ -250,7 +269,8 @@ export const ownKeys = (target) => {
250
269
  const strings = [...target.props.keys()].filter((key) => typeof key === "string");
251
270
  const symbols = [...target.props.keys()].filter((key) => typeof key === "symbol");
252
271
  return [
253
- ...(target instanceof ProgramArray ? [...Object.keys(target.items), "length"] : []),
272
+ ...(isIndexed(target) ? Object.keys(elements(target)) : []),
273
+ ...(target instanceof Arr ? ["length"] : []),
254
274
  ...strings.filter((key) => parseArrayIndex(key) !== undefined).sort((a, b) => Number(a) - Number(b)),
255
275
  ...strings.filter((key) => parseArrayIndex(key) === undefined),
256
276
  ...symbols,
@@ -264,7 +284,7 @@ export const keys = (target) => ownKeys(target).filter((key) => typeof key === "
264
284
  /** Own enumerable string entries: `Object.entries` and serialization. */
265
285
  export const entries = (target) => keys(target).map((key) => [key, getOwn(target, key)]);
266
286
  export const record = (proto, fields) => {
267
- const target = new ProgramObject(proto);
287
+ const target = new Obj(proto);
268
288
  for (const [key, value] of Object.entries(fields))
269
289
  define(target, key, value);
270
290
  return target;
@@ -1,9 +1,8 @@
1
1
  import { Effect, Exit, Scope } from "effect";
2
2
  import type { Diagnostic } from "../codemode.js";
3
- import { type AstNode, InterpreterRuntimeError } from "./model.js";
4
- import { ProgramObject, ProgramPromise } from "./objects.js";
5
- import { type Runner } from "./runner.js";
6
- export declare class PromiseRuntime<R> {
3
+ import { Obj, PromiseObj } from "./objects.js";
4
+ import type { Interpreter } from "./interpreter.js";
5
+ export declare class Pending<R> {
7
6
  private readonly scope;
8
7
  private readonly proto;
9
8
  private readonly active;
@@ -11,20 +10,19 @@ export declare class PromiseRuntime<R> {
11
10
  private readonly observed;
12
11
  private readonly failures;
13
12
  private nextID;
14
- constructor(scope: Scope.Scope, proto: ProgramObject);
13
+ constructor(scope: Scope.Scope, proto: Obj);
15
14
  createWithSelf(body: (self: {
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>>;
15
+ promise?: PromiseObj;
16
+ }) => Effect.Effect<unknown, unknown, R>): Effect.Effect<PromiseObj, never, R>;
17
+ create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<PromiseObj, never, R>;
18
+ markObserved(promise: PromiseObj): void;
19
+ await(promise: PromiseObj): Effect.Effect<Exit.Exit<unknown, unknown>>;
21
20
  fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
22
21
  diagnostics(): Array<Diagnostic>;
23
22
  interrupt(): Effect.Effect<Array<Diagnostic>>;
24
23
  }
25
- export declare const selfResolutionError: (node?: AstNode) => InterpreterRuntimeError;
26
- export declare const resolvePromiseValue: <R>(runner: Runner<R>, value: unknown, node: AstNode, own?: {
27
- promise?: ProgramPromise;
24
+ export declare const resolvePromiseValue: <R>(ctx: Interpreter<R>, value: unknown, own?: {
25
+ promise?: PromiseObj;
28
26
  }) => Effect.Effect<unknown, unknown, 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>;
27
+ export declare const resolvePromise: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<PromiseObj, never, R>;
28
+ export declare const promiseGlobal: <R>(ctx: Interpreter<R>) => import("./objects.js").Native<R>;
@@ -1,17 +1,18 @@
1
1
  import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
2
- import { InterpreterRuntimeError, ProgramThrow } from "./model.js";
3
- import { Callable, define, get, hidden, ProgramArray, ProgramFunction, ProgramObject, ProgramPromise, record, } from "./objects.js";
2
+ import { MAX_PENDING_PROMISES } from "./limits.js";
3
+ import { CallSite, Throw, rangeError, typeError } from "./model.js";
4
+ import { Callable, define, get, hidden, Arr, Fn, Obj, PromiseObj, record } from "./objects.js";
4
5
  import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
5
- import { caughtErrorValue, createAggregateErrorValue, normalizeError } from "./errors.js";
6
+ import { createAggregateErrorValue, locate, materialize, normalizeError } from "./errors.js";
6
7
  import { typeofValue } from "./references.js";
7
- import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
8
+ import { applyCollectionCallback, isSupportedCallback } from "./callback.js";
8
9
  // A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
9
- const capability = (runner, name, settle) => fn(runner.prototypes, name, 1, (_, args) => {
10
+ const capability = (ctx, name, settle) => fn(ctx.builtins, name, 1, (_, args) => {
10
11
  settle(args[0]);
11
12
  return undefined;
12
13
  });
13
14
  // Observation only controls rejection reporting; program completion interrupts all promise work.
14
- export class PromiseRuntime {
15
+ export class Pending {
15
16
  scope;
16
17
  proto;
17
18
  active = new Set();
@@ -32,11 +33,15 @@ export class PromiseRuntime {
32
33
  });
33
34
  }
34
35
  create(effect) {
35
- return Effect.suspend(() => {
36
+ return Effect.flatMap(CallSite, (site) => {
37
+ if (this.active.size >= MAX_PENDING_PROMISES) {
38
+ throw rangeError(`Too many pending promises (limit ${MAX_PENDING_PROMISES}); await promises before creating more.`);
39
+ }
36
40
  // Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
37
41
  const id = this.nextID++;
38
- return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
39
- const promise = new ProgramPromise(this.proto, fiber);
42
+ const body = Effect.catchDefect(effect, (defect) => Effect.die(locate(defect, site.node)));
43
+ return Effect.map(Effect.forkIn(body, this.scope, { startImmediately: true }), (fiber) => {
44
+ const promise = new PromiseObj(this.proto, fiber);
40
45
  this.active.add(promise);
41
46
  this.ids.set(promise, id);
42
47
  fiber.addObserver((exit) => {
@@ -83,13 +88,13 @@ export class PromiseRuntime {
83
88
  });
84
89
  }
85
90
  }
86
- export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaining cycle detected: a promise cannot resolve with itself.", node);
87
- export const resolvePromiseValue = (runner, value, node, own) => {
88
- if (own?.promise !== undefined && value === own.promise)
89
- return Effect.fail(selfResolutionError(node));
90
- if (value instanceof ProgramPromise)
91
- return runner.settlePromise(value);
92
- if (!(value instanceof ProgramObject))
91
+ export const resolvePromiseValue = (ctx, value, own) => {
92
+ if (own?.promise !== undefined && value === own.promise) {
93
+ return Effect.die(typeError("Chaining cycle detected: a promise cannot resolve with itself."));
94
+ }
95
+ if (value instanceof PromiseObj)
96
+ return ctx.await(value);
97
+ if (!(value instanceof Obj))
93
98
  return Effect.succeed(value);
94
99
  const then = get(value, "then");
95
100
  if (typeofValue(then) !== "function")
@@ -98,102 +103,101 @@ export const resolvePromiseValue = (runner, value, node, own) => {
98
103
  // Promise resolution invokes a thenable's method in a later job.
99
104
  yield* Effect.yieldNow;
100
105
  const deferred = Deferred.makeUnsafe();
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));
106
+ const resolve = capability(ctx, "resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
107
+ const reject = capability(ctx, "reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(reason))));
108
+ const executed = yield* Effect.exit(ctx.call(then, value, [resolve, reject]));
104
109
  if (!Exit.isSuccess(executed)) {
105
110
  if (Cause.hasInterruptsOnly(executed.cause))
106
111
  return yield* Effect.failCause(executed.cause);
107
112
  Deferred.doneUnsafe(deferred, Exit.fail(Cause.squash(executed.cause)));
108
113
  }
109
- return yield* resolvePromiseValue(runner, yield* Deferred.await(deferred), node, own);
114
+ return yield* resolvePromiseValue(ctx, yield* Deferred.await(deferred), own);
110
115
  });
111
116
  };
112
- export const resolvePromise = (runner, promises, value, node) => {
113
- if (value instanceof ProgramPromise)
117
+ export const resolvePromise = (ctx, value) => {
118
+ if (value instanceof PromiseObj)
114
119
  return Effect.succeed(value);
115
- return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
120
+ return ctx.pending.createWithSelf((self) => resolvePromiseValue(ctx, value, self));
116
121
  };
117
122
  const promiseStatics = ["all", "allSettled", "race", "any", "resolve", "reject"];
118
- const invokePromiseMethod = (runner, promises, name, args, node) => {
123
+ const invokePromiseMethod = (ctx, name, args) => {
119
124
  if (name === "resolve") {
120
- return resolvePromise(runner, promises, args[0], node);
125
+ return resolvePromise(ctx, args[0]);
121
126
  }
122
127
  if (name === "reject") {
123
- return promises.create(Effect.fail(new ProgramThrow(args[0])));
128
+ return ctx.pending.create(Effect.fail(new Throw(args[0])));
124
129
  }
125
- return promises.create(Effect.gen(function* () {
126
- const cursor = yield* runner.syncIterator(args[0], node);
127
- if (cursor === undefined) {
128
- throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node);
129
- }
130
+ return ctx.pending.create(Effect.gen(function* () {
131
+ const cursor = yield* ctx.iterate(args[0]);
132
+ if (cursor === undefined)
133
+ throw typeError(`Promise.${name} expects an array or other synchronous iterable.`);
130
134
  const items = [];
131
135
  while (true) {
132
136
  const step = yield* cursor.next;
133
137
  if (step.done)
134
138
  break;
135
- const item = yield* resolvePromise(runner, promises, step.value, node);
136
- promises.markObserved(item);
139
+ const item = yield* resolvePromise(ctx, step.value);
140
+ ctx.pending.markObserved(item);
137
141
  items.push(item);
138
142
  }
139
143
  if (name === "all") {
140
- return new ProgramArray(runner.prototypes.Array, yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
144
+ return new Arr(ctx.builtins.Array, yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(ctx.pending.await(item))), { concurrency: "unbounded" })));
141
145
  }
142
146
  if (name === "allSettled") {
143
147
  const outcomes = [];
144
148
  for (const item of items) {
145
- const exit = yield* promises.await(item);
149
+ const exit = yield* ctx.pending.await(item);
146
150
  if (Exit.isSuccess(exit)) {
147
- outcomes.push(record(runner.prototypes.Object, { status: "fulfilled", value: exit.value }));
151
+ outcomes.push(record(ctx.builtins.Object, { status: "fulfilled", value: exit.value }));
148
152
  continue;
149
153
  }
150
154
  if (Cause.hasInterruptsOnly(exit.cause))
151
155
  return yield* Effect.failCause(exit.cause);
152
- outcomes.push(record(runner.prototypes.Object, {
156
+ outcomes.push(record(ctx.builtins.Object, {
153
157
  status: "rejected",
154
- reason: caughtErrorValue(runner, Cause.squash(exit.cause)),
158
+ reason: materialize(ctx, Cause.squash(exit.cause)),
155
159
  }));
156
160
  }
157
161
  yield* Effect.yieldNow;
158
- return new ProgramArray(runner.prototypes.Array, outcomes);
162
+ return new Arr(ctx.builtins.Array, outcomes);
159
163
  }
160
164
  if (name === "race") {
161
165
  if (items.length === 0) {
162
- throw new InterpreterRuntimeError("Promise.race([]) would never settle; provide at least one promise or value.", node);
166
+ throw typeError("Promise.race([]) would never settle; provide at least one promise or value.");
163
167
  }
164
- return yield* settleAfterTurn(Effect.flatten(Effect.raceAll(items.map((item) => promises.await(item)))));
168
+ return yield* settleAfterTurn(Effect.flatten(Effect.raceAll(items.map((item) => ctx.pending.await(item)))));
165
169
  }
166
- const flipped = items.map((item) => Effect.flatMap(promises.await(item), (exit) => {
170
+ const flipped = items.map((item) => Effect.flatMap(ctx.pending.await(item), (exit) => {
167
171
  if (Exit.isSuccess(exit))
168
172
  return Effect.fail(new PromiseAnyFulfilled(exit.value));
169
173
  if (Cause.hasInterruptsOnly(exit.cause))
170
174
  return Effect.failCause(exit.cause);
171
- return Effect.succeed(caughtErrorValue(runner, Cause.squash(exit.cause)));
175
+ return Effect.succeed(materialize(ctx, Cause.squash(exit.cause)));
172
176
  }));
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))));
177
+ return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new Throw(createAggregateErrorValue(ctx, reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
174
178
  }));
175
179
  };
176
- const instanceMethod = (runner, promises, name, thisValue, args, node) => {
180
+ const instanceMethod = (ctx, name, thisValue, args) => {
177
181
  const method = `Promise.prototype.${name}`;
178
- const promise = receiver(ProgramPromise, thisValue, method, node);
179
- promises.markObserved(promise);
182
+ const promise = receiver(PromiseObj, thisValue, method);
183
+ ctx.pending.markObserved(promise);
180
184
  if (name === "finally") {
181
- return chainFinally(runner, promises, promise, reactionHandler(args[0], method, node), method, node);
185
+ return chainFinally(ctx, promise, reactionHandler(args[0], method), method);
182
186
  }
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);
187
+ const onFulfilled = name === "then" ? reactionHandler(args[0], method) : undefined;
188
+ const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method);
189
+ return chainReaction(ctx, promise, onFulfilled, onRejected, method);
186
190
  };
187
- const constructPromise = (runner, promises, executor, node) => {
188
- if (!(executor instanceof ProgramFunction)) {
189
- throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node);
191
+ const constructPromise = (ctx, executor) => {
192
+ if (!(executor instanceof Fn)) {
193
+ throw typeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).");
190
194
  }
191
195
  return Effect.gen(function* () {
192
196
  const deferred = Deferred.makeUnsafe();
193
- const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
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));
197
+ const promise = yield* ctx.pending.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(ctx, value, self)));
198
+ const resolve = capability(ctx, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
199
+ const reject = capability(ctx, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new Throw(value))));
200
+ const executed = yield* Effect.exit(ctx.call(executor, undefined, [resolve, reject]));
197
201
  if (!Exit.isSuccess(executed)) {
198
202
  if (Cause.hasInterruptsOnly(executed.cause))
199
203
  return yield* Effect.failCause(executed.cause);
@@ -210,67 +214,67 @@ class PromiseAnyFulfilled {
210
214
  this.value = value;
211
215
  }
212
216
  }
213
- const reactionHandler = (value, method, node) => {
217
+ const reactionHandler = (value, method) => {
214
218
  if (isSupportedCallback(value))
215
219
  return value;
216
220
  if (typeofValue(value) === "function") {
217
- throw new InterpreterRuntimeError(`${method} cannot use this callable as a handler; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`, node);
221
+ throw typeError(`${method} cannot use this callable as a handler; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`);
218
222
  }
219
223
  return undefined;
220
224
  };
221
225
  // Teardown bypasses handlers; settled reactions yield once so handlers never run inline.
222
- const reactionExit = (promises, source) => Effect.gen(function* () {
223
- const exit = yield* promises.await(source);
226
+ const reactionExit = (ctx, source) => Effect.gen(function* () {
227
+ const exit = yield* ctx.pending.await(source);
224
228
  if (!Exit.isSuccess(exit) && Cause.hasInterruptsOnly(exit.cause))
225
229
  return yield* Effect.failCause(exit.cause);
226
230
  yield* Effect.yieldNow;
227
231
  return exit;
228
232
  });
229
- const chainReaction = (runner, promises, source, onFulfilled, onRejected, method, node) => {
230
- return promises.createWithSelf((self) => Effect.gen(function* () {
231
- const exit = yield* reactionExit(promises, source);
233
+ const chainReaction = (ctx, source, onFulfilled, onRejected, method) => {
234
+ return ctx.pending.createWithSelf((self) => Effect.gen(function* () {
235
+ const exit = yield* reactionExit(ctx, source);
232
236
  const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
233
237
  if (handler === undefined)
234
238
  return yield* exit;
235
- const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(runner, Cause.squash(exit.cause));
236
- const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
237
- return yield* resolvePromiseValue(runner, result, node, self);
239
+ const input = Exit.isSuccess(exit) ? exit.value : materialize(ctx, Cause.squash(exit.cause));
240
+ const result = yield* applyCollectionCallback(ctx, handler, method)([input]);
241
+ return yield* resolvePromiseValue(ctx, result, self);
238
242
  }));
239
243
  };
240
- const chainFinally = (runner, promises, source, cleanup, method, node) => promises.create(Effect.gen(function* () {
241
- const exit = yield* reactionExit(promises, source);
244
+ const chainFinally = (ctx, source, cleanup, method) => ctx.pending.create(Effect.gen(function* () {
245
+ const exit = yield* reactionExit(ctx, source);
242
246
  if (cleanup !== undefined) {
243
- const result = yield* applyCollectionCallback(runner, cleanup, method, node)([]);
244
- const intermediate = yield* promises.create(Effect.gen(function* () {
245
- yield* runner.settlePromise(yield* resolvePromise(runner, promises, result, node));
247
+ const result = yield* applyCollectionCallback(ctx, cleanup, method)([]);
248
+ const intermediate = yield* ctx.pending.create(Effect.gen(function* () {
249
+ yield* ctx.await(yield* resolvePromise(ctx, result));
246
250
  return yield* exit;
247
251
  }));
248
- return yield* runner.settlePromise(intermediate);
252
+ return yield* ctx.await(intermediate);
249
253
  }
250
254
  return yield* exit;
251
255
  }));
252
- export const promiseGlobal = (runner, promises) => {
253
- const protos = runner.prototypes;
254
- const proto = protos.Promise;
255
- const promise = constructor(protos, proto, {
256
+ export const promiseGlobal = (ctx) => {
257
+ const builtins = ctx.builtins;
258
+ const proto = builtins.Promise;
259
+ const promise = constructor(builtins, proto, {
256
260
  name: "Promise",
257
261
  length: 1,
258
262
  call: requiresNew("Promise"),
259
- construct: (args, _, node) => constructPromise(runner, promises, args[0], node),
263
+ construct: (args) => constructPromise(ctx, args[0]),
260
264
  });
261
265
  // Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
262
266
  for (const name of promiseStatics) {
263
- define(promise, name, native(protos, {
267
+ define(promise, name, native(builtins, {
264
268
  name,
265
269
  length: 1,
266
- call: (_, args, node) => invokePromiseMethod(runner, promises, name, args, node),
270
+ call: (_, args) => invokePromiseMethod(ctx, name, args),
267
271
  callback: false,
268
272
  }), hidden);
269
273
  }
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
+ methods(builtins, proto, [
275
+ ["then", 2, (thisValue, args) => instanceMethod(ctx, "then", thisValue, args)],
276
+ ["catch", 1, (thisValue, args) => instanceMethod(ctx, "catch", thisValue, args)],
277
+ ["finally", 1, (thisValue, args) => instanceMethod(ctx, "finally", thisValue, args)],
274
278
  ]);
275
279
  return promise;
276
280
  };
@@ -1,8 +1,7 @@
1
- import { type AstNode } from "./model.js";
2
1
  /** Values that cannot cross the data boundary. */
3
2
  export declare const isRuntimeReference: (value: unknown) => boolean;
4
3
  export declare const containsRuntimeReference: (value: unknown) => boolean;
5
4
  export declare const containsOpaqueReference: (value: unknown) => boolean;
6
- export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, node: AstNode, seen?: Set<object>) => void;
5
+ export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, seen?: Set<object>) => void;
7
6
  export declare const describeValue: (value: unknown) => string;
8
7
  export declare const typeofValue: (value: unknown) => string;