@opencode/codemode 0.0.0-dev-19484 → 0.0.0-dev-19485

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.
@@ -1,5 +1,6 @@
1
1
  import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
2
2
  import { CodeModeFunction, InterpreterRuntimeError, ProgramThrow, PromiseInstanceMethodReference, } from "./model.js";
3
+ import { get, ProgramArray, ProgramObject, record } from "./objects.js";
3
4
  import { HostFunction, requiresNew, sync } from "./host.js";
4
5
  import { caughtErrorValue, normalizeError } from "./errors.js";
5
6
  import { typeofValue } from "./references.js";
@@ -88,9 +89,9 @@ export const resolvePromiseValue = (runner, value, node, own) => {
88
89
  return Effect.fail(selfResolutionError(node));
89
90
  if (value instanceof Values.Promise)
90
91
  return runner.settlePromise(value);
91
- if (value === null || typeof value !== "object" || !Object.hasOwn(value, "then"))
92
+ if (!(value instanceof ProgramObject))
92
93
  return Effect.succeed(value);
93
- const then = value.then;
94
+ const then = get(value, "then");
94
95
  if (typeofValue(then) !== "function")
95
96
  return Effect.succeed(value);
96
97
  return Effect.gen(function* () {
@@ -136,25 +137,22 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
136
137
  items.push(item);
137
138
  }
138
139
  if (name === "all") {
139
- return yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" }));
140
+ return new ProgramArray(yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
140
141
  }
141
142
  if (name === "allSettled") {
142
143
  const outcomes = [];
143
144
  for (const item of items) {
144
145
  const exit = yield* promises.await(item);
145
146
  if (Exit.isSuccess(exit)) {
146
- outcomes.push(Object.assign(Object.create(null), { status: "fulfilled", value: exit.value }));
147
+ outcomes.push(record({ status: "fulfilled", value: exit.value }));
147
148
  continue;
148
149
  }
149
150
  if (Cause.hasInterruptsOnly(exit.cause))
150
151
  return yield* Effect.failCause(exit.cause);
151
- outcomes.push(Object.assign(Object.create(null), {
152
- status: "rejected",
153
- reason: caughtErrorValue(Cause.squash(exit.cause)),
154
- }));
152
+ outcomes.push(record({ status: "rejected", reason: caughtErrorValue(Cause.squash(exit.cause)) }));
155
153
  }
156
154
  yield* Effect.yieldNow;
157
- return outcomes;
155
+ return new ProgramArray(outcomes);
158
156
  }
159
157
  if (name === "race") {
160
158
  if (items.length === 0) {
@@ -5,4 +5,3 @@ export declare const containsOpaqueReference: (value: unknown) => boolean;
5
5
  export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, node: AstNode, seen?: Set<object>) => void;
6
6
  export declare const describeValue: (value: unknown) => string;
7
7
  export declare const typeofValue: (value: unknown) => string;
8
- export declare const parseArrayIndex: (key: string | number) => number | undefined;
@@ -1,7 +1,8 @@
1
1
  import { ToolReference } from "../tool-runtime.js";
2
2
  import { Values } from "../values.js";
3
3
  import { HostFunction, HostNamespace } from "./host.js";
4
- import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, IteratorSymbol, PromiseInstanceMethodReference, } from "./model.js";
4
+ import { CodeModeFunction, CodeModeGenerator, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, PromiseInstanceMethodReference, } from "./model.js";
5
+ import { getOwn, ownKeys, ProgramArray, ProgramObject } from "./objects.js";
5
6
  export const isRuntimeReference = (value) => value instanceof HostFunction ||
6
7
  value instanceof HostNamespace ||
7
8
  value instanceof CodeModeFunction ||
@@ -13,13 +14,10 @@ export const isRuntimeReference = (value) => value instanceof HostFunction ||
13
14
  value instanceof Values.Promise ||
14
15
  Values.isValue(value);
15
16
  function* childValues(value) {
16
- for (const key of Reflect.ownKeys(value)) {
17
- if (!Object.prototype.propertyIsEnumerable.call(value, key))
18
- continue;
19
- if (typeof key === "symbol" && key !== AsyncIteratorSymbol && key !== IteratorSymbol)
20
- continue;
21
- yield Reflect.get(value, key);
22
- }
17
+ if (!(value instanceof ProgramObject))
18
+ return;
19
+ for (const key of ownKeys(value))
20
+ yield getOwn(value, key);
23
21
  }
24
22
  // Depth-first search over a value tree. `match` stops the walk; `skip` prunes a subtree without matching it.
25
23
  const find = (value, match, skip, seen) => {
@@ -53,7 +51,7 @@ export const rejectCircularInsertion = (container, value, label, node, seen = ne
53
51
  export const describeValue = (value) => {
54
52
  if (value === null)
55
53
  return "null";
56
- if (Array.isArray(value))
54
+ if (value instanceof ProgramArray)
57
55
  return "an array";
58
56
  if (value instanceof Values.Promise)
59
57
  return "an un-awaited Promise";
@@ -93,11 +91,3 @@ export const typeofValue = (value) => {
93
91
  return value.path.length > 0 ? "function" : "object";
94
92
  return typeof value;
95
93
  };
96
- const MAX_ARRAY_LENGTH = 4_294_967_295;
97
- export const parseArrayIndex = (key) => {
98
- const property = String(key);
99
- if (!/^(0|[1-9]\d*)$/.test(property))
100
- return undefined;
101
- const index = Number(property);
102
- return index < MAX_ARRAY_LENGTH ? index : undefined;
103
- };
@@ -3,6 +3,7 @@ import { Values } from "../values.js";
3
3
  import { coerceToString } from "../stdlib/value.js";
4
4
  import { HostFunction } from "./host.js";
5
5
  import { CodeModeFunction, InterpreterRuntimeError, IntrinsicReference } from "./model.js";
6
+ import { get, has, ProgramObject } from "./objects.js";
6
7
  import { typeofValue } from "./references.js";
7
8
  export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
8
9
  ? Effect.succeed(exit.value)
@@ -13,15 +14,17 @@ export const toPrimitive = (runner, value, hint, node) => {
13
14
  if (Values.isValue(value)) {
14
15
  return Effect.succeed(value instanceof Values.Date && hint === "number" ? value.time : coerceToString(value));
15
16
  }
16
- const object = value;
17
+ if (!(value instanceof ProgramObject))
18
+ return Effect.succeed(value);
17
19
  const order = hint === "number" ? ["valueOf", "toString"] : ["toString", "valueOf"];
18
20
  return Effect.gen(function* () {
19
21
  for (const method of order) {
20
- if (method === "toString" && !Object.hasOwn(object, "toString"))
22
+ if (method === "toString" && !has(value, "toString"))
21
23
  return coerceToString(value);
22
- if (!Object.hasOwn(object, method) || typeofValue(object[method]) !== "function")
24
+ const callable = get(value, method);
25
+ if (typeofValue(callable) !== "function")
23
26
  continue;
24
- const result = yield* runner.invokeCallable(object[method], [], node);
27
+ const result = yield* runner.invokeCallable(callable, [], node);
25
28
  if (result === null || (typeof result !== "object" && typeof result !== "function"))
26
29
  return result;
27
30
  }
@@ -1,14 +1,15 @@
1
1
  import { Cause, Deferred, Effect, Exit } from "effect";
2
2
  import { ToolRuntimeError, toProgram } from "../data.js";
3
3
  import { ToolReference } from "../tool-runtime.js";
4
- import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
4
+ import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, IteratorSymbol, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
5
5
  import { caughtErrorValue } from "./errors.js";
6
6
  import { globals } from "./globals.js";
7
7
  import { HostFunction, HostNamespace } from "./host.js";
8
8
  import { invokeIntrinsic } from "./methods.js";
9
+ import { assign, get, has, ownKeys, parseArrayIndex, ProgramArray, ProgramObject, record, remove, set, } from "./objects.js";
9
10
  import { preserveConsumerError } from "./runner.js";
10
11
  import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
11
- import { containsOpaqueReference, describeValue, isRuntimeReference, parseArrayIndex, rejectCircularInsertion, typeofValue, } from "./references.js";
12
+ import { containsOpaqueReference, describeValue, isRuntimeReference, rejectCircularInsertion, typeofValue, } from "./references.js";
12
13
  import { ScopeStack } from "./scope.js";
13
14
  import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
14
15
  import { dateMethods } from "../stdlib/date.js";
@@ -49,7 +50,6 @@ const calleeDescription = (callee) => {
49
50
  }
50
51
  return "The called value";
51
52
  };
52
- const hasOwn = (value, key) => value !== null && typeof value === "object" && Object.hasOwn(value, key);
53
53
  const constructorName = (value) => {
54
54
  if (typeof value === "string")
55
55
  return "String";
@@ -57,7 +57,7 @@ const constructorName = (value) => {
57
57
  return "Number";
58
58
  if (typeof value === "boolean")
59
59
  return "Boolean";
60
- if (Array.isArray(value))
60
+ if (value instanceof ProgramArray)
61
61
  return "Array";
62
62
  if (value instanceof Values.Date)
63
63
  return "Date";
@@ -73,7 +73,7 @@ const constructorName = (value) => {
73
73
  return "URLSearchParams";
74
74
  if (value instanceof Values.Promise)
75
75
  return "Promise";
76
- if (value === null || typeof value !== "object" || isRuntimeReference(value))
76
+ if (!(value instanceof ProgramObject))
77
77
  return undefined;
78
78
  return errorBrandName(value) ?? "Object";
79
79
  };
@@ -174,12 +174,6 @@ const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
174
174
  value instanceof PromiseInstanceMethodReference ||
175
175
  value instanceof IntrinsicReference ||
176
176
  value instanceof GeneratorMethodReference;
177
- const copyIteratorSymbols = (source, target, consumed) => {
178
- for (const symbol of IteratorSymbols) {
179
- if (!consumed?.has(symbol) && Object.hasOwn(source, symbol))
180
- Reflect.set(target, symbol, Reflect.get(source, symbol));
181
- }
182
- };
183
177
  const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
184
178
  /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
185
179
  export class Runtime {
@@ -574,8 +568,8 @@ class Frame {
574
568
  });
575
569
  }
576
570
  syncIterator(value, node) {
577
- const iterator = Array.isArray(value)
578
- ? value[Symbol.iterator]()
571
+ const iterator = value instanceof ProgramArray
572
+ ? value.items[Symbol.iterator]()
579
573
  : typeof value === "string"
580
574
  ? value[Symbol.iterator]()
581
575
  : value instanceof Values.Map
@@ -589,7 +583,10 @@ class Frame {
589
583
  return Effect.succeed({
590
584
  next: Effect.sync(() => {
591
585
  const step = iterator.next();
592
- return { done: Boolean(step.done), value: step.value };
586
+ return {
587
+ done: Boolean(step.done),
588
+ value: Array.isArray(step.value) ? new ProgramArray(step.value) : step.value,
589
+ };
593
590
  }),
594
591
  close: Effect.void,
595
592
  });
@@ -612,10 +609,10 @@ class Frame {
612
609
  asynchronous: value.asynchronous,
613
610
  });
614
611
  }
615
- if (!isRecord(value) || isRuntimeReference(value))
612
+ if (!(value instanceof ProgramObject))
616
613
  return Effect.undefined;
617
- const asyncMethod = allowAsync ? Reflect.get(value, AsyncIteratorSymbol) : undefined;
618
- const method = asyncMethod ?? Reflect.get(value, IteratorSymbol);
614
+ const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
615
+ const method = asyncMethod ?? get(value, IteratorSymbol);
619
616
  if (method === undefined || method === null)
620
617
  return Effect.undefined;
621
618
  const self = this;
@@ -625,7 +622,7 @@ class Frame {
625
622
  iterator: object,
626
623
  next: object instanceof CodeModeGenerator
627
624
  ? new GeneratorMethodReference(object, "next")
628
- : self.requireIteratorMethod(object.next, "Iterator next", node),
625
+ : self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
629
626
  asynchronous: asyncMethod !== undefined && asyncMethod !== null,
630
627
  };
631
628
  });
@@ -635,7 +632,7 @@ class Frame {
635
632
  return Effect.gen(function* () {
636
633
  if (iterator.asynchronous) {
637
634
  const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
638
- return { done: Boolean(object.done), value: object.value };
635
+ return { done: Boolean(get(object, "done")), value: get(object, "value") };
639
636
  }
640
637
  const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
641
638
  if (!Exit.isSuccess(called)) {
@@ -645,7 +642,7 @@ class Frame {
645
642
  }
646
643
  const captured = yield* Effect.exit(Effect.sync(() => {
647
644
  const object = self.requireIteratorObject(called.value, "Iterator next() result", node);
648
- return { done: Boolean(object.done), value: object.value };
645
+ return { done: Boolean(get(object, "done")), value: get(object, "value") };
649
646
  }));
650
647
  if (!Exit.isSuccess(captured)) {
651
648
  if (awaiting)
@@ -663,7 +660,7 @@ class Frame {
663
660
  closeIterator(iterator, node, awaiting = true) {
664
661
  const close = iterator.iterator instanceof CodeModeGenerator
665
662
  ? new GeneratorMethodReference(iterator.iterator, "return")
666
- : iterator.iterator.return;
663
+ : get(iterator.iterator, "return");
667
664
  if (close === undefined || close === null)
668
665
  return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
669
666
  const self = this;
@@ -679,7 +676,7 @@ class Frame {
679
676
  yield* Effect.yieldNow;
680
677
  return yield* Effect.failCause(called.cause);
681
678
  }
682
- const captured = yield* Effect.exit(Effect.sync(() => self.requireIteratorObject(called.value, "Iterator return() result", node).value));
679
+ const captured = yield* Effect.exit(Effect.sync(() => get(self.requireIteratorObject(called.value, "Iterator return() result", node), "value")));
683
680
  if (!Exit.isSuccess(captured)) {
684
681
  if (awaiting)
685
682
  yield* Effect.yieldNow;
@@ -690,7 +687,7 @@ class Frame {
690
687
  });
691
688
  }
692
689
  requireIteratorObject(value, context, node) {
693
- if (isRecord(value) && !isRuntimeReference(value))
690
+ if (value instanceof ProgramObject)
694
691
  return value;
695
692
  throw new InterpreterRuntimeError(`${context} must be an object.`, node).as("TypeError");
696
693
  }
@@ -710,7 +707,7 @@ class Frame {
710
707
  return [...this.runtime.toolKeys(value.path)];
711
708
  if (value === null || value === undefined)
712
709
  return [];
713
- return Object.keys(enumerableSource("for...in", value, node));
710
+ return ownKeys(enumerableSource("for...in", value, node)).filter((key) => typeof key === "string");
714
711
  }
715
712
  evaluateForInStatement(node, labels) {
716
713
  const left = node.left;
@@ -856,18 +853,14 @@ class Frame {
856
853
  return;
857
854
  }
858
855
  if (pattern.type === "ObjectPattern") {
859
- if (value === null || typeof value !== "object" || isRuntimeReference(value)) {
856
+ if (!(value instanceof ProgramObject)) {
860
857
  throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
861
858
  }
862
859
  const consumed = new Set();
863
860
  for (const property of pattern.properties) {
864
861
  if (property.type === "RestElement") {
865
- const rest = Object.create(null);
866
- for (const [key, item] of Object.entries(value)) {
867
- if (!consumed.has(key))
868
- rest[key] = item;
869
- }
870
- copyIteratorSymbols(value, rest, consumed);
862
+ const rest = new ProgramObject();
863
+ assign(rest, value, consumed);
871
864
  yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
872
865
  continue;
873
866
  }
@@ -900,25 +893,20 @@ class Frame {
900
893
  return;
901
894
  }
902
895
  if (pattern.type === "ObjectPattern") {
903
- if (value === null || typeof value !== "object" || isRuntimeReference(value)) {
896
+ if (!(value instanceof ProgramObject)) {
904
897
  throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
905
898
  }
906
- const source = value;
907
899
  const consumed = new Set();
908
900
  for (const property of pattern.properties) {
909
901
  if (property.type === "RestElement") {
910
- const rest = Object.create(null);
911
- for (const [key, item] of Object.entries(source)) {
912
- if (!consumed.has(key))
913
- rest[key] = item;
914
- }
915
- copyIteratorSymbols(source, rest, consumed);
902
+ const rest = new ProgramObject();
903
+ assign(rest, value, consumed);
916
904
  yield* self.assignPattern(property.argument, rest, property);
917
905
  continue;
918
906
  }
919
907
  const key = yield* self.destructuringPropertyKey(property);
920
908
  consumed.add(typeof key === "symbol" ? key : String(key));
921
- yield* self.assignPattern(property.value, self.destructuringPropertyValue(source, key), property);
909
+ yield* self.assignPattern(property.value, self.destructuringPropertyValue(value, key), property);
922
910
  }
923
911
  return;
924
912
  }
@@ -940,7 +928,7 @@ class Frame {
940
928
  if (done) {
941
929
  if (element === null)
942
930
  continue;
943
- yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? [] : undefined, element);
931
+ yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray() : undefined, element);
944
932
  if (element.type === "RestElement")
945
933
  return;
946
934
  continue;
@@ -959,7 +947,7 @@ class Frame {
959
947
  if (!done)
960
948
  rest.push(next.value);
961
949
  }
962
- yield* consume(element.argument, rest, element);
950
+ yield* consume(element.argument, new ProgramArray(rest), element);
963
951
  return;
964
952
  }
965
953
  const consumed = consume(element, step.done ? undefined : step.value, pattern);
@@ -984,14 +972,10 @@ class Frame {
984
972
  throw unsupportedSyntax(keyNode.type, keyNode);
985
973
  }
986
974
  destructuringPropertyValue(source, key) {
987
- if (!Array.isArray(source))
988
- return Reflect.get(source, key);
989
- if (key === "length")
990
- return source.length;
991
- if (typeof key === "number")
992
- return source[key];
993
- if (Object.hasOwn(source, key))
994
- return Reflect.get(source, key);
975
+ if (!(source instanceof ProgramArray))
976
+ return get(source, key);
977
+ if (has(source, key))
978
+ return get(source, key);
995
979
  if (typeof key === "string" && arrayMethods.has(key))
996
980
  return new IntrinsicReference(source, key);
997
981
  return undefined;
@@ -1148,11 +1132,10 @@ class Frame {
1148
1132
  case ">>>":
1149
1133
  return l >>> r;
1150
1134
  case "in":
1151
- if (rhs === null || typeof rhs !== "object") {
1135
+ if (!(rhs instanceof ProgramObject)) {
1152
1136
  throw new InterpreterRuntimeError("The 'in' operator requires a data object on the right-hand side.", node);
1153
1137
  }
1154
- // Never expose properties inherited from host prototypes.
1155
- return Object.hasOwn(rhs, coerceOperand(lhs));
1138
+ return has(rhs, coerceOperand(lhs));
1156
1139
  default:
1157
1140
  throw new InterpreterRuntimeError(`Unsupported binary operator '${operator}'.`, node);
1158
1141
  }
@@ -1387,7 +1370,7 @@ class Frame {
1387
1370
  }
1388
1371
  for (const [index, parameter] of fn.parameters.entries()) {
1389
1372
  if (parameter.type === "RestElement") {
1390
- yield* invocation.declarePattern(parameter.argument, args.slice(index), true, parameter, true);
1373
+ yield* invocation.declarePattern(parameter.argument, new ProgramArray(args.slice(index)), true, parameter, true);
1391
1374
  break;
1392
1375
  }
1393
1376
  yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
@@ -1429,13 +1412,13 @@ class Frame {
1429
1412
  if (state.completed) {
1430
1413
  if (kind === "throw")
1431
1414
  return Effect.fail(new ProgramThrow(value));
1432
- return Effect.succeed({ value: kind === "return" ? value : undefined, done: true });
1415
+ return Effect.succeed(record({ value: kind === "return" ? value : undefined, done: true }));
1433
1416
  }
1434
1417
  if (!state.started && kind !== "next") {
1435
1418
  state.completed = true;
1436
1419
  if (kind === "throw")
1437
1420
  return Effect.fail(new ProgramThrow(value));
1438
- return Effect.succeed({ value, done: true });
1421
+ return Effect.succeed(record({ value, done: true }));
1439
1422
  }
1440
1423
  state.pending.push(request);
1441
1424
  if (state.available) {
@@ -1455,7 +1438,7 @@ class Frame {
1455
1438
  const active = state.active;
1456
1439
  state.active = undefined;
1457
1440
  if (active) {
1458
- Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed({ value: exit.value, done: true }) : exit);
1441
+ Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(record({ value: exit.value, done: true })) : exit);
1459
1442
  }
1460
1443
  yield* invocation.completeGeneratorRequests(state, asynchronous);
1461
1444
  state.completed = true;
@@ -1479,10 +1462,10 @@ class Frame {
1479
1462
  }
1480
1463
  if (asynchronous && pending.kind === "return") {
1481
1464
  const resolved = yield* Effect.exit(self.awaitValue(pending.value));
1482
- Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed({ value: resolved.value, done: true }) : resolved);
1465
+ Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(record({ value: resolved.value, done: true })) : resolved);
1483
1466
  continue;
1484
1467
  }
1485
- Deferred.doneUnsafe(pending.response, Exit.succeed({ value: pending.kind === "return" ? pending.value : undefined, done: true }));
1468
+ Deferred.doneUnsafe(pending.response, Exit.succeed(record({ value: pending.kind === "return" ? pending.value : undefined, done: true })));
1486
1469
  }
1487
1470
  });
1488
1471
  }
@@ -1523,7 +1506,7 @@ class Frame {
1523
1506
  const state = this.generatorState;
1524
1507
  if (!state?.active)
1525
1508
  throw new InterpreterRuntimeError("Generator has no active request.", node);
1526
- Deferred.doneUnsafe(state.active.response, Exit.succeed({ value, done: false }));
1509
+ Deferred.doneUnsafe(state.active.response, Exit.succeed(record({ value, done: false })));
1527
1510
  state.active = undefined;
1528
1511
  return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
1529
1512
  state.active = request;
@@ -1539,7 +1522,7 @@ class Frame {
1539
1522
  delegateYield(value, node) {
1540
1523
  const self = this;
1541
1524
  return Effect.gen(function* () {
1542
- if (Array.isArray(value) ||
1525
+ if (value instanceof ProgramArray ||
1543
1526
  typeof value === "string" ||
1544
1527
  value instanceof Values.Map ||
1545
1528
  value instanceof Values.Set ||
@@ -1576,7 +1559,7 @@ class Frame {
1576
1559
  ? iterator.next
1577
1560
  : iterator.iterator instanceof CodeModeGenerator
1578
1561
  ? new GeneratorMethodReference(iterator.iterator, kind)
1579
- : iterator.iterator[kind];
1562
+ : get(iterator.iterator, kind);
1580
1563
  if (method === undefined || method === null) {
1581
1564
  if (kind === "return")
1582
1565
  return yield* Effect.fail(new GeneratorReturn(input));
@@ -1585,10 +1568,10 @@ class Frame {
1585
1568
  }
1586
1569
  const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
1587
1570
  const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
1588
- const done = Boolean(result.done);
1571
+ const done = Boolean(get(result, "done"));
1589
1572
  const resultValue = self.generatorAsync && !iterator.asynchronous
1590
- ? yield* self.awaitAsyncFromSyncValue(iterator, result.value, node, kind !== "return" && !done)
1591
- : result.value;
1573
+ ? yield* self.awaitAsyncFromSyncValue(iterator, get(result, "value"), node, kind !== "return" && !done)
1574
+ : get(result, "value");
1592
1575
  if (done) {
1593
1576
  if (kind === "return")
1594
1577
  return yield* Effect.fail(new GeneratorReturn(resultValue));
@@ -1610,7 +1593,7 @@ class Frame {
1610
1593
  });
1611
1594
  }
1612
1595
  evaluateObjectExpression(node) {
1613
- const objectValue = Object.create(null);
1596
+ const objectValue = new ProgramObject();
1614
1597
  const self = this;
1615
1598
  return Effect.gen(function* () {
1616
1599
  for (const property of node.properties) {
@@ -1618,11 +1601,7 @@ class Frame {
1618
1601
  const spread = yield* self.evaluateExpression(property.argument);
1619
1602
  if (spread === null || spread === undefined)
1620
1603
  continue;
1621
- const from = enumerableSource("Object spread", spread, property);
1622
- for (const [key, value] of Object.entries(from))
1623
- objectValue[key] = value;
1624
- if (typeof from === "object")
1625
- copyIteratorSymbols(from, objectValue);
1604
+ assign(objectValue, enumerableSource("Object spread", spread, property));
1626
1605
  continue;
1627
1606
  }
1628
1607
  if (property.kind !== "init") {
@@ -1642,7 +1621,7 @@ class Frame {
1642
1621
  else {
1643
1622
  throw new InterpreterRuntimeError("Unsupported object property key shape.", keyNode);
1644
1623
  }
1645
- Reflect.set(objectValue, key, yield* self.evaluateExpression(property.value));
1624
+ set(objectValue, key, yield* self.evaluateExpression(property.value));
1646
1625
  }
1647
1626
  return objectValue;
1648
1627
  });
@@ -1673,7 +1652,7 @@ class Frame {
1673
1652
  values.push(yield* self.evaluateExpression(element));
1674
1653
  }
1675
1654
  }
1676
- return values;
1655
+ return new ProgramArray(values);
1677
1656
  });
1678
1657
  }
1679
1658
  evaluateTemplateLiteral(node) {
@@ -1736,7 +1715,9 @@ class Frame {
1736
1715
  return new ComputedValue(objectValue.member(key, propertyNode));
1737
1716
  }
1738
1717
  // Values have no prototype chain, so `.constructor` resolves to the owning built-in directly.
1739
- if (operation === "read" && key === "constructor" && !hasOwn(objectValue, key)) {
1718
+ if (operation === "read" &&
1719
+ key === "constructor" &&
1720
+ !(objectValue instanceof ProgramObject && has(objectValue, key))) {
1740
1721
  const name = constructorName(objectValue);
1741
1722
  if (name !== undefined)
1742
1723
  return new ComputedValue(self.runtime.builtins.get(name));
@@ -1823,25 +1804,14 @@ class Frame {
1823
1804
  if (isRuntimeReference(objectValue)) {
1824
1805
  throw new InterpreterRuntimeError(`Cannot read properties of ${describeValue(objectValue)}; only data values expose properties.`, objectNode, "InvalidDataValue");
1825
1806
  }
1826
- if (typeof objectValue !== "object" || objectValue === null) {
1807
+ if (!(objectValue instanceof ProgramObject)) {
1827
1808
  throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
1828
1809
  }
1829
- if (Array.isArray(objectValue)) {
1830
- if (operation === "delete")
1831
- return { target: objectValue, key };
1832
- const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
1833
- if (key !== "length" && !(typeof key === "string" && arrayMethods.has(key)) && index === undefined) {
1834
- if (typeof key === "string" && Object.hasOwn(objectValue, key)) {
1835
- return new ComputedValue(objectValue[key]);
1836
- }
1837
- return new ComputedValue(undefined);
1838
- }
1839
- return { target: objectValue, key: index ?? key };
1840
- }
1841
1810
  return { target: objectValue, key };
1842
1811
  });
1843
1812
  }
1844
1813
  readMember(node) {
1814
+ const self = this;
1845
1815
  return Effect.map(this.getMemberReference(node), (reference) => {
1846
1816
  if (reference === OptionalShortCircuit)
1847
1817
  return OptionalShortCircuit;
@@ -1849,19 +1819,15 @@ class Frame {
1849
1819
  return reference.value;
1850
1820
  if (reference === undefined || isOpaqueMemberReference(reference))
1851
1821
  return reference;
1852
- if (Array.isArray(reference.target)) {
1853
- if (reference.key === "length")
1854
- return reference.target.length;
1855
- if (typeof reference.key === "string")
1856
- return new IntrinsicReference(reference.target, reference.key);
1857
- return Reflect.get(reference.target, reference.key);
1858
- }
1859
- if (reference.target instanceof Values.RegExp)
1860
- return reference.target.lastIndex;
1861
- if (reference.target instanceof Values.URL) {
1862
- return Reflect.get(reference.target.url, reference.key);
1863
- }
1864
- return Reflect.get(reference.target, reference.key);
1822
+ const value = self.readReferenceValue(reference, reference.key);
1823
+ if (value === undefined &&
1824
+ reference.target instanceof ProgramArray &&
1825
+ typeof reference.key === "string" &&
1826
+ arrayMethods.has(reference.key) &&
1827
+ !has(reference.target, reference.key)) {
1828
+ return new IntrinsicReference(reference.target, reference.key);
1829
+ }
1830
+ return value;
1865
1831
  });
1866
1832
  }
1867
1833
  writeMember(node, value) {
@@ -1884,7 +1850,7 @@ class Frame {
1884
1850
  if (reference.target instanceof Values.RegExp) {
1885
1851
  return Reflect.deleteProperty(reference.target.regex, reference.key);
1886
1852
  }
1887
- return Reflect.deleteProperty(reference.target, reference.key);
1853
+ return remove(reference.target, reference.key);
1888
1854
  });
1889
1855
  }
1890
1856
  // Resolve side-effecting object and key expressions exactly once.
@@ -1898,13 +1864,6 @@ class Frame {
1898
1864
  isOpaqueMemberReference(reference)) {
1899
1865
  throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
1900
1866
  }
1901
- if (Array.isArray(reference.target)) {
1902
- if (reference.key === "length")
1903
- throw new InterpreterRuntimeError("Array length cannot be assigned.", node);
1904
- if (typeof reference.key === "string" && arrayMethods.has(reference.key)) {
1905
- throw new InterpreterRuntimeError("Array methods cannot be assigned.", node);
1906
- }
1907
- }
1908
1867
  const key = reference.key;
1909
1868
  const { write, next, result } = yield* compute(self.readReferenceValue(reference, key));
1910
1869
  if (write)
@@ -1918,18 +1877,9 @@ class Frame {
1918
1877
  }
1919
1878
  if (reference.target instanceof Values.RegExp)
1920
1879
  return reference.target.lastIndex;
1921
- return Reflect.get(reference.target, key);
1880
+ return get(reference.target, key);
1922
1881
  }
1923
1882
  assignToReference(reference, key, next, node) {
1924
- if (Array.isArray(reference.target)) {
1925
- const target = reference.target;
1926
- if (typeof key !== "number" || parseArrayIndex(key) === undefined) {
1927
- throw new InterpreterRuntimeError("Array assignment index must be a valid array index.", node, "InvalidDataValue");
1928
- }
1929
- rejectCircularInsertion(target, next, "Array assignment result", node);
1930
- target[key] = next;
1931
- return;
1932
- }
1933
1883
  if (reference.target instanceof Values.URL) {
1934
1884
  const property = key;
1935
1885
  if (!urlWritableProperties.has(property)) {
@@ -1951,8 +1901,9 @@ class Frame {
1951
1901
  return;
1952
1902
  }
1953
1903
  const target = reference.target;
1954
- rejectCircularInsertion(target, next, "Object assignment result", node);
1955
- Reflect.set(target, key, next);
1904
+ rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
1905
+ if (!set(target, key, next))
1906
+ throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
1956
1907
  }
1957
1908
  toPropertyKey(value, node) {
1958
1909
  if (typeof value === "string" || typeof value === "number") {