@opencode/codemode 2.0.1 → 2.0.2

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