@swf2es/runtime 0.1.17 → 0.1.19

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.
@@ -2,6 +2,7 @@
2
2
  // calling or constructing Object, Namespace, QName or Function does.
3
3
 
4
4
  import type { AsObject, Value } from "../descriptors.js";
5
+ import { forgetStep } from "../enumeration.js";
5
6
  import type { ClassHook } from "../hooks.js";
6
7
  import { formatClassName, Namespace, prefixOf, publicQname } from "../names.js";
7
8
  import { NOT_FOUND, type Runtime } from "../runtime.js";
@@ -51,7 +52,11 @@ export const objectNatives: Natives = {
51
52
  o.$d.allHidden = false;
52
53
  }
53
54
  } else {
54
- o.$dontEnum ??= new Set();
55
+ if (o.$dontEnum === undefined) {
56
+ o.$dontEnum = new Set();
57
+ forgetStep(o);
58
+ }
59
+
55
60
  o.$dontEnum.add(name);
56
61
  }
57
62
  },
@@ -76,7 +76,7 @@ for (const [kind, , , elementsOf, store] of VECTORS) {
76
76
  a.length = length;
77
77
  } else if (length === 0) {
78
78
  // A new array: V8 empties one by a call into its runtime.
79
- this.$a = elementsOf(0);
79
+ rt.setElements(this, elementsOf(0));
80
80
  } else if (length < a.length) {
81
81
  a.length = length;
82
82
  } else if (length > a.length) {
@@ -39,13 +39,17 @@ import {
39
39
  continues,
40
40
  dictionaryAt,
41
41
  type Enumeration,
42
+ elementName,
42
43
  elementsAt,
43
44
  enumerated,
45
+ forgetStep,
44
46
  INT_ATOM_LIMIT,
45
47
  nextIndex,
46
48
  ownNames,
47
49
  pairIndex,
48
50
  pairOf,
51
+ sparseElement,
52
+ traitsAt,
49
53
  walkless,
50
54
  } from "./enumeration.js";
51
55
  import { AsError, describe, detailOf, errorMessage, stackOf, UnsupportedError } from "./errors.js";
@@ -1115,7 +1119,21 @@ export class Runtime {
1115
1119
  this.arrayConversion.noteArrayClass(cls);
1116
1120
  }
1117
1121
 
1122
+ /**
1123
+ * A class's prototype, whose methods compiled code calls on a primitive:
1124
+ * at every such call, so a String's, a Number's and a Boolean's are read
1125
+ * from their traits, kept once known, without the lookup by name.
1126
+ */
1118
1127
  prototypeOf(ref: TypeRef): AsObject {
1128
+ switch (ref) {
1129
+ case "String":
1130
+ return (this.stringTraits ?? this.builtinTraits("String")).proto;
1131
+ case "Number":
1132
+ return (this.numberTraits ?? this.builtinTraits("Number")).proto;
1133
+ case "Boolean":
1134
+ return (this.booleanTraits ?? this.builtinTraits("Boolean")).proto;
1135
+ }
1136
+
1119
1137
  return this.classOf(ref).$it.proto;
1120
1138
  }
1121
1139
 
@@ -2505,9 +2523,18 @@ export class Runtime {
2505
2523
  return this.array(values);
2506
2524
  }
2507
2525
 
2526
+ /**
2527
+ * Give `o`, which has elements, the storage `elements` in place of its
2528
+ * own, so that a for-in under way over it goes on over them.
2529
+ */
2530
+ setElements(o: AsObject, elements: Value[]): void {
2531
+ o.$a = elements;
2532
+ forgetStep(o);
2533
+ }
2534
+
2508
2535
  /** An Array holding `values`. */
2509
2536
  array(values: Value[]): AsObject {
2510
- const o = this.builtinTraits("Array").instance();
2537
+ const o = (this.arrayTraits ?? this.builtinTraits("Array")).instance();
2511
2538
  o.$a = values;
2512
2539
  return o;
2513
2540
  }
@@ -3335,7 +3362,7 @@ export class Runtime {
3335
3362
  }
3336
3363
 
3337
3364
  // As avmplus' ArrayObject and TypedVectorObject: the elements, then the other names.
3338
- const length = elementsAt(o, index);
3365
+ const length = elementsAt(o, index)?.length ?? 0;
3339
3366
  if (index > 0 && index <= length) {
3340
3367
  const element = index - 1;
3341
3368
  return element < INT_ATOM_LIMIT ? element : String(element);
@@ -3352,7 +3379,7 @@ export class Runtime {
3352
3379
  }
3353
3380
 
3354
3381
  nextValue(o: Value, index: number): Value {
3355
- const traits: Traits | undefined = o?.$traits;
3382
+ const traits: Traits | undefined = traitsAt(o, index);
3356
3383
  if (!continues(o, index)) {
3357
3384
  const properties = traits?.properties;
3358
3385
  if (properties) {
@@ -3372,7 +3399,8 @@ export class Runtime {
3372
3399
  }
3373
3400
  }
3374
3401
 
3375
- const length = elementsAt(o, index);
3402
+ const a = elementsAt(o, index);
3403
+ const length = a?.length ?? 0;
3376
3404
  if (index > 0 && index <= length) {
3377
3405
  const element = index - 1;
3378
3406
  if (traits?.getIndex) {
@@ -3381,8 +3409,8 @@ export class Runtime {
3381
3409
 
3382
3410
  if (traits === this.arrayTraits) {
3383
3411
  // A hole reads undefined too: only then is `in` asked.
3384
- const value = o.$a[element];
3385
- if (value !== undefined || element in o.$a) {
3412
+ const value = (a as Value[])[element];
3413
+ if (value !== undefined || element in (a as Value[])) {
3386
3414
  return value;
3387
3415
  }
3388
3416
  }
@@ -3396,12 +3424,22 @@ export class Runtime {
3396
3424
  }
3397
3425
 
3398
3426
  // Else a Dictionary's slot holds a dynamic property's name.
3399
- const name =
3400
- keys !== null
3401
- ? (keys.nameAt(index - length) as string)
3402
- : index <= length
3403
- ? String(index - 1)
3404
- : enumerated(o, index - length, index);
3427
+ let name: string;
3428
+ if (keys !== null) {
3429
+ name = keys.nameAt(index - length) as string;
3430
+ } else if (index <= length) {
3431
+ // A step by a sparse Array's indices reads its element here, off the path of every other.
3432
+ if (index < 0) {
3433
+ const value = sparseElement(o, index, traits === this.arrayTraits, NOT_FOUND);
3434
+ if (value !== NOT_FOUND) {
3435
+ return value;
3436
+ }
3437
+ }
3438
+
3439
+ name = elementName(index);
3440
+ } else {
3441
+ name = enumerated(o, index - length, index) as string;
3442
+ }
3405
3443
 
3406
3444
  // A dynamic property's value, as avmplus' nextValue reads its slot's:
3407
3445
  // no binding has its name, which setting it would have gone to.