@opencode/codemode 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/data.d.ts +6 -5
  2. package/dist/data.js +47 -44
  3. package/dist/index.d.ts +0 -1
  4. package/dist/index.js +0 -1
  5. package/dist/interpreter/errors.d.ts +5 -3
  6. package/dist/interpreter/errors.js +51 -22
  7. package/dist/interpreter/execute.js +5 -3
  8. package/dist/interpreter/generators.d.ts +4 -0
  9. package/dist/interpreter/generators.js +25 -0
  10. package/dist/interpreter/globals.js +69 -47
  11. package/dist/interpreter/intrinsics.d.ts +13 -0
  12. package/dist/interpreter/intrinsics.js +82 -0
  13. package/dist/interpreter/model.d.ts +13 -36
  14. package/dist/interpreter/model.js +15 -45
  15. package/dist/interpreter/native.d.ts +19 -0
  16. package/dist/interpreter/native.js +40 -0
  17. package/dist/interpreter/objects.d.ts +106 -13
  18. package/dist/interpreter/objects.js +192 -65
  19. package/dist/interpreter/promises.d.ts +12 -13
  20. package/dist/interpreter/promises.js +59 -54
  21. package/dist/interpreter/references.d.ts +1 -0
  22. package/dist/interpreter/references.js +20 -33
  23. package/dist/interpreter/runner.d.ts +15 -11
  24. package/dist/interpreter/runner.js +21 -21
  25. package/dist/interpreter/runtime.d.ts +3 -3
  26. package/dist/interpreter/runtime.js +165 -327
  27. package/dist/interpreter/scope.js +6 -6
  28. package/dist/stdlib/array.d.ts +4 -2
  29. package/dist/stdlib/array.js +424 -32
  30. package/dist/stdlib/collections.d.ts +3 -7
  31. package/dist/stdlib/collections.js +291 -119
  32. package/dist/stdlib/console.d.ts +3 -2
  33. package/dist/stdlib/console.js +35 -30
  34. package/dist/stdlib/date.d.ts +1 -7
  35. package/dist/stdlib/date.js +93 -188
  36. package/dist/stdlib/json.d.ts +2 -2
  37. package/dist/stdlib/json.js +27 -27
  38. package/dist/stdlib/math.d.ts +2 -2
  39. package/dist/stdlib/math.js +96 -76
  40. package/dist/stdlib/number.d.ts +3 -4
  41. package/dist/stdlib/number.js +95 -60
  42. package/dist/stdlib/object.d.ts +4 -4
  43. package/dist/stdlib/object.js +128 -54
  44. package/dist/stdlib/regexp.d.ts +6 -8
  45. package/dist/stdlib/regexp.js +76 -68
  46. package/dist/stdlib/string.d.ts +2 -2
  47. package/dist/stdlib/string.js +213 -50
  48. package/dist/stdlib/url.d.ts +5 -13
  49. package/dist/stdlib/url.js +202 -102
  50. package/dist/stdlib/value.d.ts +5 -9
  51. package/dist/stdlib/value.js +16 -38
  52. package/dist/stdlib/web.d.ts +4 -4
  53. package/dist/stdlib/web.js +12 -10
  54. package/dist/tool-runtime.d.ts +2 -1
  55. package/dist/tool-runtime.js +2 -2
  56. package/package.json +1 -1
  57. package/dist/interpreter/host.d.ts +0 -41
  58. package/dist/interpreter/host.js +0 -44
  59. package/dist/interpreter/methods.d.ts +0 -4
  60. package/dist/interpreter/methods.js +0 -837
  61. package/dist/values.d.ts +0 -37
  62. package/dist/values.js +0 -56
@@ -1,25 +1,17 @@
1
1
  import { Cause, Deferred, Effect, Exit } from "effect";
2
- import { ToolRuntimeError, toProgram } from "../data.js";
2
+ import { toProgram } from "../data.js";
3
3
  import { ToolReference } from "../tool-runtime.js";
4
- import { AsyncIteratorSymbol, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, IteratorSymbol, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
4
+ import { AsyncIteratorSymbol, GeneratorReturn, InterpreterRuntimeError, IteratorSymbol, locate, OptionalShortCircuit, ProgramThrow, rangeError, unsupportedSyntax, } from "./model.js";
5
5
  import { caughtErrorValue } from "./errors.js";
6
6
  import { globals } from "./globals.js";
7
- import { HostFunction, HostNamespace } from "./host.js";
8
- import { invokeIntrinsic } from "./methods.js";
9
- import { assign, get, has, ownKeys, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, record, remove, set, } from "./objects.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";
10
8
  import { preserveConsumerError } from "./runner.js";
11
- import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
12
- import { containsOpaqueReference, describeValue, isRuntimeReference, rejectCircularInsertion, typeofValue, } from "./references.js";
9
+ import { PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
10
+ import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
13
11
  import { ScopeStack } from "./scope.js";
14
- import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
15
- import { dateMethods } from "../stdlib/date.js";
16
- import { numberMethods } from "../stdlib/number.js";
17
- import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
18
- import { stringMethods } from "../stdlib/string.js";
19
- import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
12
+ import { constructRegExp } from "../stdlib/regexp.js";
20
13
  import { enumerableSource } from "../stdlib/object.js";
21
- import { coerceToNumber, coerceToString, compoundOperators, errorBrandName } from "../stdlib/value.js";
22
- import { Values } from "../values.js";
14
+ import { coerceToNumber, coerceToString, compoundOperators } from "../stdlib/value.js";
23
15
  // What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
24
16
  // Unlabelled break ends this loop; a label the loop does not carry propagates outward.
25
17
  const loopExit = (result, labels) => {
@@ -50,37 +42,16 @@ const calleeDescription = (callee) => {
50
42
  }
51
43
  return "The called value";
52
44
  };
53
- const constructorName = (value) => {
54
- if (typeof value === "string")
55
- return "String";
56
- if (typeof value === "number")
57
- return "Number";
58
- if (typeof value === "boolean")
59
- return "Boolean";
60
- if (value instanceof ProgramArray)
61
- return "Array";
62
- if (value instanceof Values.Date)
63
- return "Date";
64
- if (value instanceof Values.RegExp)
65
- return "RegExp";
66
- if (value instanceof Values.Map)
67
- return "Map";
68
- if (value instanceof Values.Set)
69
- return "Set";
70
- if (value instanceof Values.URL)
71
- return "URL";
72
- if (value instanceof Values.URLSearchParams)
73
- return "URLSearchParams";
74
- if (value instanceof Values.Promise)
75
- return "Promise";
76
- if (!(value instanceof ProgramObject) || value instanceof ProgramFunction)
77
- return undefined;
78
- return errorBrandName(value) ?? "Object";
79
- };
45
+ // OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
80
46
  const instanceofValue = (lhs, rhs, node) => {
81
- if (rhs instanceof HostFunction && rhs.instanceOf !== undefined)
82
- return rhs.instanceOf(lhs);
83
- throw new InterpreterRuntimeError("The right-hand side of 'instanceof' must be a supported constructor: Error (or a specific error type like TypeError), Date, RegExp, Map, Set, URL, URLSearchParams, Array, Object, or Promise.", node);
47
+ if (!(rhs instanceof Callable)) {
48
+ throw new InterpreterRuntimeError("The right-hand side of 'instanceof' is not callable.", node);
49
+ }
50
+ 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);
53
+ }
54
+ return hasPrototype(lhs, prototype);
84
55
  };
85
56
  const collectPatternNames = (pattern, out = []) => {
86
57
  switch (pattern.type) {
@@ -170,10 +141,6 @@ const loopDeclaration = (left, statement) => {
170
141
  lexical: kind !== "var",
171
142
  };
172
143
  };
173
- const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
174
- value instanceof PromiseInstanceMethodReference ||
175
- value instanceof IntrinsicReference ||
176
- value instanceof GeneratorMethodReference;
177
144
  const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
178
145
  /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
179
146
  export class Runtime {
@@ -181,29 +148,29 @@ export class Runtime {
181
148
  search;
182
149
  toolKeys;
183
150
  promises;
151
+ prototypes;
184
152
  logs;
185
153
  runner;
186
- /** Built-in globals by name, unaffected by program shadowing. */
187
- builtins;
188
154
  root;
189
- constructor(executeTool, search, toolKeys, promises, logs = [], extraGlobals = () => []) {
155
+ constructor(executeTool, search, toolKeys, promises, prototypes, logs = [], extraGlobals = () => []) {
190
156
  this.executeTool = executeTool;
191
157
  this.search = search;
192
158
  this.toolKeys = toolKeys;
193
159
  this.promises = promises;
160
+ this.prototypes = prototypes;
194
161
  this.logs = logs;
195
162
  const globalScope = new Map();
196
163
  // Calling back into the program never reads frame state, so any frame serves; the root is always alive.
197
164
  this.root = new Frame(this, new ScopeStack([globalScope]));
198
165
  this.runner = {
199
- invokeFunction: (fn, args) => this.root.invokeFunction(fn, args),
200
- invokeCallable: (callable, args, node) => this.root.invokeCallable(callable, args, node),
166
+ invokeCallable: (callable, thisValue, args, node) => this.root.invokeCallable(callable, thisValue, args, node),
201
167
  settlePromise: (promise) => this.root.settlePromise(promise),
202
168
  syncIterator: (value, node) => this.root.syncIterator(value, node),
169
+ prototypes,
203
170
  };
204
- this.builtins = new Map([...globals(this), ...extraGlobals(this)]);
205
- for (const [name, value] of this.builtins)
171
+ for (const [name, value] of [...globals(this), ...extraGlobals(this)]) {
206
172
  globalScope.set(name, { mutable: false, value });
173
+ }
207
174
  }
208
175
  run(program) {
209
176
  return this.root.run(program);
@@ -249,10 +216,7 @@ class Frame {
249
216
  }
250
217
  // Fork at the call site so admission and hooks occur when the call is made.
251
218
  createToolCallPromise(path, args) {
252
- return this.createPromise(Effect.suspend(() => this.runtime.executeTool(path, args)));
253
- }
254
- createPromise(effect) {
255
- return this.runtime.promises.create(effect);
219
+ return this.runtime.promises.create(Effect.suspend(() => this.runtime.executeTool(path, args)));
256
220
  }
257
221
  // Fiber exits make settlement idempotent; yielding prevents inline continuation.
258
222
  settlePromise(promise) {
@@ -325,7 +289,7 @@ class Frame {
325
289
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
326
290
  }
327
291
  createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
328
- return new ProgramFunction(name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
292
+ return new ProgramFunction(this.runtime.prototypes.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
329
293
  }
330
294
  // NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
331
295
  evaluateNamed(node, name) {
@@ -505,7 +469,7 @@ class Frame {
505
469
  const iterator = yield* self.customIterator(right, node, awaiting);
506
470
  const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
507
471
  if (iterator === undefined && cursor === undefined) {
508
- throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node).as("TypeError");
472
+ throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node);
509
473
  }
510
474
  const close = () => iterator
511
475
  ? self.closeIterator(iterator, node, awaiting)
@@ -579,20 +543,21 @@ class Frame {
579
543
  ? value.items[Symbol.iterator]()
580
544
  : typeof value === "string"
581
545
  ? value[Symbol.iterator]()
582
- : value instanceof Values.Map
546
+ : value instanceof ProgramMap
583
547
  ? value.map.entries()
584
- : value instanceof Values.Set
548
+ : value instanceof ProgramSet
585
549
  ? value.set.values()
586
- : value instanceof Values.URLSearchParams
550
+ : value instanceof ProgramURLSearchParams
587
551
  ? value.params.entries()
588
552
  : undefined;
589
553
  if (iterator !== undefined) {
554
+ const proto = this.runtime.prototypes.Array;
590
555
  return Effect.succeed({
591
556
  next: Effect.sync(() => {
592
557
  const step = iterator.next();
593
558
  return {
594
559
  done: Boolean(step.done),
595
- value: Array.isArray(step.value) ? new ProgramArray(step.value) : step.value,
560
+ value: Array.isArray(step.value) ? new ProgramArray(proto, step.value) : step.value,
596
561
  };
597
562
  }),
598
563
  close: Effect.void,
@@ -607,15 +572,6 @@ class Frame {
607
572
  });
608
573
  }
609
574
  customIterator(value, node, allowAsync = true) {
610
- if (value instanceof CodeModeGenerator) {
611
- if (value.asynchronous && !allowAsync)
612
- return Effect.undefined;
613
- return Effect.succeed({
614
- iterator: value,
615
- next: new GeneratorMethodReference(value, "next"),
616
- asynchronous: value.asynchronous,
617
- });
618
- }
619
575
  if (!(value instanceof ProgramObject))
620
576
  return Effect.undefined;
621
577
  const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
@@ -623,13 +579,11 @@ class Frame {
623
579
  if (method === undefined || method === null)
624
580
  return Effect.undefined;
625
581
  const self = this;
626
- return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), [], node), (iterator) => {
627
- const object = self.requireIterator(iterator, node);
582
+ return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), value, [], node), (iterator) => {
583
+ const object = self.requireIteratorObject(iterator, "Iterator method result", node);
628
584
  return {
629
585
  iterator: object,
630
- next: object instanceof CodeModeGenerator
631
- ? new GeneratorMethodReference(object, "next")
632
- : self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
586
+ next: self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
633
587
  asynchronous: asyncMethod !== undefined && asyncMethod !== null,
634
588
  };
635
589
  });
@@ -638,10 +592,10 @@ class Frame {
638
592
  const self = this;
639
593
  return Effect.gen(function* () {
640
594
  if (iterator.asynchronous) {
641
- const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
595
+ const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, iterator.iterator, [], node)), "Iterator next() result", node);
642
596
  return { done: Boolean(get(object, "done")), value: get(object, "value") };
643
597
  }
644
- const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
598
+ const called = yield* Effect.exit(self.invokeCallable(iterator.next, iterator.iterator, [], node));
645
599
  if (!Exit.isSuccess(called)) {
646
600
  if (awaiting)
647
601
  yield* Effect.yieldNow;
@@ -665,19 +619,17 @@ class Frame {
665
619
  });
666
620
  }
667
621
  closeIterator(iterator, node, awaiting = true) {
668
- const close = iterator.iterator instanceof CodeModeGenerator
669
- ? new GeneratorMethodReference(iterator.iterator, "return")
670
- : get(iterator.iterator, "return");
622
+ const close = get(iterator.iterator, "return");
671
623
  if (close === undefined || close === null)
672
624
  return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
673
625
  const self = this;
674
626
  return Effect.gen(function* () {
675
627
  const method = self.requireIteratorMethod(close, "Iterator return", node);
676
628
  if (iterator.asynchronous) {
677
- self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, [], node)), "Iterator return() result", node);
629
+ self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, iterator.iterator, [], node)), "Iterator return() result", node);
678
630
  return;
679
631
  }
680
- const called = yield* Effect.exit(self.invokeCallable(method, [], node));
632
+ const called = yield* Effect.exit(self.invokeCallable(method, iterator.iterator, [], node));
681
633
  if (!Exit.isSuccess(called)) {
682
634
  if (awaiting)
683
635
  yield* Effect.yieldNow;
@@ -696,17 +648,12 @@ class Frame {
696
648
  requireIteratorObject(value, context, node) {
697
649
  if (value instanceof ProgramObject)
698
650
  return value;
699
- throw new InterpreterRuntimeError(`${context} must be an object.`, node).as("TypeError");
700
- }
701
- requireIterator(value, node) {
702
- return value instanceof CodeModeGenerator
703
- ? value
704
- : this.requireIteratorObject(value, "Iterator method result", node);
651
+ throw new InterpreterRuntimeError(`${context} must be an object.`, node);
705
652
  }
706
653
  requireIteratorMethod(value, context, node) {
707
654
  if (typeofValue(value) === "function")
708
655
  return value;
709
- throw new InterpreterRuntimeError(`${context} must be a function.`, node).as("TypeError");
656
+ throw new InterpreterRuntimeError(`${context} must be a function.`, node);
710
657
  }
711
658
  // for...in over null/undefined iterates nothing, like JS.
712
659
  enumerableKeys(value, node) {
@@ -714,7 +661,7 @@ class Frame {
714
661
  return [...this.runtime.toolKeys(value.path)];
715
662
  if (value === null || value === undefined)
716
663
  return [];
717
- return ownKeys(enumerableSource("for...in", value, node)).filter((key) => typeof key === "string");
664
+ return keys(enumerableSource(this.runtime.runner, "for...in", value, node));
718
665
  }
719
666
  evaluateForInStatement(node, labels) {
720
667
  const left = node.left;
@@ -802,7 +749,7 @@ class Frame {
802
749
  if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
803
750
  return Effect.failCause(cause);
804
751
  }
805
- const caught = caughtErrorValue(Cause.squash(cause));
752
+ const caught = caughtErrorValue(self.runtime.runner, Cause.squash(cause));
806
753
  const parameter = handler.param;
807
754
  self.scopes.push();
808
755
  return Effect.gen(function* () {
@@ -868,14 +815,14 @@ class Frame {
868
815
  const consumed = new Set();
869
816
  for (const property of pattern.properties) {
870
817
  if (property.type === "RestElement") {
871
- const rest = new ProgramObject();
818
+ const rest = new ProgramObject(self.runtime.prototypes.Object);
872
819
  assign(rest, value, consumed);
873
820
  yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
874
821
  continue;
875
822
  }
876
823
  const key = yield* self.destructuringPropertyKey(property);
877
824
  consumed.add(typeof key === "symbol" ? key : String(key));
878
- yield* self.declarePattern(property.value, self.destructuringPropertyValue(value, key), mutable, property, initialize);
825
+ yield* self.declarePattern(property.value, get(value, key), mutable, property, initialize);
879
826
  }
880
827
  return;
881
828
  }
@@ -908,14 +855,14 @@ class Frame {
908
855
  const consumed = new Set();
909
856
  for (const property of pattern.properties) {
910
857
  if (property.type === "RestElement") {
911
- const rest = new ProgramObject();
858
+ const rest = new ProgramObject(self.runtime.prototypes.Object);
912
859
  assign(rest, value, consumed);
913
860
  yield* self.assignPattern(property.argument, rest, property);
914
861
  continue;
915
862
  }
916
863
  const key = yield* self.destructuringPropertyKey(property);
917
864
  consumed.add(typeof key === "symbol" ? key : String(key));
918
- yield* self.assignPattern(property.value, self.destructuringPropertyValue(value, key), property);
865
+ yield* self.assignPattern(property.value, get(value, key), property);
919
866
  }
920
867
  return;
921
868
  }
@@ -935,14 +882,14 @@ class Frame {
935
882
  return Effect.gen(function* () {
936
883
  const cursor = yield* self.syncIterator(value, pattern);
937
884
  if (cursor === undefined) {
938
- throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
885
+ throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern);
939
886
  }
940
887
  let done = false;
941
888
  for (const element of pattern.elements) {
942
889
  if (done) {
943
890
  if (element === null)
944
891
  continue;
945
- yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray() : undefined, element);
892
+ yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray(self.runtime.prototypes.Array) : undefined, element);
946
893
  if (element.type === "RestElement")
947
894
  return;
948
895
  continue;
@@ -961,7 +908,7 @@ class Frame {
961
908
  if (!done)
962
909
  rest.push(next.value);
963
910
  }
964
- yield* consume(element.argument, new ProgramArray(rest), element);
911
+ yield* consume(element.argument, new ProgramArray(self.runtime.prototypes.Array, rest), element);
965
912
  return;
966
913
  }
967
914
  const consumed = consume(element, step.done ? undefined : step.value, pattern);
@@ -985,22 +932,13 @@ class Frame {
985
932
  return Effect.succeed(String(keyNode.value));
986
933
  throw unsupportedSyntax(keyNode.type, keyNode);
987
934
  }
988
- destructuringPropertyValue(source, key) {
989
- if (!(source instanceof ProgramArray))
990
- return get(source, key);
991
- if (has(source, key))
992
- return get(source, key);
993
- if (typeof key === "string" && arrayMethods.has(key))
994
- return new IntrinsicReference(source, key);
995
- return undefined;
996
- }
997
935
  evaluateExpression(node) {
998
936
  switch (node.type) {
999
937
  case "Literal": {
1000
938
  const regex = node.regex;
1001
939
  if (regex)
1002
- return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
1003
- return Effect.sync(() => toProgram(node.value, "Literal"));
940
+ return Effect.sync(() => constructRegExp(this.runtime.prototypes, [regex.pattern, regex.flags], node));
941
+ return Effect.sync(() => toProgram(this.runtime.prototypes, node.value, "Literal"));
1004
942
  }
1005
943
  case "Identifier":
1006
944
  return Effect.sync(() => this.scopes.get(node.name, node));
@@ -1058,7 +996,7 @@ class Frame {
1058
996
  return Effect.gen(function* () {
1059
997
  const callee = yield* self.evaluateExpression(node.callee);
1060
998
  // Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
1061
- const construct = callee instanceof HostFunction ? callee.construct : undefined;
999
+ const construct = callee instanceof NativeFunction ? callee.construct : undefined;
1062
1000
  if (construct === undefined) {
1063
1001
  // `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
1064
1002
  // unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
@@ -1066,13 +1004,13 @@ class Frame {
1066
1004
  const name = calleeDescription(node.callee);
1067
1005
  const message = callee instanceof ProgramFunction
1068
1006
  ? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
1069
- : callee instanceof HostFunction
1007
+ : callee instanceof NativeFunction
1070
1008
  ? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
1071
1009
  : `${name} is not a constructor.`;
1072
- throw new InterpreterRuntimeError(message, node).as("TypeError");
1010
+ throw new InterpreterRuntimeError(message, node);
1073
1011
  }
1074
1012
  const args = yield* self.evaluateCallArguments(node.arguments);
1075
- return yield* construct(args, node);
1013
+ return yield* construct(args, callee, node);
1076
1014
  });
1077
1015
  }
1078
1016
  evaluateBinaryExpression(node) {
@@ -1086,7 +1024,7 @@ class Frame {
1086
1024
  const rhs = yield* self.evaluateExpression(node.right);
1087
1025
  if (operator === "instanceof")
1088
1026
  return instanceofValue(lhs, rhs, node);
1089
- return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
1027
+ return toProgram(self.runtime.prototypes, self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
1090
1028
  });
1091
1029
  }
1092
1030
  applyBinaryOperator(operator, lhs, rhs, node) {
@@ -1103,7 +1041,7 @@ class Frame {
1103
1041
  // Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
1104
1042
  // Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
1105
1043
  const coerceOperand = (operand) => {
1106
- if (operand instanceof Values.Date) {
1044
+ if (operand instanceof ProgramDate) {
1107
1045
  return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
1108
1046
  }
1109
1047
  return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
@@ -1188,7 +1126,7 @@ class Frame {
1188
1126
  if (containsOpaqueReference(value)) {
1189
1127
  throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
1190
1128
  }
1191
- const operand = value instanceof Values.Date
1129
+ const operand = value instanceof ProgramDate
1192
1130
  ? value.time
1193
1131
  : value !== null && typeof value === "object"
1194
1132
  ? coerceToString(value)
@@ -1207,7 +1145,7 @@ class Frame {
1207
1145
  default:
1208
1146
  throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
1209
1147
  }
1210
- return toProgram(result, "Unary expression result");
1148
+ return toProgram(this.runtime.prototypes, result, "Unary expression result");
1211
1149
  });
1212
1150
  }
1213
1151
  evaluateAssignmentExpression(node) {
@@ -1228,7 +1166,7 @@ class Frame {
1228
1166
  if (operator !== "=") {
1229
1167
  const current = self.scopes.get(name, left);
1230
1168
  const rightValue = yield* self.evaluateExpression(node.right);
1231
- const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1169
+ const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1232
1170
  return self.scopes.set(name, next, left);
1233
1171
  }
1234
1172
  const rightValue = yield* self.evaluateNamed(node.right, name);
@@ -1238,7 +1176,7 @@ class Frame {
1238
1176
  return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
1239
1177
  if (operator === "=")
1240
1178
  return { write: true, next: rightValue, result: rightValue };
1241
- const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1179
+ const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1242
1180
  return { write: true, next, result: next };
1243
1181
  }));
1244
1182
  }
@@ -1303,23 +1241,37 @@ class Frame {
1303
1241
  }
1304
1242
  throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
1305
1243
  }
1244
+ // EvaluateCall: a member callee supplies its base object as `this`; anything else calls with undefined.
1306
1245
  evaluateCallExpression(node) {
1307
1246
  const callee = node.callee;
1308
1247
  const self = this;
1309
1248
  return Effect.gen(function* () {
1310
1249
  if (callee.type === "Super")
1311
1250
  throw unsupportedSyntax(callee.type, callee);
1312
- const callable = yield* self.evaluateExpression(callee);
1251
+ const { callable, thisValue } = callee.type === "MemberExpression"
1252
+ ? yield* self.readMethod(callee)
1253
+ : { callable: yield* self.evaluateExpression(callee), thisValue: undefined };
1313
1254
  if (callable === OptionalShortCircuit)
1314
1255
  return OptionalShortCircuit;
1315
1256
  if ((callable === null || callable === undefined) && node.optional)
1316
1257
  return OptionalShortCircuit;
1317
1258
  const args = yield* self.evaluateCallArguments(node.arguments);
1318
- return yield* self.invokeCallable(callable, args, node, callee);
1259
+ return yield* self.invokeCallable(callable, thisValue, args, node, callee);
1260
+ });
1261
+ }
1262
+ readMethod(node) {
1263
+ return Effect.map(this.getMemberReference(node), (reference) => {
1264
+ if (reference === OptionalShortCircuit)
1265
+ return { callable: OptionalShortCircuit, thisValue: undefined };
1266
+ if (reference instanceof ToolReference)
1267
+ return { callable: reference, thisValue: undefined };
1268
+ if ("value" in reference)
1269
+ return { callable: reference.value, thisValue: undefined };
1270
+ return { callable: this.readReference(reference, node), thisValue: reference.receiver };
1319
1271
  });
1320
1272
  }
1321
1273
  // The single dispatch for every invocation: call expressions and callbacks share it.
1322
- invokeCallable(callable, args, node, callee) {
1274
+ invokeCallable(callable, thisValue, args, node, callee) {
1323
1275
  const self = this;
1324
1276
  return Effect.gen(function* () {
1325
1277
  if (callable instanceof ToolReference) {
@@ -1328,27 +1280,11 @@ class Frame {
1328
1280
  }
1329
1281
  return yield* self.createToolCallPromise(callable.path, args);
1330
1282
  }
1331
- if (callable instanceof ProgramFunction) {
1283
+ if (callable instanceof ProgramFunction)
1332
1284
  return yield* self.invokeFunction(callable, args);
1333
- }
1334
- if (callable instanceof GeneratorMethodReference) {
1335
- if (callable.kind === "iterator")
1336
- return callable.generator;
1337
- const requested = callable.generator.request(callable.kind, args[0], node);
1338
- return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
1339
- }
1340
- if (callable instanceof IntrinsicReference) {
1341
- return yield* invokeIntrinsic(self.runtime.runner, callable, args, node);
1342
- }
1343
- if (callable instanceof PromiseInstanceMethodReference) {
1344
- return yield* invokePromiseInstanceMethod(self.runtime.runner, self.runtime.promises, callable, args, node);
1345
- }
1346
- if (callable instanceof HostFunction)
1347
- return yield* callable.call(args, node);
1348
- if (callable === undefined || callable === null) {
1349
- throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
1350
- }
1351
- throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
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);
1352
1288
  });
1353
1289
  }
1354
1290
  evaluateCallArguments(argNodes) {
@@ -1360,7 +1296,7 @@ class Frame {
1360
1296
  const spread = yield* self.evaluateExpression(argNode.argument);
1361
1297
  const cursor = yield* self.syncIterator(spread, argNode);
1362
1298
  if (cursor === undefined)
1363
- throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
1299
+ throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode);
1364
1300
  while (true) {
1365
1301
  const step = yield* cursor.next;
1366
1302
  if (step.done)
@@ -1376,6 +1312,7 @@ class Frame {
1376
1312
  });
1377
1313
  }
1378
1314
  invokeFunction(fn, args) {
1315
+ const self = this;
1379
1316
  const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
1380
1317
  const run = Effect.gen(function* () {
1381
1318
  // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
@@ -1387,7 +1324,7 @@ class Frame {
1387
1324
  }
1388
1325
  for (const [index, parameter] of fn.parameters.entries()) {
1389
1326
  if (parameter.type === "RestElement") {
1390
- yield* invocation.declarePattern(parameter.argument, new ProgramArray(args.slice(index)), true, parameter, true);
1327
+ yield* invocation.declarePattern(parameter.argument, new ProgramArray(self.runtime.prototypes.Array, args.slice(index)), true, parameter, true);
1391
1328
  break;
1392
1329
  }
1393
1330
  yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
@@ -1410,10 +1347,12 @@ class Frame {
1410
1347
  const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
1411
1348
  invocation.generatorState = state;
1412
1349
  invocation.generatorAsync = asynchronous;
1413
- const generator = new CodeModeGenerator(asynchronous, (kind, value, node) => {
1350
+ const protos = this.runtime.prototypes;
1351
+ const result = (value, done) => record(protos.Object, { value, done });
1352
+ const request = (kind, value, node) => {
1414
1353
  const request = { kind, value, response: Deferred.makeUnsafe() };
1415
1354
  if (!asynchronous && state.active) {
1416
- return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node).as("TypeError"));
1355
+ return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node));
1417
1356
  }
1418
1357
  if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
1419
1358
  state.started = true;
@@ -1429,13 +1368,13 @@ class Frame {
1429
1368
  if (state.completed) {
1430
1369
  if (kind === "throw")
1431
1370
  return Effect.fail(new ProgramThrow(value));
1432
- return Effect.succeed(record({ value: kind === "return" ? value : undefined, done: true }));
1371
+ return Effect.succeed(result(kind === "return" ? value : undefined, true));
1433
1372
  }
1434
1373
  if (!state.started && kind !== "next") {
1435
1374
  state.completed = true;
1436
1375
  if (kind === "throw")
1437
1376
  return Effect.fail(new ProgramThrow(value));
1438
- return Effect.succeed(record({ value, done: true }));
1377
+ return Effect.succeed(result(value, true));
1439
1378
  }
1440
1379
  state.pending.push(request);
1441
1380
  if (state.available) {
@@ -1455,7 +1394,7 @@ class Frame {
1455
1394
  const active = state.active;
1456
1395
  state.active = undefined;
1457
1396
  if (active) {
1458
- Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(record({ value: exit.value, done: true })) : exit);
1397
+ Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(result(exit.value, true)) : exit);
1459
1398
  }
1460
1399
  yield* invocation.completeGeneratorRequests(state, asynchronous);
1461
1400
  state.completed = true;
@@ -1463,11 +1402,13 @@ class Frame {
1463
1402
  return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
1464
1403
  }
1465
1404
  return Deferred.await(request.response);
1466
- });
1405
+ };
1406
+ const generator = new ProgramGenerator(asynchronous ? protos.AsyncGenerator : protos.Generator, asynchronous, request);
1467
1407
  return generator;
1468
1408
  }
1469
1409
  completeGeneratorRequests(state, asynchronous) {
1470
1410
  const self = this;
1411
+ const result = (value, done) => record(self.runtime.prototypes.Object, { value, done });
1471
1412
  return Effect.gen(function* () {
1472
1413
  while (true) {
1473
1414
  const pending = self.dequeueGeneratorRequest(state);
@@ -1479,10 +1420,10 @@ class Frame {
1479
1420
  }
1480
1421
  if (asynchronous && pending.kind === "return") {
1481
1422
  const resolved = yield* Effect.exit(self.awaitValue(pending.value));
1482
- Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(record({ value: resolved.value, done: true })) : resolved);
1423
+ Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(result(resolved.value, true)) : resolved);
1483
1424
  continue;
1484
1425
  }
1485
- Deferred.doneUnsafe(pending.response, Exit.succeed(record({ value: pending.kind === "return" ? pending.value : undefined, done: true })));
1426
+ Deferred.doneUnsafe(pending.response, Exit.succeed(result(pending.kind === "return" ? pending.value : undefined, true)));
1486
1427
  }
1487
1428
  });
1488
1429
  }
@@ -1523,7 +1464,7 @@ class Frame {
1523
1464
  const state = this.generatorState;
1524
1465
  if (!state?.active)
1525
1466
  throw new InterpreterRuntimeError("Generator has no active request.", node);
1526
- Deferred.doneUnsafe(state.active.response, Exit.succeed(record({ value, done: false })));
1467
+ Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.runtime.prototypes.Object, { value, done: false })));
1527
1468
  state.active = undefined;
1528
1469
  return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
1529
1470
  state.active = request;
@@ -1541,9 +1482,9 @@ class Frame {
1541
1482
  return Effect.gen(function* () {
1542
1483
  if (value instanceof ProgramArray ||
1543
1484
  typeof value === "string" ||
1544
- value instanceof Values.Map ||
1545
- value instanceof Values.Set ||
1546
- value instanceof Values.URLSearchParams) {
1485
+ value instanceof ProgramMap ||
1486
+ value instanceof ProgramSet ||
1487
+ value instanceof ProgramURLSearchParams) {
1547
1488
  const cursor = yield* self.syncIterator(value, node);
1548
1489
  if (!cursor)
1549
1490
  throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
@@ -1561,29 +1502,25 @@ class Frame {
1561
1502
  }
1562
1503
  if (error instanceof ProgramThrow) {
1563
1504
  yield* cursor.close;
1564
- throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1505
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
1565
1506
  }
1566
1507
  return yield* Effect.failCause(resumed.cause);
1567
1508
  }
1568
1509
  }
1569
1510
  const iterator = yield* self.customIterator(value, node, self.generatorAsync);
1570
1511
  if (!iterator)
1571
- throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node).as("TypeError");
1512
+ throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node);
1572
1513
  let kind = "next";
1573
1514
  let input = undefined;
1574
1515
  while (true) {
1575
- const method = kind === "next"
1576
- ? iterator.next
1577
- : iterator.iterator instanceof CodeModeGenerator
1578
- ? new GeneratorMethodReference(iterator.iterator, kind)
1579
- : get(iterator.iterator, kind);
1516
+ const method = kind === "next" ? iterator.next : get(iterator.iterator, kind);
1580
1517
  if (method === undefined || method === null) {
1581
1518
  if (kind === "return")
1582
1519
  return yield* Effect.fail(new GeneratorReturn(input));
1583
1520
  yield* self.closeIterator(iterator, node, self.generatorAsync);
1584
- throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1521
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
1585
1522
  }
1586
- const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
1523
+ const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), iterator.iterator, [input], node);
1587
1524
  const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
1588
1525
  const done = Boolean(get(result, "done"));
1589
1526
  const resultValue = self.generatorAsync && !iterator.asynchronous
@@ -1610,7 +1547,7 @@ class Frame {
1610
1547
  });
1611
1548
  }
1612
1549
  evaluateObjectExpression(node) {
1613
- const objectValue = new ProgramObject();
1550
+ const objectValue = new ProgramObject(this.runtime.prototypes.Object);
1614
1551
  const self = this;
1615
1552
  return Effect.gen(function* () {
1616
1553
  for (const property of node.properties) {
@@ -1618,7 +1555,7 @@ class Frame {
1618
1555
  const spread = yield* self.evaluateExpression(property.argument);
1619
1556
  if (spread === null || spread === undefined)
1620
1557
  continue;
1621
- assign(objectValue, enumerableSource("Object spread", spread, property));
1558
+ assign(objectValue, enumerableSource(self.runtime.runner, "Object spread", spread, property));
1622
1559
  continue;
1623
1560
  }
1624
1561
  if (property.kind !== "init") {
@@ -1643,7 +1580,7 @@ class Frame {
1643
1580
  : key === AsyncIteratorSymbol
1644
1581
  ? "[Symbol.asyncIterator]"
1645
1582
  : String(key);
1646
- set(objectValue, key, yield* self.evaluateNamed(property.value, name));
1583
+ define(objectValue, key, yield* self.evaluateNamed(property.value, name));
1647
1584
  }
1648
1585
  return objectValue;
1649
1586
  });
@@ -1662,7 +1599,7 @@ class Frame {
1662
1599
  const spread = yield* self.evaluateExpression(element.argument);
1663
1600
  const cursor = yield* self.syncIterator(spread, element);
1664
1601
  if (cursor === undefined)
1665
- throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
1602
+ throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element);
1666
1603
  while (true) {
1667
1604
  const step = yield* cursor.next;
1668
1605
  if (step.done)
@@ -1674,7 +1611,7 @@ class Frame {
1674
1611
  values.push(yield* self.evaluateExpression(element));
1675
1612
  }
1676
1613
  }
1677
- return new ProgramArray(values);
1614
+ return new ProgramArray(self.runtime.prototypes.Array, values);
1678
1615
  });
1679
1616
  }
1680
1617
  evaluateTemplateLiteral(node) {
@@ -1692,7 +1629,7 @@ class Frame {
1692
1629
  output += quasi.value.cooked;
1693
1630
  if (index < expressions.length) {
1694
1631
  const raw = yield* self.evaluateExpression(expressions[index]);
1695
- output += coerceToString(toProgram(raw, "Template interpolation"));
1632
+ output += coerceToString(toProgram(self.runtime.prototypes, raw, "Template interpolation"));
1696
1633
  }
1697
1634
  }
1698
1635
  return output;
@@ -1707,7 +1644,7 @@ class Frame {
1707
1644
  }
1708
1645
  return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
1709
1646
  }
1710
- getMemberReference(node, operation = "read") {
1647
+ getMemberReference(node) {
1711
1648
  const objectNode = node.object;
1712
1649
  const propertyNode = node.property;
1713
1650
  if (objectNode.type === "Super")
@@ -1732,123 +1669,49 @@ class Frame {
1732
1669
  }
1733
1670
  return new ToolReference([...objectValue.path, key]);
1734
1671
  }
1735
- if (objectValue instanceof HostFunction || objectValue instanceof HostNamespace) {
1736
- // Unknown static members read as undefined so feature detection works like native JS.
1737
- return new ComputedValue(objectValue.member(key, propertyNode));
1738
- }
1739
- // Values have no prototype chain, so `.constructor` resolves to the owning built-in directly.
1740
- if (operation === "read" &&
1741
- key === "constructor" &&
1742
- !(objectValue instanceof ProgramObject && has(objectValue, key))) {
1743
- const name = constructorName(objectValue);
1744
- if (name !== undefined)
1745
- return new ComputedValue(self.runtime.builtins.get(name));
1746
- }
1672
+ if (objectValue instanceof ProgramObject)
1673
+ return { target: objectValue, key, receiver: objectValue };
1674
+ // Primitives read through their wrapper prototype without being boxed; strings own length and indexes.
1675
+ const protos = self.runtime.prototypes;
1747
1676
  if (typeof objectValue === "string") {
1748
1677
  if (key === "length")
1749
- return new ComputedValue(objectValue.length);
1678
+ return { value: objectValue.length };
1750
1679
  const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
1751
1680
  if (index !== undefined)
1752
- return new ComputedValue(objectValue[index]);
1753
- if (typeof key === "string" && stringMethods.has(key))
1754
- return new IntrinsicReference(objectValue, key);
1755
- return new ComputedValue(undefined);
1756
- }
1757
- if (typeof objectValue === "number") {
1758
- if (typeof key === "string" && numberMethods.has(key))
1759
- return new IntrinsicReference(objectValue, key);
1760
- return new ComputedValue(undefined);
1761
- }
1762
- if (objectValue instanceof Values.Date) {
1763
- if (typeof key === "string" && dateMethods.has(key))
1764
- return new IntrinsicReference(objectValue, key);
1765
- return new ComputedValue(undefined);
1766
- }
1767
- if (objectValue instanceof Values.RegExp) {
1768
- if (key === "lastIndex")
1769
- return { target: objectValue, key };
1770
- if (typeof key === "string" && regexpProperties.has(key)) {
1771
- return new ComputedValue(objectValue.regex[key]);
1772
- }
1773
- if (typeof key === "string" && regexpMethods.has(key))
1774
- return new IntrinsicReference(objectValue, key);
1775
- return new ComputedValue(undefined);
1776
- }
1777
- if (objectValue instanceof Values.Map) {
1778
- if (key === "size")
1779
- return new ComputedValue(objectValue.map.size);
1780
- if (typeof key === "string" && mapMethods.has(key))
1781
- return new IntrinsicReference(objectValue, key);
1782
- return new ComputedValue(undefined);
1783
- }
1784
- if (objectValue instanceof Values.Set) {
1785
- if (key === "size")
1786
- return new ComputedValue(objectValue.set.size);
1787
- if (typeof key === "string" && setMethods.has(key))
1788
- return new IntrinsicReference(objectValue, key);
1789
- return new ComputedValue(undefined);
1790
- }
1791
- if (objectValue instanceof Values.URL) {
1792
- if (key === "searchParams") {
1793
- return new ComputedValue(objectValue.searchParams);
1794
- }
1795
- if (typeof key === "string" && urlMethods.has(key))
1796
- return new IntrinsicReference(objectValue, key);
1797
- if (typeof key === "string" && urlProperties.has(key))
1798
- return { target: objectValue, key };
1799
- return new ComputedValue(undefined);
1800
- }
1801
- if (objectValue instanceof Values.URLSearchParams) {
1802
- if (key === "size")
1803
- return new ComputedValue(objectValue.params.size);
1804
- if (typeof key === "string" && urlSearchParamsMethods.has(key)) {
1805
- return new IntrinsicReference(objectValue, key);
1806
- }
1807
- return new ComputedValue(undefined);
1808
- }
1809
- // Reject unknown promise properties so a missing await cannot hide.
1810
- if (objectValue instanceof Values.Promise) {
1811
- if (key === "then" || key === "catch" || key === "finally") {
1812
- return new PromiseInstanceMethodReference(objectValue, key);
1813
- }
1814
- throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", objectNode, "InvalidDataValue");
1815
- }
1816
- if (objectValue instanceof CodeModeGenerator) {
1817
- if (key === "next" || key === "return" || key === "throw") {
1818
- return new GeneratorMethodReference(objectValue, key);
1819
- }
1820
- if ((key === IteratorSymbol && !objectValue.asynchronous) ||
1821
- (key === AsyncIteratorSymbol && objectValue.asynchronous)) {
1822
- return new GeneratorMethodReference(objectValue, "iterator");
1823
- }
1824
- return new ComputedValue(undefined);
1681
+ return { value: objectValue[index] };
1682
+ return { target: protos.String, key, receiver: objectValue };
1825
1683
  }
1826
- if (objectValue instanceof ProgramObject)
1827
- return { target: objectValue, key };
1828
- if (isRuntimeReference(objectValue)) {
1829
- throw new InterpreterRuntimeError(`Cannot read properties of ${describeValue(objectValue)}; only data values expose properties.`, objectNode, "InvalidDataValue");
1684
+ if (typeof objectValue === "number")
1685
+ return { target: protos.Number, key, receiver: objectValue };
1686
+ if (typeof objectValue === "boolean")
1687
+ return { target: protos.Boolean, key, receiver: objectValue };
1688
+ if (objectValue === null || objectValue === undefined) {
1689
+ throw new InterpreterRuntimeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
1830
1690
  }
1831
1691
  throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
1832
1692
  });
1833
1693
  }
1694
+ readReference(reference, node) {
1695
+ // 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");
1698
+ }
1699
+ try {
1700
+ return get(reference.target, reference.key, reference.receiver);
1701
+ }
1702
+ catch (error) {
1703
+ throw locate(error, node);
1704
+ }
1705
+ }
1834
1706
  readMember(node) {
1835
- const self = this;
1836
1707
  return Effect.map(this.getMemberReference(node), (reference) => {
1837
1708
  if (reference === OptionalShortCircuit)
1838
1709
  return OptionalShortCircuit;
1839
- if (reference instanceof ComputedValue)
1840
- return reference.value;
1841
- if (reference === undefined || isOpaqueMemberReference(reference))
1710
+ if (reference instanceof ToolReference)
1842
1711
  return reference;
1843
- const value = self.readReferenceValue(reference, reference.key);
1844
- if (value === undefined &&
1845
- reference.target instanceof ProgramArray &&
1846
- typeof reference.key === "string" &&
1847
- arrayMethods.has(reference.key) &&
1848
- !has(reference.target, reference.key)) {
1849
- return new IntrinsicReference(reference.target, reference.key);
1850
- }
1851
- return value;
1712
+ if ("value" in reference)
1713
+ return reference.value;
1714
+ return this.readReference(reference, node);
1852
1715
  });
1853
1716
  }
1854
1717
  writeMember(node, value) {
@@ -1859,75 +1722,50 @@ class Frame {
1859
1722
  if (target.type !== "MemberExpression") {
1860
1723
  throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
1861
1724
  }
1862
- return Effect.map(this.getMemberReference(target, "delete"), (reference) => {
1725
+ return Effect.map(this.getMemberReference(target), (reference) => {
1863
1726
  if (reference === OptionalShortCircuit)
1864
1727
  return true;
1865
- if (reference instanceof ComputedValue ||
1866
- reference === undefined ||
1867
- isOpaqueMemberReference(reference) ||
1868
- reference.target instanceof Values.URL) {
1728
+ if (reference instanceof ToolReference || "value" in reference || reference.receiver !== reference.target) {
1869
1729
  throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
1870
1730
  }
1871
- if (reference.target instanceof Values.RegExp) {
1872
- return Reflect.deleteProperty(reference.target.regex, reference.key);
1873
- }
1874
- return remove(reference.target, reference.key);
1731
+ if (remove(reference.target, reference.key))
1732
+ return true;
1733
+ throw new InterpreterRuntimeError(`Cannot delete property '${String(reference.key)}'.`, target);
1875
1734
  });
1876
1735
  }
1877
1736
  // Resolve side-effecting object and key expressions exactly once.
1878
1737
  modifyMember(node, compute) {
1879
1738
  const self = this;
1880
1739
  return Effect.gen(function* () {
1881
- const reference = yield* self.getMemberReference(node, "write");
1882
- if (reference === OptionalShortCircuit ||
1883
- reference instanceof ComputedValue ||
1884
- reference === undefined ||
1885
- isOpaqueMemberReference(reference)) {
1740
+ const reference = yield* self.getMemberReference(node);
1741
+ if (reference === OptionalShortCircuit || reference instanceof ToolReference || "value" in reference) {
1886
1742
  throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
1887
1743
  }
1744
+ if (reference.receiver !== reference.target) {
1745
+ throw new InterpreterRuntimeError(`Cannot create property '${String(reference.key)}' on ${typeof reference.receiver} '${String(reference.receiver)}'.`, node);
1746
+ }
1888
1747
  const key = reference.key;
1889
- const { write, next, result } = yield* compute(self.readReferenceValue(reference, key));
1748
+ const { write, next, result } = yield* compute(self.readReference(reference, node));
1890
1749
  if (write)
1891
- self.assignToReference(reference, key, next, node);
1750
+ self.assignToReference(reference.target, key, next, node);
1892
1751
  return result;
1893
1752
  });
1894
1753
  }
1895
- readReferenceValue(reference, key) {
1896
- if (reference.target instanceof Values.URL) {
1897
- return Reflect.get(reference.target.url, key);
1898
- }
1899
- if (reference.target instanceof Values.RegExp)
1900
- return reference.target.lastIndex;
1901
- return get(reference.target, key);
1902
- }
1903
- assignToReference(reference, key, next, node) {
1904
- if (reference.target instanceof Values.URL) {
1905
- const property = key;
1906
- if (!urlWritableProperties.has(property)) {
1907
- throw new InterpreterRuntimeError(`URL.${property} is read-only.`, node).as("TypeError");
1908
- }
1754
+ assignToReference(target, key, next, node) {
1755
+ rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
1756
+ const written = (() => {
1909
1757
  try {
1910
- const url = reference.target.url;
1911
- url[property] = uriArgument(next, `URL.${property} value`);
1912
- return;
1758
+ return set(target, key, next);
1913
1759
  }
1914
1760
  catch (error) {
1915
- if (error instanceof InterpreterRuntimeError || error instanceof ToolRuntimeError)
1916
- throw error;
1917
- throw new InterpreterRuntimeError(`URL.${property} received an invalid value.`, node).as("TypeError");
1761
+ throw locate(error, node);
1918
1762
  }
1919
- }
1920
- if (reference.target instanceof Values.RegExp) {
1921
- reference.target.lastIndex = next;
1922
- return;
1923
- }
1924
- const target = reference.target;
1925
- rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
1926
- if (set(target, key, next))
1763
+ })();
1764
+ if (written)
1927
1765
  return;
1928
- if (target instanceof ProgramArray)
1929
- throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
1930
- throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node).as("TypeError");
1766
+ if (target instanceof ProgramArray && key === "length")
1767
+ throw rangeError("Invalid array length", node);
1768
+ throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node);
1931
1769
  }
1932
1770
  toPropertyKey(value, node) {
1933
1771
  if (typeof value === "string" || typeof value === "number") {