@opencode/codemode 2.0.3 → 2.0.5

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 (72) hide show
  1. package/README.md +5 -2
  2. package/dist/codemode.d.ts +7 -2
  3. package/dist/codemode.js +15 -2
  4. package/dist/data.d.ts +14 -21
  5. package/dist/data.js +72 -140
  6. package/dist/extension.d.ts +11 -0
  7. package/dist/extension.js +9 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +1 -0
  10. package/dist/interpreter/callback.d.ts +20 -0
  11. package/dist/interpreter/{runner.js → callback.js} +14 -14
  12. package/dist/interpreter/errors.d.ts +12 -5
  13. package/dist/interpreter/errors.js +66 -54
  14. package/dist/interpreter/execute.d.ts +2 -2
  15. package/dist/interpreter/execute.js +15 -15
  16. package/dist/interpreter/extensions.d.ts +8 -0
  17. package/dist/interpreter/extensions.js +160 -0
  18. package/dist/interpreter/generators.d.ts +2 -3
  19. package/dist/interpreter/generators.js +10 -10
  20. package/dist/interpreter/globals.d.ts +4 -12
  21. package/dist/interpreter/globals.js +56 -49
  22. package/dist/interpreter/interpreter.d.ts +34 -0
  23. package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
  24. package/dist/interpreter/intrinsics.d.ts +5 -5
  25. package/dist/interpreter/intrinsics.js +16 -10
  26. package/dist/interpreter/limits.d.ts +10 -0
  27. package/dist/interpreter/limits.js +19 -0
  28. package/dist/interpreter/model.d.ts +27 -14
  29. package/dist/interpreter/model.js +22 -14
  30. package/dist/interpreter/native.d.ts +12 -13
  31. package/dist/interpreter/native.js +17 -16
  32. package/dist/interpreter/objects.d.ts +55 -48
  33. package/dist/interpreter/objects.js +64 -44
  34. package/dist/interpreter/promises.d.ts +13 -15
  35. package/dist/interpreter/promises.js +89 -85
  36. package/dist/interpreter/references.d.ts +1 -2
  37. package/dist/interpreter/references.js +18 -16
  38. package/dist/interpreter/scope.js +6 -6
  39. package/dist/openapi/types.d.ts +1 -1
  40. package/dist/stdlib/array.d.ts +3 -4
  41. package/dist/stdlib/array.js +115 -110
  42. package/dist/stdlib/bytes.d.ts +10 -0
  43. package/dist/stdlib/bytes.js +228 -0
  44. package/dist/stdlib/collections.d.ts +4 -4
  45. package/dist/stdlib/collections.js +89 -89
  46. package/dist/stdlib/console.d.ts +5 -3
  47. package/dist/stdlib/console.js +30 -37
  48. package/dist/stdlib/date.d.ts +2 -2
  49. package/dist/stdlib/date.js +35 -35
  50. package/dist/stdlib/json.d.ts +3 -3
  51. package/dist/stdlib/json.js +29 -67
  52. package/dist/stdlib/math.d.ts +3 -3
  53. package/dist/stdlib/math.js +17 -21
  54. package/dist/stdlib/number.d.ts +3 -3
  55. package/dist/stdlib/number.js +32 -36
  56. package/dist/stdlib/object.d.ts +5 -5
  57. package/dist/stdlib/object.js +59 -62
  58. package/dist/stdlib/regexp.d.ts +7 -8
  59. package/dist/stdlib/regexp.js +40 -48
  60. package/dist/stdlib/string.d.ts +2 -2
  61. package/dist/stdlib/string.js +110 -88
  62. package/dist/stdlib/url.d.ts +4 -6
  63. package/dist/stdlib/url.js +86 -90
  64. package/dist/stdlib/value.d.ts +3 -3
  65. package/dist/stdlib/value.js +26 -24
  66. package/dist/stdlib/web.d.ts +4 -4
  67. package/dist/stdlib/web.js +22 -8
  68. package/dist/tool-runtime.d.ts +38 -19
  69. package/dist/tool-runtime.js +70 -48
  70. package/package.json +1 -1
  71. package/dist/interpreter/runner.d.ts +0 -28
  72. package/dist/interpreter/runtime.d.ts +0 -19
@@ -1,12 +1,13 @@
1
1
  import { Cause, Deferred, Effect, Exit } from "effect";
2
- import { toProgram } from "../data.js";
2
+ import { fromJson, toBoundary } from "../data.js";
3
3
  import { ToolReference } from "../tool-runtime.js";
4
- import { AsyncIteratorSymbol, GeneratorReturn, InterpreterRuntimeError, IteratorSymbol, locate, OptionalShortCircuit, ProgramThrow, rangeError, unsupportedSyntax, } from "./model.js";
5
- import { caughtErrorValue } from "./errors.js";
4
+ import { AsyncIteratorSymbol, CallSite, GeneratorReturn, IteratorSymbol, OptionalShortCircuit, invalidData, Throw, rangeError, typeError, unsupportedSyntax, } from "./model.js";
5
+ import { checkStringLength } from "./limits.js";
6
+ import { locate, materialize } from "./errors.js";
6
7
  import { globals } from "./globals.js";
7
- import { assign, Callable, define, get, has, hasPrototype, keys, NativeFunction, parseArrayIndex, ProgramArray, ProgramDate, ProgramFunction, ProgramGenerator, ProgramMap, ProgramObject, ProgramPromise, ProgramSet, ProgramURLSearchParams, record, remove, set, } from "./objects.js";
8
- import { preserveConsumerError } from "./runner.js";
9
- import { PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
8
+ import { assign, Callable, define, get, has, hasPrototype, keys, Native, parseArrayIndex, Arr, Bytes, DateObj, Fn, GeneratorObj, MapObj, Obj, PromiseObj, SetObj, URLSearchParamsObj, record, remove, set, } from "./objects.js";
9
+ import { preserveConsumerError } from "./callback.js";
10
+ import { Pending, resolvePromise, resolvePromiseValue } from "./promises.js";
10
11
  import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
11
12
  import { ScopeStack } from "./scope.js";
12
13
  import { constructRegExp } from "../stdlib/regexp.js";
@@ -45,11 +46,11 @@ const calleeDescription = (callee) => {
45
46
  // OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
46
47
  const instanceofValue = (lhs, rhs, node) => {
47
48
  if (!(rhs instanceof Callable)) {
48
- throw new InterpreterRuntimeError("The right-hand side of 'instanceof' is not callable.", node);
49
+ throw typeError("The right-hand side of 'instanceof' is not callable.", node);
49
50
  }
50
51
  const prototype = get(rhs, "prototype");
51
- if (!(prototype instanceof ProgramObject)) {
52
- throw new InterpreterRuntimeError("The right-hand side of 'instanceof' has no 'prototype' object.", node);
52
+ if (!(prototype instanceof Obj)) {
53
+ throw typeError("The right-hand side of 'instanceof' has no 'prototype' object.", node);
53
54
  }
54
55
  return hasPrototype(lhs, prototype);
55
56
  };
@@ -132,7 +133,7 @@ const loopDeclaration = (left, statement) => {
132
133
  return undefined;
133
134
  const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
134
135
  if (declaration === undefined) {
135
- throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
136
+ throw typeError(`${statement} supports one declared binding.`, left);
136
137
  }
137
138
  const kind = left.kind;
138
139
  return {
@@ -141,50 +142,60 @@ const loopDeclaration = (left, statement) => {
141
142
  lexical: kind !== "var",
142
143
  };
143
144
  };
144
- const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
145
145
  /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
146
- export class Runtime {
147
- executeTool;
148
- search;
149
- toolKeys;
150
- promises;
151
- prototypes;
146
+ export class Interpreter {
147
+ tools;
148
+ pending;
149
+ builtins;
152
150
  logs;
153
- runner;
154
151
  root;
155
- constructor(executeTool, search, toolKeys, promises, prototypes, logs = [], extraGlobals = () => []) {
156
- this.executeTool = executeTool;
157
- this.search = search;
158
- this.toolKeys = toolKeys;
159
- this.promises = promises;
160
- this.prototypes = prototypes;
161
- this.logs = logs;
152
+ constructor(options) {
153
+ this.tools = options.tools;
154
+ this.pending = options.pending;
155
+ this.builtins = options.builtins;
156
+ this.logs = options.logs ?? [];
162
157
  const globalScope = new Map();
163
158
  // Calling back into the program never reads frame state, so any frame serves; the root is always alive.
164
159
  this.root = new Frame(this, new ScopeStack([globalScope]));
165
- this.runner = {
166
- invokeCallable: (callable, thisValue, args, node) => this.root.invokeCallable(callable, thisValue, args, node),
167
- settlePromise: (promise) => this.root.settlePromise(promise),
168
- syncIterator: (value, node) => this.root.syncIterator(value, node),
169
- prototypes,
170
- };
171
- for (const [name, value] of [...globals(this), ...extraGlobals(this)]) {
160
+ for (const [name, value] of [...globals(this), ...(options.globals?.(this) ?? [])]) {
172
161
  globalScope.set(name, { mutable: false, value });
173
162
  }
174
163
  }
175
164
  run(program) {
176
165
  return this.root.run(program);
177
166
  }
167
+ call(callable, thisValue, args) {
168
+ return this.root.call(callable, thisValue, args);
169
+ }
170
+ await(promise) {
171
+ return this.root.await(promise);
172
+ }
173
+ iterate(value) {
174
+ return this.root.iterate(value);
175
+ }
176
+ /** Runs one host tool: arguments cross as JSON and the result comes back as program values. */
177
+ tool(run, args) {
178
+ const ctx = this;
179
+ return Effect.gen(function* () {
180
+ const json = yield* Effect.forEach(args, (arg) => toBoundary(ctx, arg));
181
+ return fromJson(ctx, yield* run(json));
182
+ });
183
+ }
178
184
  }
185
+ const MAX_CALL_DEPTH = 10_000;
179
186
  /** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
180
187
  class Frame {
181
- runtime;
188
+ ctx;
182
189
  scopes;
190
+ depth;
183
191
  generatorState;
184
192
  generatorAsync = false;
185
- constructor(runtime, scopes) {
186
- this.runtime = runtime;
193
+ constructor(ctx, scopes,
194
+ /** Nested call depth; resets when an await resumes, since the continuation runs from the job queue. */
195
+ depth = 0) {
196
+ this.ctx = ctx;
187
197
  this.scopes = scopes;
198
+ this.depth = depth;
188
199
  }
189
200
  run(program) {
190
201
  const self = this;
@@ -206,24 +217,24 @@ class Frame {
206
217
  break;
207
218
  }
208
219
  if (result.kind === "break" || result.kind === "continue") {
209
- throw new InterpreterRuntimeError(`Unexpected '${result.kind}' outside of a loop.`, statement);
220
+ throw typeError(`Unexpected '${result.kind}' outside of a loop.`, statement);
210
221
  }
211
222
  }
212
223
  // The implicit async body adopts returned promises before copy-out.
213
- value = yield* resolvePromiseValue(self.runtime.runner, value, program);
224
+ value = yield* resolvePromiseValue(self.ctx, value);
214
225
  return value;
215
226
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
216
227
  }
217
228
  // Fork at the call site so admission and hooks occur when the call is made.
218
229
  createToolCallPromise(path, args) {
219
- return this.runtime.promises.create(Effect.suspend(() => this.runtime.executeTool(path, args)));
230
+ return this.ctx.pending.create(this.ctx.tool((json) => this.ctx.tools.execute(path, json), args));
220
231
  }
221
232
  // Fiber exits make settlement idempotent; yielding prevents inline continuation.
222
- settlePromise(promise) {
223
- const promises = this.runtime.promises;
233
+ await(promise) {
234
+ const pending = this.ctx.pending;
224
235
  return Effect.suspend(() => {
225
- promises.markObserved(promise);
226
- return Effect.flatMap(promises.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
236
+ pending.markObserved(promise);
237
+ return Effect.flatMap(pending.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
227
238
  });
228
239
  }
229
240
  evaluateStatement(node) {
@@ -289,7 +300,7 @@ class Frame {
289
300
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
290
301
  }
291
302
  createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
292
- return new ProgramFunction(this.runtime.prototypes.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
303
+ return new Fn(this.ctx.builtins.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
293
304
  }
294
305
  // NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
295
306
  evaluateNamed(node, name) {
@@ -348,7 +359,7 @@ class Frame {
348
359
  return Effect.gen(function* () {
349
360
  const discriminant = yield* self.evaluateExpression(node.discriminant);
350
361
  if (containsOpaqueReference(discriminant)) {
351
- throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
362
+ throw invalidData("Switch discriminants must be data values.", node);
352
363
  }
353
364
  self.scopes.push();
354
365
  return yield* Effect.gen(function* () {
@@ -366,7 +377,7 @@ class Frame {
366
377
  }
367
378
  const candidate = yield* self.evaluateExpression(test);
368
379
  if (containsOpaqueReference(candidate)) {
369
- throw new InterpreterRuntimeError("Switch case values must be data values.", test, "InvalidDataValue");
380
+ throw invalidData("Switch case values must be data values.", test);
370
381
  }
371
382
  if (candidate === discriminant) {
372
383
  selected = index;
@@ -467,9 +478,9 @@ class Frame {
467
478
  self.predeclarePattern(declared.pattern, declared.mutable, left);
468
479
  const right = yield* self.evaluateExpression(node.right);
469
480
  const iterator = yield* self.customIterator(right, node, awaiting);
470
- const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
481
+ const cursor = iterator === undefined ? yield* self.iterate(right, node) : undefined;
471
482
  if (iterator === undefined && cursor === undefined) {
472
- throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node);
483
+ throw invalidData(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node);
473
484
  }
474
485
  const close = () => iterator
475
486
  ? self.closeIterator(iterator, node, awaiting)
@@ -477,7 +488,7 @@ class Frame {
477
488
  ? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
478
489
  : (cursor?.close ?? Effect.void);
479
490
  if (left.type === "RestElement" || left.type === "AssignmentPattern") {
480
- throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
491
+ throw typeError("Unsupported for...of binding.", left);
481
492
  }
482
493
  const assignment = left.type === "VariableDeclaration" ? undefined : left;
483
494
  const evaluateBody = (value) => Effect.gen(function* () {
@@ -500,7 +511,7 @@ class Frame {
500
511
  while (true) {
501
512
  const current = iterator
502
513
  ? yield* self.nextIteratorResult(iterator, node, awaiting)
503
- : yield* cursor?.next ?? Effect.fail(new InterpreterRuntimeError("Iterator is unavailable.", node));
514
+ : yield* cursor?.next ?? Effect.die(typeError("Iterator is unavailable.", node));
504
515
  const step = cursor && awaiting ? { done: current.done, value: yield* self.awaitValue(current.value) } : current;
505
516
  if (step.done)
506
517
  return { kind: "none" };
@@ -523,8 +534,8 @@ class Frame {
523
534
  self.scopes.pop();
524
535
  })));
525
536
  }
526
- awaitValue(value, node = promiseResolutionNode) {
527
- return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value, node), (promise) => this.settlePromise(promise));
537
+ awaitValue(value) {
538
+ return Effect.flatMap(resolvePromise(this.ctx, value), (promise) => Effect.ensuring(this.await(promise), Effect.sync(() => (this.depth = 0))));
528
539
  }
529
540
  awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
530
541
  const self = this;
@@ -538,26 +549,28 @@ class Frame {
538
549
  return yield* Effect.failCause(settled.cause);
539
550
  });
540
551
  }
541
- syncIterator(value, node) {
542
- const iterator = value instanceof ProgramArray
552
+ iterate(value, node) {
553
+ const iterator = value instanceof Arr
543
554
  ? value.items[Symbol.iterator]()
544
555
  : typeof value === "string"
545
556
  ? value[Symbol.iterator]()
546
- : value instanceof ProgramMap
557
+ : value instanceof MapObj
547
558
  ? value.map.entries()
548
- : value instanceof ProgramSet
559
+ : value instanceof SetObj
549
560
  ? value.set.values()
550
- : value instanceof ProgramURLSearchParams
561
+ : value instanceof URLSearchParamsObj
551
562
  ? value.params.entries()
552
- : undefined;
563
+ : value instanceof Bytes
564
+ ? value.bytes.values()
565
+ : undefined;
553
566
  if (iterator !== undefined) {
554
- const proto = this.runtime.prototypes.Array;
567
+ const proto = this.ctx.builtins.Array;
555
568
  return Effect.succeed({
556
569
  next: Effect.sync(() => {
557
570
  const step = iterator.next();
558
571
  return {
559
572
  done: Boolean(step.done),
560
- value: Array.isArray(step.value) ? new ProgramArray(proto, step.value) : step.value,
573
+ value: Array.isArray(step.value) ? new Arr(proto, step.value) : step.value,
561
574
  };
562
575
  }),
563
576
  close: Effect.void,
@@ -572,14 +585,14 @@ class Frame {
572
585
  });
573
586
  }
574
587
  customIterator(value, node, allowAsync = true) {
575
- if (!(value instanceof ProgramObject))
588
+ if (!(value instanceof Obj))
576
589
  return Effect.undefined;
577
590
  const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
578
591
  const method = asyncMethod ?? get(value, IteratorSymbol);
579
592
  if (method === undefined || method === null)
580
593
  return Effect.undefined;
581
594
  const self = this;
582
- return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), value, [], node), (iterator) => {
595
+ return Effect.map(this.call(this.requireIteratorMethod(method, "Iterator method", node), value, [], node), (iterator) => {
583
596
  const object = self.requireIteratorObject(iterator, "Iterator method result", node);
584
597
  return {
585
598
  iterator: object,
@@ -592,10 +605,10 @@ class Frame {
592
605
  const self = this;
593
606
  return Effect.gen(function* () {
594
607
  if (iterator.asynchronous) {
595
- const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, iterator.iterator, [], node)), "Iterator next() result", node);
608
+ const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.call(iterator.next, iterator.iterator, [], node)), "Iterator next() result", node);
596
609
  return { done: Boolean(get(object, "done")), value: get(object, "value") };
597
610
  }
598
- const called = yield* Effect.exit(self.invokeCallable(iterator.next, iterator.iterator, [], node));
611
+ const called = yield* Effect.exit(self.call(iterator.next, iterator.iterator, [], node));
599
612
  if (!Exit.isSuccess(called)) {
600
613
  if (awaiting)
601
614
  yield* Effect.yieldNow;
@@ -626,10 +639,10 @@ class Frame {
626
639
  return Effect.gen(function* () {
627
640
  const method = self.requireIteratorMethod(close, "Iterator return", node);
628
641
  if (iterator.asynchronous) {
629
- self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, iterator.iterator, [], node)), "Iterator return() result", node);
642
+ self.requireIteratorObject(yield* self.awaitValue(yield* self.call(method, iterator.iterator, [], node)), "Iterator return() result", node);
630
643
  return;
631
644
  }
632
- const called = yield* Effect.exit(self.invokeCallable(method, iterator.iterator, [], node));
645
+ const called = yield* Effect.exit(self.call(method, iterator.iterator, [], node));
633
646
  if (!Exit.isSuccess(called)) {
634
647
  if (awaiting)
635
648
  yield* Effect.yieldNow;
@@ -646,22 +659,22 @@ class Frame {
646
659
  });
647
660
  }
648
661
  requireIteratorObject(value, context, node) {
649
- if (value instanceof ProgramObject)
662
+ if (value instanceof Obj)
650
663
  return value;
651
- throw new InterpreterRuntimeError(`${context} must be an object.`, node);
664
+ throw typeError(`${context} must be an object.`, node);
652
665
  }
653
666
  requireIteratorMethod(value, context, node) {
654
667
  if (typeofValue(value) === "function")
655
668
  return value;
656
- throw new InterpreterRuntimeError(`${context} must be a function.`, node);
669
+ throw typeError(`${context} must be a function.`, node);
657
670
  }
658
671
  // for...in over null/undefined iterates nothing, like JS.
659
672
  enumerableKeys(value, node) {
660
673
  if (value instanceof ToolReference)
661
- return [...this.runtime.toolKeys(value.path)];
674
+ return [...this.ctx.tools.keys(value.path)];
662
675
  if (value === null || value === undefined)
663
676
  return [];
664
- return keys(enumerableSource(this.runtime.runner, "for...in", value, node));
677
+ return keys(enumerableSource(this.ctx, "for...in", value, node));
665
678
  }
666
679
  evaluateForInStatement(node, labels) {
667
680
  const left = node.left;
@@ -675,7 +688,7 @@ class Frame {
675
688
  const right = yield* self.evaluateExpression(node.right);
676
689
  const keys = self.enumerableKeys(right, node.right);
677
690
  if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
678
- throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
691
+ throw typeError("Unsupported for...in binding.", left);
679
692
  }
680
693
  const assignmentName = left.type === "Identifier" ? left.name : undefined;
681
694
  for (const key of keys) {
@@ -737,7 +750,7 @@ class Frame {
737
750
  : result);
738
751
  }
739
752
  evaluateThrowStatement(node) {
740
- return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new ProgramThrow(value)));
753
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new Throw(value)));
741
754
  }
742
755
  evaluateTryStatement(node) {
743
756
  const body = node.block;
@@ -749,7 +762,7 @@ class Frame {
749
762
  if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
750
763
  return Effect.failCause(cause);
751
764
  }
752
- const caught = caughtErrorValue(self.runtime.runner, Cause.squash(cause));
765
+ const caught = materialize(self.ctx, Cause.squash(cause));
753
766
  const parameter = handler.param;
754
767
  self.scopes.push();
755
768
  return Effect.gen(function* () {
@@ -776,7 +789,7 @@ class Frame {
776
789
  return Effect.gen(function* () {
777
790
  for (const declaration of node.declarations) {
778
791
  if (declaration.type !== "VariableDeclarator") {
779
- throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
792
+ throw typeError("Unsupported variable declaration shape.", declaration);
780
793
  }
781
794
  const init = declaration.init;
782
795
  // `var x` alone is a no-op: the binding was hoisted on function entry.
@@ -809,27 +822,27 @@ class Frame {
809
822
  return;
810
823
  }
811
824
  if (pattern.type === "ObjectPattern") {
812
- if (!(value instanceof ProgramObject)) {
813
- throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
825
+ if (!(value instanceof Obj)) {
826
+ throw typeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern);
814
827
  }
815
828
  const consumed = new Set();
816
829
  for (const property of pattern.properties) {
817
830
  if (property.type === "RestElement") {
818
- const rest = new ProgramObject(self.runtime.prototypes.Object);
831
+ const rest = new Obj(self.ctx.builtins.Object);
819
832
  assign(rest, value, consumed);
820
833
  yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
821
834
  continue;
822
835
  }
823
836
  const key = yield* self.destructuringPropertyKey(property);
824
837
  consumed.add(typeof key === "symbol" ? key : String(key));
825
- yield* self.declarePattern(property.value, get(value, key), mutable, property, initialize);
838
+ yield* self.declarePattern(property.value, self.readProperty(value, key, property), mutable, property, initialize);
826
839
  }
827
840
  return;
828
841
  }
829
842
  if (pattern.type === "ArrayPattern") {
830
843
  return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.declarePattern(target, item, mutable, context, initialize));
831
844
  }
832
- throw new InterpreterRuntimeError(`Unsupported binding pattern '${pattern.type}'.`, pattern);
845
+ throw typeError(`Unsupported binding pattern '${pattern.type}'.`, pattern);
833
846
  });
834
847
  }
835
848
  assignPattern(pattern, value, node) {
@@ -849,27 +862,27 @@ class Frame {
849
862
  return;
850
863
  }
851
864
  if (pattern.type === "ObjectPattern") {
852
- if (!(value instanceof ProgramObject)) {
853
- throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
865
+ if (!(value instanceof Obj)) {
866
+ throw invalidData(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern);
854
867
  }
855
868
  const consumed = new Set();
856
869
  for (const property of pattern.properties) {
857
870
  if (property.type === "RestElement") {
858
- const rest = new ProgramObject(self.runtime.prototypes.Object);
871
+ const rest = new Obj(self.ctx.builtins.Object);
859
872
  assign(rest, value, consumed);
860
873
  yield* self.assignPattern(property.argument, rest, property);
861
874
  continue;
862
875
  }
863
876
  const key = yield* self.destructuringPropertyKey(property);
864
877
  consumed.add(typeof key === "symbol" ? key : String(key));
865
- yield* self.assignPattern(property.value, get(value, key), property);
878
+ yield* self.assignPattern(property.value, self.readProperty(value, key, property), property);
866
879
  }
867
880
  return;
868
881
  }
869
882
  if (pattern.type === "ArrayPattern") {
870
883
  return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.assignPattern(target, item, context));
871
884
  }
872
- throw new InterpreterRuntimeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
885
+ throw typeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
873
886
  });
874
887
  }
875
888
  evaluateDefault(pattern) {
@@ -880,16 +893,16 @@ class Frame {
880
893
  destructureArrayPattern(pattern, value, consume) {
881
894
  const self = this;
882
895
  return Effect.gen(function* () {
883
- const cursor = yield* self.syncIterator(value, pattern);
896
+ const cursor = yield* self.iterate(value, pattern);
884
897
  if (cursor === undefined) {
885
- throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern);
898
+ throw typeError("Array destructuring requires a supported iterable value.", pattern);
886
899
  }
887
900
  let done = false;
888
901
  for (const element of pattern.elements) {
889
902
  if (done) {
890
903
  if (element === null)
891
904
  continue;
892
- yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray(self.runtime.prototypes.Array) : undefined, element);
905
+ yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new Arr(self.ctx.builtins.Array) : undefined, element);
893
906
  if (element.type === "RestElement")
894
907
  return;
895
908
  continue;
@@ -908,7 +921,7 @@ class Frame {
908
921
  if (!done)
909
922
  rest.push(next.value);
910
923
  }
911
- yield* consume(element.argument, new ProgramArray(self.runtime.prototypes.Array, rest), element);
924
+ yield* consume(element.argument, new Arr(self.ctx.builtins.Array, rest), element);
912
925
  return;
913
926
  }
914
927
  const consumed = consume(element, step.done ? undefined : step.value, pattern);
@@ -920,7 +933,7 @@ class Frame {
920
933
  }
921
934
  destructuringPropertyKey(property) {
922
935
  if (property.type !== "Property" || property.kind !== "init") {
923
- throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
936
+ throw typeError("Unsupported object destructuring property.", property);
924
937
  }
925
938
  const keyNode = property.key;
926
939
  if (property.computed) {
@@ -937,8 +950,10 @@ class Frame {
937
950
  case "Literal": {
938
951
  const regex = node.regex;
939
952
  if (regex)
940
- return Effect.sync(() => constructRegExp(this.runtime.prototypes, [regex.pattern, regex.flags], node));
941
- return Effect.sync(() => toProgram(this.runtime.prototypes, node.value, "Literal"));
953
+ return Effect.sync(() => constructRegExp(this.ctx.builtins, [regex.pattern, regex.flags]));
954
+ if (typeof node.value === "bigint")
955
+ throw typeError("BigInt literals are not supported.", node);
956
+ return Effect.succeed(node.value);
942
957
  }
943
958
  case "Identifier":
944
959
  return Effect.sync(() => this.scopes.get(node.name, node));
@@ -981,7 +996,7 @@ class Frame {
981
996
  return this.evaluateUpdateExpression(node);
982
997
  case "AwaitExpression": {
983
998
  // Await always suspends, including for plain values.
984
- return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value, node));
999
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value));
985
1000
  }
986
1001
  case "YieldExpression":
987
1002
  return this.evaluateYieldExpression(node);
@@ -996,21 +1011,21 @@ class Frame {
996
1011
  return Effect.gen(function* () {
997
1012
  const callee = yield* self.evaluateExpression(node.callee);
998
1013
  // Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
999
- const construct = callee instanceof NativeFunction ? callee.construct : undefined;
1014
+ const construct = callee instanceof Native ? callee.construct : undefined;
1000
1015
  if (construct === undefined) {
1001
1016
  // `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
1002
1017
  // unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
1003
1018
  // otherwise; say `new` is unsupported for them and point at the plain call.
1004
1019
  const name = calleeDescription(node.callee);
1005
- const message = callee instanceof ProgramFunction
1020
+ const message = callee instanceof Fn
1006
1021
  ? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
1007
- : callee instanceof NativeFunction
1022
+ : callee instanceof Native
1008
1023
  ? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
1009
1024
  : `${name} is not a constructor.`;
1010
- throw new InterpreterRuntimeError(message, node);
1025
+ throw typeError(message, node);
1011
1026
  }
1012
1027
  const args = yield* self.evaluateCallArguments(node.arguments);
1013
- return yield* construct(args, callee, node);
1028
+ return yield* self.native(() => construct(args, callee), node);
1014
1029
  });
1015
1030
  }
1016
1031
  evaluateBinaryExpression(node) {
@@ -1024,7 +1039,7 @@ class Frame {
1024
1039
  const rhs = yield* self.evaluateExpression(node.right);
1025
1040
  if (operator === "instanceof")
1026
1041
  return instanceofValue(lhs, rhs, node);
1027
- return toProgram(self.runtime.prototypes, self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
1042
+ return self.applyBinaryOperator(operator, lhs, rhs, node);
1028
1043
  });
1029
1044
  }
1030
1045
  applyBinaryOperator(operator, lhs, rhs, node) {
@@ -1032,16 +1047,16 @@ class Frame {
1032
1047
  return lhs === rhs;
1033
1048
  if (operator === "!==")
1034
1049
  return lhs !== rhs;
1035
- if (operator === "in" && rhs instanceof ProgramObject && !containsOpaqueReference(lhs)) {
1050
+ if (operator === "in" && rhs instanceof Obj && !containsOpaqueReference(lhs)) {
1036
1051
  return has(rhs, lhs !== null && typeof lhs === "object" ? coerceToString(lhs) : lhs);
1037
1052
  }
1038
1053
  if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
1039
- throw new InterpreterRuntimeError("Binary operators require data values.", node, "InvalidDataValue");
1054
+ throw invalidData("Binary operators require data values.", node);
1040
1055
  }
1041
1056
  // Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
1042
1057
  // Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
1043
1058
  const coerceOperand = (operand) => {
1044
- if (operand instanceof ProgramDate) {
1059
+ if (operand instanceof DateObj) {
1045
1060
  return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
1046
1061
  }
1047
1062
  return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
@@ -1050,8 +1065,12 @@ class Frame {
1050
1065
  const l = coerceOperand(lhs);
1051
1066
  const r = coerceOperand(rhs);
1052
1067
  switch (operator) {
1053
- case "+":
1054
- return l + r;
1068
+ case "+": {
1069
+ const sum = l + r;
1070
+ if (typeof sum === "string")
1071
+ checkStringLength(sum.length);
1072
+ return sum;
1073
+ }
1055
1074
  case "-":
1056
1075
  return l - r;
1057
1076
  case "*":
@@ -1087,12 +1106,12 @@ class Frame {
1087
1106
  case ">>>":
1088
1107
  return l >>> r;
1089
1108
  case "in":
1090
- if (!(rhs instanceof ProgramObject)) {
1091
- throw new InterpreterRuntimeError("The 'in' operator requires a data object on the right-hand side.", node);
1109
+ if (!(rhs instanceof Obj)) {
1110
+ throw typeError("The 'in' operator requires a data object on the right-hand side.", node);
1092
1111
  }
1093
1112
  return has(rhs, coerceOperand(lhs));
1094
1113
  default:
1095
- throw new InterpreterRuntimeError(`Unsupported binary operator '${operator}'.`, node);
1114
+ throw typeError(`Unsupported binary operator '${operator}'.`, node);
1096
1115
  }
1097
1116
  }
1098
1117
  evaluateLogicalExpression(node) {
@@ -1104,7 +1123,7 @@ class Frame {
1104
1123
  return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
1105
1124
  if (operator === "??")
1106
1125
  return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
1107
- throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
1126
+ throw typeError(`Unsupported logical operator '${operator}'.`, node);
1108
1127
  });
1109
1128
  }
1110
1129
  evaluateUnaryExpression(node) {
@@ -1124,9 +1143,9 @@ class Frame {
1124
1143
  if (operator === "void")
1125
1144
  return undefined;
1126
1145
  if (containsOpaqueReference(value)) {
1127
- throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
1146
+ throw invalidData("Unary operators require data values.", node);
1128
1147
  }
1129
- const operand = value instanceof ProgramDate
1148
+ const operand = value instanceof DateObj
1130
1149
  ? value.time
1131
1150
  : value !== null && typeof value === "object"
1132
1151
  ? coerceToString(value)
@@ -1143,9 +1162,9 @@ class Frame {
1143
1162
  result = ~operand;
1144
1163
  break;
1145
1164
  default:
1146
- throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
1165
+ throw typeError(`Unsupported unary operator '${operator}'.`, node);
1147
1166
  }
1148
- return toProgram(this.runtime.prototypes, result, "Unary expression result");
1167
+ return result;
1149
1168
  });
1150
1169
  }
1151
1170
  evaluateAssignmentExpression(node) {
@@ -1166,8 +1185,7 @@ class Frame {
1166
1185
  if (operator !== "=") {
1167
1186
  const current = self.scopes.get(name, left);
1168
1187
  const rightValue = yield* self.evaluateExpression(node.right);
1169
- const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1170
- return self.scopes.set(name, next, left);
1188
+ return self.scopes.set(name, self.applyCompoundAssignment(operator, current, rightValue, node), left);
1171
1189
  }
1172
1190
  const rightValue = yield* self.evaluateNamed(node.right, name);
1173
1191
  return self.scopes.set(name, rightValue, left);
@@ -1176,11 +1194,11 @@ class Frame {
1176
1194
  return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
1177
1195
  if (operator === "=")
1178
1196
  return { write: true, next: rightValue, result: rightValue };
1179
- const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1197
+ const next = self.applyCompoundAssignment(operator, current, rightValue, node);
1180
1198
  return { write: true, next, result: next };
1181
1199
  }));
1182
1200
  }
1183
- throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1201
+ throw typeError("Assignment target must be an Identifier or MemberExpression.", left);
1184
1202
  });
1185
1203
  }
1186
1204
  evaluateLogicalAssignment(node, left, operator) {
@@ -1205,7 +1223,7 @@ class Frame {
1205
1223
  }))
1206
1224
  : Effect.succeed({ write: false, next: current, result: current }));
1207
1225
  }
1208
- throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1226
+ throw typeError("Assignment target must be an Identifier or MemberExpression.", left);
1209
1227
  }
1210
1228
  evaluateUpdateExpression(node) {
1211
1229
  const operator = node.operator;
@@ -1213,13 +1231,13 @@ class Frame {
1213
1231
  const prefix = node.prefix;
1214
1232
  const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
1215
1233
  if (increment === undefined) {
1216
- throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
1234
+ throw typeError(`Unsupported update operator '${operator}'.`, node);
1217
1235
  }
1218
1236
  // CodeMode numeric coercion, not host Number(): null-prototype data objects would make
1219
1237
  // the host throw during ToPrimitive, and opaque runtime references must reject clearly.
1220
1238
  const operand = (current) => {
1221
1239
  if (containsOpaqueReference(current)) {
1222
- throw new InterpreterRuntimeError(`'${operator}' requires a data value.`, argument, "InvalidDataValue");
1240
+ throw invalidData(`'${operator}' requires a data value.`, argument);
1223
1241
  }
1224
1242
  return coerceToNumber(current);
1225
1243
  };
@@ -1239,7 +1257,7 @@ class Frame {
1239
1257
  return Effect.succeed({ write: true, next, result: prefix ? next : value });
1240
1258
  });
1241
1259
  }
1242
- throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
1260
+ throw typeError("Update target must be an Identifier or MemberExpression.", argument);
1243
1261
  }
1244
1262
  // EvaluateCall: a member callee supplies its base object as `this`; anything else calls with undefined.
1245
1263
  evaluateCallExpression(node) {
@@ -1256,7 +1274,7 @@ class Frame {
1256
1274
  if ((callable === null || callable === undefined) && node.optional)
1257
1275
  return OptionalShortCircuit;
1258
1276
  const args = yield* self.evaluateCallArguments(node.arguments);
1259
- return yield* self.invokeCallable(callable, thisValue, args, node, callee);
1277
+ return yield* self.call(callable, thisValue, args, node, callee);
1260
1278
  });
1261
1279
  }
1262
1280
  readMethod(node) {
@@ -1271,22 +1289,27 @@ class Frame {
1271
1289
  });
1272
1290
  }
1273
1291
  // The single dispatch for every invocation: call expressions and callbacks share it.
1274
- invokeCallable(callable, thisValue, args, node, callee) {
1292
+ call(callable, thisValue, args, node, callee) {
1275
1293
  const self = this;
1276
1294
  return Effect.gen(function* () {
1277
1295
  if (callable instanceof ToolReference) {
1278
1296
  if (callable.path.length === 0) {
1279
- throw new InterpreterRuntimeError("The tools root is not callable.", callee ?? node);
1297
+ throw typeError("The tools root is not callable.", callee ?? node);
1280
1298
  }
1281
1299
  return yield* self.createToolCallPromise(callable.path, args);
1282
1300
  }
1283
- if (callable instanceof ProgramFunction)
1284
- return yield* self.invokeFunction(callable, args);
1285
- if (callable instanceof NativeFunction)
1286
- return yield* callable.call(thisValue, args, node);
1287
- throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node);
1301
+ if (callable instanceof Fn)
1302
+ return yield* self.invokeFunction(callable, args, node);
1303
+ if (callable instanceof Native) {
1304
+ return yield* self.native(() => callable.call(thisValue, args), node);
1305
+ }
1306
+ throw typeError(`${calleeDescription(callee)} is not a function.`, callee ?? node);
1288
1307
  });
1289
1308
  }
1309
+ // Built-ins throw without a location, synchronously or inside their Effect; the call site supplies it.
1310
+ native(body, node) {
1311
+ return Effect.provideService(Effect.catchDefect(Effect.suspend(body), (defect) => Effect.die(locate(defect, node))), CallSite, { node, depth: this.depth });
1312
+ }
1290
1313
  evaluateCallArguments(argNodes) {
1291
1314
  const self = this;
1292
1315
  return Effect.gen(function* () {
@@ -1294,9 +1317,9 @@ class Frame {
1294
1317
  for (const argNode of argNodes) {
1295
1318
  if (argNode.type === "SpreadElement") {
1296
1319
  const spread = yield* self.evaluateExpression(argNode.argument);
1297
- const cursor = yield* self.syncIterator(spread, argNode);
1320
+ const cursor = yield* self.iterate(spread, argNode);
1298
1321
  if (cursor === undefined)
1299
- throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode);
1322
+ throw typeError("Spread arguments require a synchronous iterable.", argNode);
1300
1323
  while (true) {
1301
1324
  const step = yield* cursor.next;
1302
1325
  if (step.done)
@@ -1311,49 +1334,54 @@ class Frame {
1311
1334
  return args;
1312
1335
  });
1313
1336
  }
1314
- invokeFunction(fn, args) {
1337
+ // A callback invoked by a built-in runs below the call that invoked the built-in, so the deeper of the two counts.
1338
+ invokeFunction(fn, args, node) {
1315
1339
  const self = this;
1316
- const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
1317
- const run = Effect.gen(function* () {
1318
- // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
1319
- const paramScope = invocation.scopes.current();
1320
- for (const parameter of fn.parameters) {
1321
- for (const name of collectPatternNames(parameter)) {
1322
- paramScope.set(name, { mutable: true, value: undefined, initialized: false });
1340
+ return Effect.flatMap(CallSite, (site) => {
1341
+ const depth = Math.max(self.depth, site.depth) + 1;
1342
+ if (depth > MAX_CALL_DEPTH)
1343
+ throw rangeError("Maximum call stack size exceeded", node);
1344
+ const invocation = new Frame(this.ctx, new ScopeStack([...fn.capturedScopes, new Map()]), depth);
1345
+ const run = Effect.gen(function* () {
1346
+ // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
1347
+ const paramScope = invocation.scopes.current();
1348
+ for (const parameter of fn.parameters) {
1349
+ for (const name of collectPatternNames(parameter)) {
1350
+ paramScope.set(name, { mutable: true, value: undefined, initialized: false });
1351
+ }
1323
1352
  }
1324
- }
1325
- for (const [index, parameter] of fn.parameters.entries()) {
1326
- if (parameter.type === "RestElement") {
1327
- yield* invocation.declarePattern(parameter.argument, new ProgramArray(self.runtime.prototypes.Array, args.slice(index)), true, parameter, true);
1328
- break;
1353
+ for (const [index, parameter] of fn.parameters.entries()) {
1354
+ if (parameter.type === "RestElement") {
1355
+ yield* invocation.declarePattern(parameter.argument, new Arr(self.ctx.builtins.Array, args.slice(index)), true, parameter, true);
1356
+ break;
1357
+ }
1358
+ yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
1329
1359
  }
1330
- yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
1331
- }
1332
- if (fn.body.type === "BlockStatement") {
1333
- invocation.scopes.push();
1334
- invocation.hoistVars(fn.body.body, paramScope);
1335
- const result = yield* invocation.evaluateStatement(fn.body);
1336
- return result.kind === "return" ? result.value : undefined;
1337
- }
1338
- return yield* invocation.evaluateExpression(fn.body);
1360
+ if (fn.body.type === "BlockStatement") {
1361
+ invocation.scopes.push();
1362
+ invocation.hoistVars(fn.body.body, paramScope);
1363
+ const result = yield* invocation.evaluateStatement(fn.body);
1364
+ return result.kind === "return" ? result.value : undefined;
1365
+ }
1366
+ return yield* invocation.evaluateExpression(fn.body);
1367
+ });
1368
+ if (fn.generator)
1369
+ return Effect.succeed(this.createGenerator(invocation, run, fn.async));
1370
+ if (!fn.async)
1371
+ return run;
1372
+ return this.ctx.pending.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.ctx, value, self)));
1339
1373
  });
1340
- if (fn.generator)
1341
- return Effect.succeed(this.createGenerator(invocation, run, fn.async));
1342
- if (!fn.async)
1343
- return run;
1344
- return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, self)));
1345
1374
  }
1346
1375
  createGenerator(invocation, run, asynchronous) {
1347
1376
  const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
1348
1377
  invocation.generatorState = state;
1349
1378
  invocation.generatorAsync = asynchronous;
1350
- const protos = this.runtime.prototypes;
1351
- const result = (value, done) => record(protos.Object, { value, done });
1352
- const request = (kind, value, node) => {
1379
+ const builtins = this.ctx.builtins;
1380
+ const result = (value, done) => record(builtins.Object, { value, done });
1381
+ const request = (kind, value) => {
1353
1382
  const request = { kind, value, response: Deferred.makeUnsafe() };
1354
- if (!asynchronous && state.active) {
1355
- return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node));
1356
- }
1383
+ if (!asynchronous && state.active)
1384
+ return Effect.die(typeError("Generator is already running."));
1357
1385
  if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
1358
1386
  state.started = true;
1359
1387
  state.completed = true;
@@ -1361,19 +1389,19 @@ class Frame {
1361
1389
  if (state.draining)
1362
1390
  return Deferred.await(request.response);
1363
1391
  state.draining = true;
1364
- return Effect.andThen(this.runtime.promises.fork(invocation
1392
+ return Effect.andThen(this.ctx.pending.fork(invocation
1365
1393
  .completeGeneratorRequests(state, true)
1366
1394
  .pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
1367
1395
  }
1368
1396
  if (state.completed) {
1369
1397
  if (kind === "throw")
1370
- return Effect.fail(new ProgramThrow(value));
1398
+ return Effect.fail(new Throw(value));
1371
1399
  return Effect.succeed(result(kind === "return" ? value : undefined, true));
1372
1400
  }
1373
1401
  if (!state.started && kind !== "next") {
1374
1402
  state.completed = true;
1375
1403
  if (kind === "throw")
1376
- return Effect.fail(new ProgramThrow(value));
1404
+ return Effect.fail(new Throw(value));
1377
1405
  return Effect.succeed(result(value, true));
1378
1406
  }
1379
1407
  state.pending.push(request);
@@ -1399,23 +1427,23 @@ class Frame {
1399
1427
  yield* invocation.completeGeneratorRequests(state, asynchronous);
1400
1428
  state.completed = true;
1401
1429
  });
1402
- return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
1430
+ return Effect.andThen(this.ctx.pending.fork(body), Deferred.await(request.response));
1403
1431
  }
1404
1432
  return Deferred.await(request.response);
1405
1433
  };
1406
- const generator = new ProgramGenerator(asynchronous ? protos.AsyncGenerator : protos.Generator, asynchronous, request);
1434
+ const generator = new GeneratorObj(asynchronous ? builtins.AsyncGenerator : builtins.Generator, asynchronous, request);
1407
1435
  return generator;
1408
1436
  }
1409
1437
  completeGeneratorRequests(state, asynchronous) {
1410
1438
  const self = this;
1411
- const result = (value, done) => record(self.runtime.prototypes.Object, { value, done });
1439
+ const result = (value, done) => record(self.ctx.builtins.Object, { value, done });
1412
1440
  return Effect.gen(function* () {
1413
1441
  while (true) {
1414
1442
  const pending = self.dequeueGeneratorRequest(state);
1415
1443
  if (!pending)
1416
1444
  return;
1417
1445
  if (pending.kind === "throw") {
1418
- Deferred.doneUnsafe(pending.response, Exit.fail(new ProgramThrow(pending.value)));
1446
+ Deferred.doneUnsafe(pending.response, Exit.fail(new Throw(pending.value)));
1419
1447
  continue;
1420
1448
  }
1421
1449
  if (asynchronous && pending.kind === "return") {
@@ -1450,7 +1478,7 @@ class Frame {
1450
1478
  const self = this;
1451
1479
  return Effect.gen(function* () {
1452
1480
  if (!self.generatorState)
1453
- throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
1481
+ throw typeError("yield is only valid inside a generator.", node);
1454
1482
  if (node.delegate) {
1455
1483
  const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1456
1484
  return yield* self.delegateYield(value, node);
@@ -1463,15 +1491,15 @@ class Frame {
1463
1491
  suspendGenerator(value, node) {
1464
1492
  const state = this.generatorState;
1465
1493
  if (!state?.active)
1466
- throw new InterpreterRuntimeError("Generator has no active request.", node);
1467
- Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.runtime.prototypes.Object, { value, done: false })));
1494
+ throw typeError("Generator has no active request.", node);
1495
+ Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.ctx.builtins.Object, { value, done: false })));
1468
1496
  state.active = undefined;
1469
1497
  return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
1470
1498
  state.active = request;
1471
1499
  if (request.kind === "next")
1472
1500
  return Effect.succeed(request.value);
1473
1501
  if (request.kind === "throw")
1474
- return Effect.fail(new ProgramThrow(request.value));
1502
+ return Effect.fail(new Throw(request.value));
1475
1503
  return this.generatorAsync
1476
1504
  ? Effect.flatMap(this.awaitValue(request.value), (value) => Effect.fail(new GeneratorReturn(value)))
1477
1505
  : Effect.fail(new GeneratorReturn(request.value));
@@ -1480,14 +1508,15 @@ class Frame {
1480
1508
  delegateYield(value, node) {
1481
1509
  const self = this;
1482
1510
  return Effect.gen(function* () {
1483
- if (value instanceof ProgramArray ||
1511
+ if (value instanceof Arr ||
1484
1512
  typeof value === "string" ||
1485
- value instanceof ProgramMap ||
1486
- value instanceof ProgramSet ||
1487
- value instanceof ProgramURLSearchParams) {
1488
- const cursor = yield* self.syncIterator(value, node);
1513
+ value instanceof MapObj ||
1514
+ value instanceof SetObj ||
1515
+ value instanceof URLSearchParamsObj ||
1516
+ value instanceof Bytes) {
1517
+ const cursor = yield* self.iterate(value, node);
1489
1518
  if (!cursor)
1490
- throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
1519
+ throw typeError("Built-in iterator is unavailable.", node);
1491
1520
  while (true) {
1492
1521
  const step = yield* cursor.next;
1493
1522
  if (step.done)
@@ -1500,16 +1529,16 @@ class Frame {
1500
1529
  yield* cursor.close;
1501
1530
  return yield* Effect.fail(error);
1502
1531
  }
1503
- if (error instanceof ProgramThrow) {
1532
+ if (error instanceof Throw) {
1504
1533
  yield* cursor.close;
1505
- throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
1534
+ throw typeError("The delegated iterator does not provide a throw() method.", node);
1506
1535
  }
1507
1536
  return yield* Effect.failCause(resumed.cause);
1508
1537
  }
1509
1538
  }
1510
1539
  const iterator = yield* self.customIterator(value, node, self.generatorAsync);
1511
1540
  if (!iterator)
1512
- throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node);
1541
+ throw typeError("yield* requires a compatible iterable value.", node);
1513
1542
  let kind = "next";
1514
1543
  let input = undefined;
1515
1544
  while (true) {
@@ -1518,9 +1547,9 @@ class Frame {
1518
1547
  if (kind === "return")
1519
1548
  return yield* Effect.fail(new GeneratorReturn(input));
1520
1549
  yield* self.closeIterator(iterator, node, self.generatorAsync);
1521
- throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
1550
+ throw typeError("The delegated iterator does not provide a throw() method.", node);
1522
1551
  }
1523
- const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), iterator.iterator, [input], node);
1552
+ const called = yield* self.call(self.requireIteratorMethod(method, `Iterator ${kind}`, node), iterator.iterator, [input], node);
1524
1553
  const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
1525
1554
  const done = Boolean(get(result, "done"));
1526
1555
  const resultValue = self.generatorAsync && !iterator.asynchronous
@@ -1538,7 +1567,7 @@ class Frame {
1538
1567
  continue;
1539
1568
  }
1540
1569
  const error = Cause.squash(resumed.cause);
1541
- if (!(error instanceof GeneratorReturn) && !(error instanceof ProgramThrow)) {
1570
+ if (!(error instanceof GeneratorReturn) && !(error instanceof Throw)) {
1542
1571
  return yield* Effect.failCause(resumed.cause);
1543
1572
  }
1544
1573
  kind = error instanceof GeneratorReturn ? "return" : "throw";
@@ -1547,7 +1576,7 @@ class Frame {
1547
1576
  });
1548
1577
  }
1549
1578
  evaluateObjectExpression(node) {
1550
- const objectValue = new ProgramObject(this.runtime.prototypes.Object);
1579
+ const objectValue = new Obj(this.ctx.builtins.Object);
1551
1580
  const self = this;
1552
1581
  return Effect.gen(function* () {
1553
1582
  for (const property of node.properties) {
@@ -1555,11 +1584,11 @@ class Frame {
1555
1584
  const spread = yield* self.evaluateExpression(property.argument);
1556
1585
  if (spread === null || spread === undefined)
1557
1586
  continue;
1558
- assign(objectValue, enumerableSource(self.runtime.runner, "Object spread", spread, property));
1587
+ assign(objectValue, enumerableSource(self.ctx, "Object spread", spread, property));
1559
1588
  continue;
1560
1589
  }
1561
1590
  if (property.kind !== "init") {
1562
- throw new InterpreterRuntimeError("Only init object properties are supported.", property);
1591
+ throw typeError("Only init object properties are supported.", property);
1563
1592
  }
1564
1593
  const keyNode = property.key;
1565
1594
  let key;
@@ -1573,7 +1602,7 @@ class Frame {
1573
1602
  key = self.toPropertyKey(keyNode.value, keyNode);
1574
1603
  }
1575
1604
  else {
1576
- throw new InterpreterRuntimeError("Unsupported object property key shape.", keyNode);
1605
+ throw typeError("Unsupported object property key shape.", keyNode);
1577
1606
  }
1578
1607
  const name = key === IteratorSymbol
1579
1608
  ? "[Symbol.iterator]"
@@ -1597,9 +1626,9 @@ class Frame {
1597
1626
  }
1598
1627
  if (element.type === "SpreadElement") {
1599
1628
  const spread = yield* self.evaluateExpression(element.argument);
1600
- const cursor = yield* self.syncIterator(spread, element);
1629
+ const cursor = yield* self.iterate(spread, element);
1601
1630
  if (cursor === undefined)
1602
- throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element);
1631
+ throw typeError("Array spread requires a synchronous iterable.", element);
1603
1632
  while (true) {
1604
1633
  const step = yield* cursor.next;
1605
1634
  if (step.done)
@@ -1611,7 +1640,7 @@ class Frame {
1611
1640
  values.push(yield* self.evaluateExpression(element));
1612
1641
  }
1613
1642
  }
1614
- return new ProgramArray(self.runtime.prototypes.Array, values);
1643
+ return new Arr(self.ctx.builtins.Array, values);
1615
1644
  });
1616
1645
  }
1617
1646
  evaluateTemplateLiteral(node) {
@@ -1624,12 +1653,14 @@ class Frame {
1624
1653
  const quasi = quasis[index];
1625
1654
  // acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
1626
1655
  if (typeof quasi.value.cooked !== "string") {
1627
- throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
1656
+ throw typeError("Invalid template literal quasi.", quasi);
1628
1657
  }
1629
1658
  output += quasi.value.cooked;
1659
+ checkStringLength(output.length);
1630
1660
  if (index < expressions.length) {
1631
1661
  const raw = yield* self.evaluateExpression(expressions[index]);
1632
- output += coerceToString(toProgram(self.runtime.prototypes, raw, "Template interpolation"));
1662
+ output += coerceToString(raw);
1663
+ checkStringLength(output.length);
1633
1664
  }
1634
1665
  }
1635
1666
  return output;
@@ -1640,7 +1671,7 @@ class Frame {
1640
1671
  }
1641
1672
  applyCompoundAssignment(operator, current, incoming, node) {
1642
1673
  if (!compoundOperators.has(operator)) {
1643
- throw new InterpreterRuntimeError(`Unsupported assignment operator '${operator}'.`, node);
1674
+ throw typeError(`Unsupported assignment operator '${operator}'.`, node);
1644
1675
  }
1645
1676
  return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
1646
1677
  }
@@ -1665,39 +1696,43 @@ class Frame {
1665
1696
  : self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
1666
1697
  if (objectValue instanceof ToolReference) {
1667
1698
  if (typeof key !== "string") {
1668
- throw new InterpreterRuntimeError("Tool paths must use string property names.", propertyNode);
1699
+ throw typeError("Tool paths must use string property names.", propertyNode);
1669
1700
  }
1670
1701
  return new ToolReference([...objectValue.path, key]);
1671
1702
  }
1672
- if (objectValue instanceof ProgramObject)
1703
+ if (objectValue instanceof Obj)
1673
1704
  return { target: objectValue, key, receiver: objectValue };
1674
1705
  // Primitives read through their wrapper prototype without being boxed; strings own length and indexes.
1675
- const protos = self.runtime.prototypes;
1706
+ const builtins = self.ctx.builtins;
1676
1707
  if (typeof objectValue === "string") {
1677
1708
  if (key === "length")
1678
1709
  return { value: objectValue.length };
1679
1710
  const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
1680
1711
  if (index !== undefined)
1681
1712
  return { value: objectValue[index] };
1682
- return { target: protos.String, key, receiver: objectValue };
1713
+ return { target: builtins.String, key, receiver: objectValue };
1683
1714
  }
1684
1715
  if (typeof objectValue === "number")
1685
- return { target: protos.Number, key, receiver: objectValue };
1716
+ return { target: builtins.Number, key, receiver: objectValue };
1686
1717
  if (typeof objectValue === "boolean")
1687
- return { target: protos.Boolean, key, receiver: objectValue };
1718
+ return { target: builtins.Boolean, key, receiver: objectValue };
1688
1719
  if (objectValue === null || objectValue === undefined) {
1689
- throw new InterpreterRuntimeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
1720
+ throw typeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
1690
1721
  }
1691
- throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
1722
+ throw typeError("Cannot access a property on a non-object value.", objectNode);
1692
1723
  });
1693
1724
  }
1694
1725
  readReference(reference, node) {
1695
1726
  // Reject unknown promise properties so a missing await cannot hide.
1696
- if (reference.target instanceof ProgramPromise && !has(reference.target, reference.key)) {
1697
- throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", node.object, "InvalidDataValue");
1727
+ if (reference.target instanceof PromiseObj && !has(reference.target, reference.key)) {
1728
+ throw invalidData("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", node.object);
1698
1729
  }
1730
+ return this.readProperty(reference.target, reference.key, node, reference.receiver);
1731
+ }
1732
+ // Accessors throw without a location; the member or pattern that read them supplies it.
1733
+ readProperty(target, key, node, receiver = target) {
1699
1734
  try {
1700
- return get(reference.target, reference.key, reference.receiver);
1735
+ return get(target, key, receiver);
1701
1736
  }
1702
1737
  catch (error) {
1703
1738
  throw locate(error, node);
@@ -1720,17 +1755,17 @@ class Frame {
1720
1755
  evaluateDeleteExpression(argument) {
1721
1756
  const target = argument.type === "ChainExpression" ? argument.expression : argument;
1722
1757
  if (target.type !== "MemberExpression") {
1723
- throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
1758
+ throw typeError("Only data fields may be deleted.", argument);
1724
1759
  }
1725
1760
  return Effect.map(this.getMemberReference(target), (reference) => {
1726
1761
  if (reference === OptionalShortCircuit)
1727
1762
  return true;
1728
1763
  if (reference instanceof ToolReference || "value" in reference || reference.receiver !== reference.target) {
1729
- throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
1764
+ throw invalidData("Only data fields may be deleted.", target);
1730
1765
  }
1731
1766
  if (remove(reference.target, reference.key))
1732
1767
  return true;
1733
- throw new InterpreterRuntimeError(`Cannot delete property '${String(reference.key)}'.`, target);
1768
+ throw typeError(`Cannot delete property '${String(reference.key)}'.`, target);
1734
1769
  });
1735
1770
  }
1736
1771
  // Resolve side-effecting object and key expressions exactly once.
@@ -1739,10 +1774,10 @@ class Frame {
1739
1774
  return Effect.gen(function* () {
1740
1775
  const reference = yield* self.getMemberReference(node);
1741
1776
  if (reference === OptionalShortCircuit || reference instanceof ToolReference || "value" in reference) {
1742
- throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
1777
+ throw typeError("Only data fields may be assigned.", node);
1743
1778
  }
1744
1779
  if (reference.receiver !== reference.target) {
1745
- throw new InterpreterRuntimeError(`Cannot create property '${String(reference.key)}' on ${typeof reference.receiver} '${String(reference.receiver)}'.`, node);
1780
+ throw typeError(`Cannot create property '${String(reference.key)}' on ${typeof reference.receiver} '${String(reference.receiver)}'.`, node);
1746
1781
  }
1747
1782
  const key = reference.key;
1748
1783
  const { write, next, result } = yield* compute(self.readReference(reference, node));
@@ -1752,9 +1787,9 @@ class Frame {
1752
1787
  });
1753
1788
  }
1754
1789
  assignToReference(target, key, next, node) {
1755
- rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
1756
1790
  const written = (() => {
1757
1791
  try {
1792
+ rejectCircularInsertion(target, next, target instanceof Arr ? "Array assignment result" : "Object assignment result");
1758
1793
  return set(target, key, next);
1759
1794
  }
1760
1795
  catch (error) {
@@ -1763,9 +1798,9 @@ class Frame {
1763
1798
  })();
1764
1799
  if (written)
1765
1800
  return;
1766
- if (target instanceof ProgramArray && key === "length")
1801
+ if (target instanceof Arr && key === "length")
1767
1802
  throw rangeError("Invalid array length", node);
1768
- throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node);
1803
+ throw typeError(`Cannot assign to read only property '${String(key)}'.`, node);
1769
1804
  }
1770
1805
  toPropertyKey(value, node) {
1771
1806
  if (typeof value === "string" || typeof value === "number") {
@@ -1773,6 +1808,6 @@ class Frame {
1773
1808
  }
1774
1809
  if (value === AsyncIteratorSymbol || value === IteratorSymbol)
1775
1810
  return value;
1776
- throw new InterpreterRuntimeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node);
1811
+ throw typeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node);
1777
1812
  }
1778
1813
  }