@swf2es/runtime 0.1.15 → 0.1.17
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.
- package/dist/avm2/amf.d.ts +1 -1
- package/dist/avm2/amf.d.ts.map +1 -1
- package/dist/avm2/amf.js +4 -3
- package/dist/avm2/amf.js.map +1 -1
- package/dist/avm2/as3-types.d.ts +25 -0
- package/dist/avm2/as3-types.d.ts.map +1 -0
- package/dist/avm2/as3-types.js +9 -0
- package/dist/avm2/as3-types.js.map +1 -0
- package/dist/avm2/builtin-types.generated.d.ts +553 -0
- package/dist/avm2/builtin-types.generated.d.ts.map +1 -0
- package/dist/avm2/builtin-types.generated.js +11 -0
- package/dist/avm2/builtin-types.generated.js.map +1 -0
- package/dist/avm2/cache-fill.d.ts +4 -1
- package/dist/avm2/cache-fill.d.ts.map +1 -1
- package/dist/avm2/cache-fill.js +5 -6
- package/dist/avm2/cache-fill.js.map +1 -1
- package/dist/avm2/classes.d.ts.map +1 -1
- package/dist/avm2/classes.js +10 -3
- package/dist/avm2/classes.js.map +1 -1
- package/dist/avm2/descriptors.d.ts +6 -1
- package/dist/avm2/descriptors.d.ts.map +1 -1
- package/dist/avm2/descriptors.js.map +1 -1
- package/dist/avm2/errors.d.ts +14 -0
- package/dist/avm2/errors.d.ts.map +1 -1
- package/dist/avm2/errors.js +20 -1
- package/dist/avm2/errors.js.map +1 -1
- package/dist/avm2/index.d.ts +4 -0
- package/dist/avm2/index.d.ts.map +1 -1
- package/dist/avm2/index.js +3 -0
- package/dist/avm2/index.js.map +1 -1
- package/dist/avm2/names.d.ts +11 -0
- package/dist/avm2/names.d.ts.map +1 -1
- package/dist/avm2/names.js +12 -0
- package/dist/avm2/names.js.map +1 -1
- package/dist/avm2/natives/array.js +1 -1
- package/dist/avm2/natives/array.js.map +1 -1
- package/dist/avm2/natives/bytearray.d.ts.map +1 -1
- package/dist/avm2/natives/bytearray.js +6 -11
- package/dist/avm2/natives/bytearray.js.map +1 -1
- package/dist/avm2/natives/describe.js +6 -1
- package/dist/avm2/natives/describe.js.map +1 -1
- package/dist/avm2/natives/object.d.ts.map +1 -1
- package/dist/avm2/natives/object.js +5 -2
- package/dist/avm2/natives/object.js.map +1 -1
- package/dist/avm2/natives/proxy.d.ts.map +1 -1
- package/dist/avm2/natives/proxy.js +9 -4
- package/dist/avm2/natives/proxy.js.map +1 -1
- package/dist/avm2/natives/vector.js +1 -1
- package/dist/avm2/natives/vector.js.map +1 -1
- package/dist/avm2/options.d.ts +5 -0
- package/dist/avm2/options.d.ts.map +1 -1
- package/dist/avm2/options.js.map +1 -1
- package/dist/avm2/property-cache.d.ts +17 -13
- package/dist/avm2/property-cache.d.ts.map +1 -1
- package/dist/avm2/property-cache.js +50 -10
- package/dist/avm2/property-cache.js.map +1 -1
- package/dist/avm2/runtime.d.ts +101 -1
- package/dist/avm2/runtime.d.ts.map +1 -1
- package/dist/avm2/runtime.js +351 -45
- package/dist/avm2/runtime.js.map +1 -1
- package/dist/avm2/traits.d.ts +13 -0
- package/dist/avm2/traits.d.ts.map +1 -1
- package/dist/avm2/traits.js +23 -0
- package/dist/avm2/traits.js.map +1 -1
- package/package.json +2 -2
- package/src/avm2/amf.ts +4 -3
- package/src/avm2/as3-types.ts +41 -0
- package/src/avm2/builtin-types.generated.ts +619 -0
- package/src/avm2/cache-fill.ts +5 -7
- package/src/avm2/classes.ts +10 -3
- package/src/avm2/descriptors.ts +6 -2
- package/src/avm2/errors.ts +21 -1
- package/src/avm2/index.ts +6 -0
- package/src/avm2/names.ts +13 -0
- package/src/avm2/natives/array.ts +1 -1
- package/src/avm2/natives/bytearray.ts +6 -14
- package/src/avm2/natives/describe.ts +8 -1
- package/src/avm2/natives/object.ts +5 -2
- package/src/avm2/natives/proxy.ts +20 -4
- package/src/avm2/natives/vector.ts +1 -1
- package/src/avm2/options.ts +5 -0
- package/src/avm2/property-cache.ts +57 -11
- package/src/avm2/runtime.ts +407 -53
- package/src/avm2/traits.ts +27 -1
package/src/avm2/runtime.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { API_VERSION, checkApiVersion } from "@swf2es/format";
|
|
15
15
|
import { AmfClasses } from "./amf-classes.js";
|
|
16
16
|
import { ArrayConversion } from "./array-conversion.js";
|
|
17
|
+
import type { MethodName, PropertyName, Ref, WritableName } from "./as3-types.js";
|
|
17
18
|
import { fillCache } from "./cache-fill.js";
|
|
18
19
|
import { newClass, specializeVector, withId } from "./classes.js";
|
|
19
20
|
import { classNamed, classNamedByCode, definingAbc, definitionNamed } from "./definitions.js";
|
|
@@ -47,7 +48,7 @@ import {
|
|
|
47
48
|
pairOf,
|
|
48
49
|
walkless,
|
|
49
50
|
} from "./enumeration.js";
|
|
50
|
-
import { AsError, describe, errorMessage, stackOf } from "./errors.js";
|
|
51
|
+
import { AsError, describe, detailOf, errorMessage, stackOf, UnsupportedError } from "./errors.js";
|
|
51
52
|
import { FloatValue, floatValue } from "./float.js";
|
|
52
53
|
import { type ClassHook, hookedBinding, type NativesProvider, type PropertyHook } from "./hooks.js";
|
|
53
54
|
import {
|
|
@@ -70,6 +71,8 @@ import {
|
|
|
70
71
|
CONSTANT_RTQnameA,
|
|
71
72
|
CONSTANT_RTQnameL,
|
|
72
73
|
CONSTANT_RTQnameLA,
|
|
74
|
+
MADE_Number,
|
|
75
|
+
MADE_Value,
|
|
73
76
|
Multiname,
|
|
74
77
|
Namespace,
|
|
75
78
|
NS_Private,
|
|
@@ -113,7 +116,7 @@ import {
|
|
|
113
116
|
IC_Slot,
|
|
114
117
|
invalidate,
|
|
115
118
|
NO_CACHE,
|
|
116
|
-
|
|
119
|
+
ScopeFinds,
|
|
117
120
|
UNFILLED,
|
|
118
121
|
} from "./property-cache.js";
|
|
119
122
|
import {
|
|
@@ -153,7 +156,34 @@ class ScopePack {
|
|
|
153
156
|
) {}
|
|
154
157
|
}
|
|
155
158
|
|
|
159
|
+
/** Whether a chain or a pack, `scopes` with bits `w`, has a with scope, in a pack in it too. */
|
|
160
|
+
function hasWith(scopes: Value[], w: number): boolean {
|
|
161
|
+
for (let i = 0; i < scopes.length; i++) {
|
|
162
|
+
const o = scopes[i];
|
|
163
|
+
if (o instanceof ScopePack ? hasWith(o.scopes, o.w) : (w >> i) & 1) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
|
|
156
171
|
/** The value of `o`'s dynamic property `name`, or NOT_FOUND. */
|
|
172
|
+
/** Whether k is an int atom avmplus can take as a uint: an integer of 0 to 2^32-1, -0 not, as it is a double's. */
|
|
173
|
+
function uintAtom(k: Value): k is number {
|
|
174
|
+
return typeof k === "number" && k >>> 0 === k && (k !== 0 || 1 / k > 0);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Whether v is an object's atom to avmplus: not null, nor a Namespace or float, whose atoms are their own. */
|
|
178
|
+
function isScriptObject(v: Value): boolean {
|
|
179
|
+
return (
|
|
180
|
+
typeof v === "object" && v !== null && !(v instanceof Namespace) && !(v instanceof FloatValue)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The name avmplus' getUintProperty looks a number up by: public, at every version. */
|
|
185
|
+
const ELEMENT_NAME = new Multiname(CONSTANT_MultinameL, [publicNs], [255], null, false);
|
|
186
|
+
|
|
157
187
|
function dynamicValue(o: AsObject, name: string): Value {
|
|
158
188
|
const d: Map<string, Value> | null | undefined = o.$d;
|
|
159
189
|
if (!d) {
|
|
@@ -167,6 +197,7 @@ function dynamicValue(o: AsObject, name: string): Value {
|
|
|
167
197
|
export class Runtime {
|
|
168
198
|
readonly print: (line: string) => void;
|
|
169
199
|
readonly debugger: boolean;
|
|
200
|
+
private readonly onUnsupported: ((message: string) => void) | undefined;
|
|
170
201
|
readonly compileAbc:
|
|
171
202
|
| ((abc: Uint8Array, unit: CompileUnit) => ((rt: Runtime) => Abc) | number)
|
|
172
203
|
| null;
|
|
@@ -229,6 +260,13 @@ export class Runtime {
|
|
|
229
260
|
/** The builtin classes' traits, made before their classes so the bootstrap can refer to them. */
|
|
230
261
|
readonly objectTraits: Traits;
|
|
231
262
|
readonly classTraits: Traits;
|
|
263
|
+
/**
|
|
264
|
+
* What the super operations of a script's methods and of a class's
|
|
265
|
+
* static ones look in, as avmplus' script traits extend Object and a
|
|
266
|
+
* class object's traits Class: their `super` is that class's instance.
|
|
267
|
+
*/
|
|
268
|
+
readonly scriptSuper: AsObject;
|
|
269
|
+
readonly staticSuper: AsObject;
|
|
232
270
|
readonly functionTraits: Traits;
|
|
233
271
|
/**
|
|
234
272
|
* Method closures, by receiver and method, so that o.f === o.f; by the
|
|
@@ -249,7 +287,7 @@ export class Runtime {
|
|
|
249
287
|
/** Special traits: an activation's or a catch scope's, by descriptor. */
|
|
250
288
|
private readonly scopeTraits = new WeakMap<object, Traits>();
|
|
251
289
|
readonly specialized = new Map<AsObject, AsObject>();
|
|
252
|
-
readonly empty: Scope = Object.assign([], { w: 0 });
|
|
290
|
+
readonly empty: Scope = Object.assign([], { w: 0, found: undefined });
|
|
253
291
|
|
|
254
292
|
/**
|
|
255
293
|
* `natives` are the natives by name, or a provider that makes them for
|
|
@@ -264,6 +302,7 @@ export class Runtime {
|
|
|
264
302
|
) {
|
|
265
303
|
this.print = options.print ?? defaultPrint;
|
|
266
304
|
this.debugger = options.debugger ?? false;
|
|
305
|
+
this.onUnsupported = options.onUnsupported;
|
|
267
306
|
this.compileAbc = options.compileAbc ?? null;
|
|
268
307
|
this.files = options.files ?? memoryFiles();
|
|
269
308
|
this.workerHost = options.workers ?? null;
|
|
@@ -283,6 +322,8 @@ export class Runtime {
|
|
|
283
322
|
this.objectTraits.dynamic = true;
|
|
284
323
|
this.objectTraits.testsValues = true;
|
|
285
324
|
this.classTraits = new Traits("Class", this.objectTraits);
|
|
325
|
+
this.scriptSuper = { $it: this.objectTraits };
|
|
326
|
+
this.staticSuper = { $it: this.classTraits };
|
|
286
327
|
this.functionTraits = new Traits("Function", this.objectTraits);
|
|
287
328
|
this.functionTraits.dynamic = true;
|
|
288
329
|
this.natives = typeof natives === "function" ? natives(this) : natives;
|
|
@@ -429,6 +470,7 @@ export class Runtime {
|
|
|
429
470
|
// Its string only once a lookup needs it: a Dictionary does not.
|
|
430
471
|
const keyed = Multiname.keyed(kind, namespaces, versions, part, mn.attribute, this.keyName);
|
|
431
472
|
keyed.domain = mn.domain;
|
|
473
|
+
keyed.made = MADE_Value;
|
|
432
474
|
return keyed;
|
|
433
475
|
} else {
|
|
434
476
|
name = typeof part === "string" ? part : this.toString(part);
|
|
@@ -437,6 +479,42 @@ export class Runtime {
|
|
|
437
479
|
|
|
438
480
|
const named = new Multiname(kind, namespaces, versions, name, mn.attribute);
|
|
439
481
|
named.domain = mn.domain;
|
|
482
|
+
// A number here is one no element access made: a Proxy tells it by its string.
|
|
483
|
+
if (mn.runtimeName && typeof last !== "number") {
|
|
484
|
+
named.made = MADE_Value;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return named;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* The name runtimeName makes of `mn`, a MultinameL, and a string the
|
|
492
|
+
* code itself holds, `obj["name"]`: a module makes it once as it loads
|
|
493
|
+
* and keeps it as it keeps `mn`, so it has a cache as a module's own
|
|
494
|
+
* names have, however many such names the module has and however long
|
|
495
|
+
* the string is.
|
|
496
|
+
*/
|
|
497
|
+
literalName(mn: Multiname, name: string): Multiname {
|
|
498
|
+
const named = new Multiname(mn.kind, mn.namespaces, mn.versions, name, mn.attribute);
|
|
499
|
+
named.domain = mn.domain;
|
|
500
|
+
named.made = MADE_Value;
|
|
501
|
+
named.cache = UNFILLED;
|
|
502
|
+
|
|
503
|
+
return named;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* The name number `i` makes of `mn` in an element's read or write, which
|
|
508
|
+
* avmplus' JIT hands an object as a number (getpropertylate_i and _d), a
|
|
509
|
+
* Proxy as its string: where the name has no public namespace, it is a
|
|
510
|
+
* name as any other.
|
|
511
|
+
*/
|
|
512
|
+
private indexName(mn: Multiname, i: number): Multiname {
|
|
513
|
+
const named = this.runtimeName(mn, i);
|
|
514
|
+
if (mn.kind === CONSTANT_MultinameL && mn.elementName) {
|
|
515
|
+
named.made = MADE_Number;
|
|
516
|
+
}
|
|
517
|
+
|
|
440
518
|
return named;
|
|
441
519
|
}
|
|
442
520
|
|
|
@@ -462,6 +540,7 @@ export class Runtime {
|
|
|
462
540
|
|
|
463
541
|
const named = new Multiname(base.kind, base.namespaces, base.versions, name, base.attribute);
|
|
464
542
|
named.domain = base.domain;
|
|
543
|
+
named.made = MADE_Value;
|
|
465
544
|
if (!cache) {
|
|
466
545
|
cache = { names: new Map(), misses: 0 };
|
|
467
546
|
this.stringNames.set(base, cache);
|
|
@@ -578,6 +657,7 @@ export class Runtime {
|
|
|
578
657
|
const traits = new Traits("global", this.objectTraits);
|
|
579
658
|
traits.dynamic = true;
|
|
580
659
|
traits.isGlobal = true;
|
|
660
|
+
traits.abc = script.abc;
|
|
581
661
|
traits.describe(script.desc.traits);
|
|
582
662
|
const g = traits.instance();
|
|
583
663
|
// As the script's initializer, its methods run in an empty scope chain,
|
|
@@ -585,14 +665,9 @@ export class Runtime {
|
|
|
585
665
|
// indexes the scopes their closures capture: the global object is
|
|
586
666
|
// only what they push.
|
|
587
667
|
for (const [d, factory, id, , params] of script.desc.traits.methods) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
d,
|
|
592
|
-
withId(factory(this.empty, null), id),
|
|
593
|
-
factory,
|
|
594
|
-
params,
|
|
595
|
-
);
|
|
668
|
+
const method = withId(factory(this.empty, this.scriptSuper), id);
|
|
669
|
+
this.keepStatic(factory, method);
|
|
670
|
+
installMethod(this, traits.methodHome(3), d, method, factory, params);
|
|
596
671
|
}
|
|
597
672
|
|
|
598
673
|
// Caches keep the methods.
|
|
@@ -622,7 +697,7 @@ export class Runtime {
|
|
|
622
697
|
if (script.state === 0 || (retry && script.state === 3)) {
|
|
623
698
|
script.state = 1;
|
|
624
699
|
try {
|
|
625
|
-
script.desc.init(this.empty,
|
|
700
|
+
script.desc.init(this.empty, this.scriptSuper).call(g);
|
|
626
701
|
} catch (e) {
|
|
627
702
|
script.state = 3;
|
|
628
703
|
throw e;
|
|
@@ -671,6 +746,7 @@ export class Runtime {
|
|
|
671
746
|
scope(outer: Scope, locals: Value[], withs: number): Scope {
|
|
672
747
|
const chain = outer.concat(locals) as Scope;
|
|
673
748
|
chain.w = outer.w | (withs << outer.length);
|
|
749
|
+
chain.found = undefined;
|
|
674
750
|
return chain;
|
|
675
751
|
}
|
|
676
752
|
|
|
@@ -686,6 +762,7 @@ export class Runtime {
|
|
|
686
762
|
const packed = chain.slice(0, at) as Scope;
|
|
687
763
|
packed.push(new ScopePack(chain.slice(at), chain.w >>> at) as never);
|
|
688
764
|
packed.w = (chain.w & ((1 << at) - 1)) | (1 << at);
|
|
765
|
+
packed.found = undefined;
|
|
689
766
|
return packed;
|
|
690
767
|
}
|
|
691
768
|
|
|
@@ -724,6 +801,47 @@ export class Runtime {
|
|
|
724
801
|
}
|
|
725
802
|
}
|
|
726
803
|
|
|
804
|
+
const found = this.outerScopeOf(outer, mn);
|
|
805
|
+
if (found !== null) {
|
|
806
|
+
return found;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return this.global(mn, outer.length ? outer[0] : locals[0], strict);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* The innermost object of a captured chain that has `mn`, or null: kept
|
|
814
|
+
* on a chain without a with scope (ScopeFinds), as a function whose
|
|
815
|
+
* chain the compiler could not type, such as one made where chains of
|
|
816
|
+
* different lengths meet, looks its names up each time it runs.
|
|
817
|
+
*/
|
|
818
|
+
private outerScopeOf(outer: Scope, mn: Multiname): AsObject | null {
|
|
819
|
+
let finds = outer.found;
|
|
820
|
+
if (finds === undefined) {
|
|
821
|
+
finds = hasWith(outer, outer.w) ? null : new ScopeFinds();
|
|
822
|
+
outer.found = finds;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// A name made at run time is a new one each time: keeping it would only grow the map.
|
|
826
|
+
if (finds === null || mn.cache === NO_CACHE) {
|
|
827
|
+
return this.searchOuter(outer, mn);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if (finds.epoch !== epoch()) {
|
|
831
|
+
finds.clear();
|
|
832
|
+
finds.epoch = epoch();
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
let o = finds.get(mn);
|
|
836
|
+
if (o === undefined) {
|
|
837
|
+
o = this.searchOuter(outer, mn);
|
|
838
|
+
finds.set(mn, o);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return o;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
private searchOuter(outer: Scope, mn: Multiname): AsObject | null {
|
|
727
845
|
for (let i = outer.length - 1; i >= 0; i--) {
|
|
728
846
|
const o = outer[i];
|
|
729
847
|
if (o instanceof ScopePack) {
|
|
@@ -736,7 +854,7 @@ export class Runtime {
|
|
|
736
854
|
}
|
|
737
855
|
}
|
|
738
856
|
|
|
739
|
-
return
|
|
857
|
+
return null;
|
|
740
858
|
}
|
|
741
859
|
|
|
742
860
|
findPropertyStrict(mn: Multiname, outer: Scope, locals: Value[], withs: number): AsObject {
|
|
@@ -887,16 +1005,24 @@ export class Runtime {
|
|
|
887
1005
|
traitsOf(v: Value): Traits {
|
|
888
1006
|
switch (typeof v) {
|
|
889
1007
|
case "object":
|
|
890
|
-
case "function":
|
|
1008
|
+
case "function": {
|
|
891
1009
|
if (v === null) {
|
|
892
1010
|
throw this.error("TypeError", 1009);
|
|
893
1011
|
}
|
|
894
1012
|
|
|
1013
|
+
// An object's own first: instanceof walks the whole prototype
|
|
1014
|
+
// chain of an object, and a class's is as deep as its bases.
|
|
1015
|
+
const traits = v.$traits;
|
|
1016
|
+
if (traits !== undefined) {
|
|
1017
|
+
return traits;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
895
1020
|
return v instanceof FloatValue
|
|
896
1021
|
? this.builtinTraits("float")
|
|
897
1022
|
: v instanceof Namespace
|
|
898
1023
|
? this.builtinTraits("Namespace")
|
|
899
|
-
:
|
|
1024
|
+
: traits;
|
|
1025
|
+
}
|
|
900
1026
|
// As avmplus' toVTable: every number is a Number at run time, int or
|
|
901
1027
|
// not; int's and uint's traits only bind early, from static types.
|
|
902
1028
|
case "number":
|
|
@@ -918,12 +1044,19 @@ export class Runtime {
|
|
|
918
1044
|
private receiverTraits(v: Value): Traits | undefined {
|
|
919
1045
|
switch (typeof v) {
|
|
920
1046
|
case "object":
|
|
921
|
-
case "function":
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1047
|
+
case "function": {
|
|
1048
|
+
if (v === null) {
|
|
1049
|
+
return undefined;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// A float and a Namespace have none of their own (see traitsOf).
|
|
1053
|
+
const traits: Traits | undefined = v.$traits;
|
|
1054
|
+
if (traits !== undefined) {
|
|
1055
|
+
return traits;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
return v instanceof FloatValue ? this.builtinTraits("float") : undefined;
|
|
1059
|
+
}
|
|
927
1060
|
case "string":
|
|
928
1061
|
return this.stringTraits;
|
|
929
1062
|
case "number":
|
|
@@ -1084,7 +1217,7 @@ export class Runtime {
|
|
|
1084
1217
|
"ReferenceError",
|
|
1085
1218
|
name === null && nsset ? 1081 : 1069,
|
|
1086
1219
|
mn.name ?? "*",
|
|
1087
|
-
traits.
|
|
1220
|
+
traits.errorName,
|
|
1088
1221
|
);
|
|
1089
1222
|
}
|
|
1090
1223
|
|
|
@@ -1126,7 +1259,7 @@ export class Runtime {
|
|
|
1126
1259
|
}
|
|
1127
1260
|
}
|
|
1128
1261
|
|
|
1129
|
-
return this.getProperty(o, this.
|
|
1262
|
+
return this.getProperty(o, this.indexName(mn, i));
|
|
1130
1263
|
}
|
|
1131
1264
|
|
|
1132
1265
|
/** obj[i] = v for a number i, as avmplus' setUintProperty. */
|
|
@@ -1140,13 +1273,128 @@ export class Runtime {
|
|
|
1140
1273
|
return;
|
|
1141
1274
|
}
|
|
1142
1275
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1276
|
+
const a: Value[] | undefined = o.$a;
|
|
1277
|
+
if (a !== undefined) {
|
|
1278
|
+
if (a !== SEALED_ELEMENTS && i !== 0xffffffff) {
|
|
1279
|
+
a[i] = v;
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
} else if (traits?.dynamic && traits.properties === null && !traits.refusesNames) {
|
|
1283
|
+
// As ScriptObject::setUintProperty: an object with no elements of its own keeps the
|
|
1284
|
+
// number among its dynamic properties, with no binding asked for.
|
|
1285
|
+
const d: Map<string, Value> | null | undefined = o.$d;
|
|
1286
|
+
if (d) {
|
|
1287
|
+
d.set(`${i}`, v);
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1146
1290
|
}
|
|
1147
1291
|
}
|
|
1148
1292
|
|
|
1149
|
-
this.setProperty(o, this.
|
|
1293
|
+
this.setProperty(o, this.indexName(mn, i), v);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* obj[k] by a runtime name with no public namespace, or an attribute's,
|
|
1298
|
+
* in a script's or a class's initializer, which avmplus interprets: its
|
|
1299
|
+
* getproperty reads an int key of at least 0 off an object by
|
|
1300
|
+
* getUintProperty, whatever namespaces the name has, where its JIT asks
|
|
1301
|
+
* for a public one (getIndexed). Any other key makes a name.
|
|
1302
|
+
*/
|
|
1303
|
+
getInterpreted(o: Value, mn: Multiname, k: Value): Value {
|
|
1304
|
+
if (uintAtom(k) && isScriptObject(o)) {
|
|
1305
|
+
return this.getIndexed(o, ELEMENT_NAME, k);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return this.getProperty(o, this.runtimeName(mn, k));
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/** obj[k] = v as getInterpreted reads it, as avmplus' interpreter's setproperty. */
|
|
1312
|
+
setInterpreted(o: Value, mn: Multiname, k: Value, v: Value): void {
|
|
1313
|
+
if (uintAtom(k) && isScriptObject(o)) {
|
|
1314
|
+
this.setIndexed(o, ELEMENT_NAME, k, v);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
this.setProperty(o, this.runtimeName(mn, k), v);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
/**
|
|
1322
|
+
* obj[k] for a key whose type the compiler does not know, by a name with
|
|
1323
|
+
* no namespace from the stack, as avmplus' getprop_index and
|
|
1324
|
+
* getpropertyHelper: a number is an index (getIndexed), an object a
|
|
1325
|
+
* Dictionary has as a key is read by itself, and anything else, a QName
|
|
1326
|
+
* and a Dictionary's absent key among them, is looked up by the name it
|
|
1327
|
+
* makes.
|
|
1328
|
+
*/
|
|
1329
|
+
getKeyed(o: Value, mn: Multiname, k: Value): Value {
|
|
1330
|
+
let r: Value;
|
|
1331
|
+
if (typeof k === "number") {
|
|
1332
|
+
r = this.getIndexed(o, mn, k);
|
|
1333
|
+
return r;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
if (typeof k === "object" && k !== null) {
|
|
1337
|
+
const keys: DictionaryKeys | undefined = o?.$keys;
|
|
1338
|
+
if (keys !== undefined) {
|
|
1339
|
+
if (!mn.elementName) {
|
|
1340
|
+
r = this.getProperty(o, this.runtimeName(mn, this.unkeyed(k)));
|
|
1341
|
+
return r;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// What is there was put there by a name with the object as its key, which a QName's is not.
|
|
1345
|
+
const v = keys.get(k);
|
|
1346
|
+
if (v !== undefined) {
|
|
1347
|
+
return v;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
r = this.getProperty(o, this.runtimeName(mn, k));
|
|
1353
|
+
return r;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* An object given as the key of a Dictionary by a name with no public
|
|
1358
|
+
* namespace, as the name is made of it: avmplus' JIT asks a Dictionary
|
|
1359
|
+
* for an object only through getprop_index and setprop_index, which such
|
|
1360
|
+
* a name does not reach, so the object is its string, as on any other
|
|
1361
|
+
* receiver (initMultinameLate); a QName names what it names. Its
|
|
1362
|
+
* interpreter asks the Dictionary by any name, as a name made without
|
|
1363
|
+
* this does: the compiler leaves script and class initializers to that.
|
|
1364
|
+
*/
|
|
1365
|
+
private unkeyed(k: AsObject): Value {
|
|
1366
|
+
return k.$traits !== undefined && k.$local === undefined ? this.toString(k) : k;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/** obj[k] = v for a key whose type the compiler does not know, as avmplus' setprop_index and setpropertyHelper. */
|
|
1370
|
+
setKeyed(o: Value, mn: Multiname, k: Value, v: Value): void {
|
|
1371
|
+
if (typeof k === "number") {
|
|
1372
|
+
this.setIndexed(o, mn, k, v);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
if (typeof k === "object" && k !== null) {
|
|
1377
|
+
const keys: DictionaryKeys | undefined = o?.$keys;
|
|
1378
|
+
if (keys !== undefined) {
|
|
1379
|
+
if (!mn.elementName) {
|
|
1380
|
+
this.setProperty(o, this.runtimeName(mn, this.unkeyed(k)), v);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
if (keys.replace(k, v)) {
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// A new key: an object of traits, which a float and a Namespace are not, and no QName,
|
|
1389
|
+
// which names what it names. Those are added, or not, by the name they make.
|
|
1390
|
+
if (k.$traits !== undefined && k.$local === undefined) {
|
|
1391
|
+
keys.add(k, v);
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
this.setProperty(o, this.runtimeName(mn, k), v);
|
|
1150
1398
|
}
|
|
1151
1399
|
|
|
1152
1400
|
/**
|
|
@@ -1375,21 +1623,17 @@ export class Runtime {
|
|
|
1375
1623
|
return o[slot];
|
|
1376
1624
|
}
|
|
1377
1625
|
|
|
1378
|
-
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.
|
|
1626
|
+
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.errorName);
|
|
1379
1627
|
}
|
|
1380
1628
|
default:
|
|
1381
|
-
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.
|
|
1629
|
+
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.errorName);
|
|
1382
1630
|
}
|
|
1383
1631
|
}
|
|
1384
1632
|
|
|
1385
1633
|
/** fillCache (cache-fill.ts), for a name that caches on traits a cache knows `o` by. */
|
|
1386
1634
|
private fill(o: Value, traits: Traits, b: number, mn: Multiname): void {
|
|
1387
1635
|
const head = mn.cache;
|
|
1388
|
-
if (
|
|
1389
|
-
head === NO_CACHE ||
|
|
1390
|
-
(head.replaced === REPLACEMENTS && head.epoch === epoch()) ||
|
|
1391
|
-
this.receiverTraits(o) !== traits
|
|
1392
|
-
) {
|
|
1636
|
+
if (head === NO_CACHE || this.receiverTraits(o) !== traits) {
|
|
1393
1637
|
return;
|
|
1394
1638
|
}
|
|
1395
1639
|
|
|
@@ -1424,6 +1668,8 @@ export class Runtime {
|
|
|
1424
1668
|
f.$length = (method as CountedMethod).$length ?? method.length;
|
|
1425
1669
|
f.$id = (method as Method & { $id?: number }).$id ?? 0;
|
|
1426
1670
|
f.$closure = true;
|
|
1671
|
+
// Whose method it is, for moduleOf.
|
|
1672
|
+
f.$of = traits;
|
|
1427
1673
|
if (typeof o === "object") {
|
|
1428
1674
|
byMethod.set(method, f);
|
|
1429
1675
|
}
|
|
@@ -1482,7 +1728,7 @@ export class Runtime {
|
|
|
1482
1728
|
switch (b & 7) {
|
|
1483
1729
|
case BIND_Const:
|
|
1484
1730
|
if (!init) {
|
|
1485
|
-
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.
|
|
1731
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.errorName);
|
|
1486
1732
|
}
|
|
1487
1733
|
o[slotKey(id)] = this.coerce(v, traits.slotType(id));
|
|
1488
1734
|
return;
|
|
@@ -1494,9 +1740,9 @@ export class Runtime {
|
|
|
1494
1740
|
(traits.proto[untypedSetKey(id + 1)] ?? traits.proto[methodKey(id + 1)]).call(o, v);
|
|
1495
1741
|
return;
|
|
1496
1742
|
case BIND_Method:
|
|
1497
|
-
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.
|
|
1743
|
+
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.errorName);
|
|
1498
1744
|
default:
|
|
1499
|
-
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.
|
|
1745
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.errorName);
|
|
1500
1746
|
}
|
|
1501
1747
|
}
|
|
1502
1748
|
|
|
@@ -1521,7 +1767,7 @@ export class Runtime {
|
|
|
1521
1767
|
}
|
|
1522
1768
|
}
|
|
1523
1769
|
|
|
1524
|
-
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.
|
|
1770
|
+
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.errorName);
|
|
1525
1771
|
}
|
|
1526
1772
|
|
|
1527
1773
|
initProperty(o: Value, mn: Multiname, v: Value): void {
|
|
@@ -1540,7 +1786,7 @@ export class Runtime {
|
|
|
1540
1786
|
|
|
1541
1787
|
// A primitive's property cannot be deleted, as MethodEnv's delproperty has it.
|
|
1542
1788
|
if (typeof o !== "object" || o instanceof Namespace) {
|
|
1543
|
-
throw this.error("ReferenceError", 1120, mn.name ?? "*", this.traitsOf(o).
|
|
1789
|
+
throw this.error("ReferenceError", 1120, mn.name ?? "*", this.traitsOf(o).errorName);
|
|
1544
1790
|
}
|
|
1545
1791
|
|
|
1546
1792
|
// E4X 11.3.1: delete x[list] is a TypeError, as in delete x.a.(b == 1).
|
|
@@ -1740,8 +1986,7 @@ export class Runtime {
|
|
|
1740
1986
|
if (
|
|
1741
1987
|
typeof o === "object" &&
|
|
1742
1988
|
o !== null &&
|
|
1743
|
-
!(o instanceof Namespace)
|
|
1744
|
-
!(o instanceof FloatValue)
|
|
1989
|
+
(o.$traits !== undefined || !(o instanceof Namespace || o instanceof FloatValue))
|
|
1745
1990
|
) {
|
|
1746
1991
|
return o.$p;
|
|
1747
1992
|
}
|
|
@@ -1758,6 +2003,36 @@ export class Runtime {
|
|
|
1758
2003
|
return qname(publicNs, this.nameString(name));
|
|
1759
2004
|
}
|
|
1760
2005
|
|
|
2006
|
+
// Natives' typed reach into AS3 objects (as3-types.ts): getProperty,
|
|
2007
|
+
// setProperty and callProperty of the public name, the lookup natives
|
|
2008
|
+
// made before, with the name checked against the class's declarations
|
|
2009
|
+
// when compiled.
|
|
2010
|
+
|
|
2011
|
+
/** `o`'s public property `name`: a variable, constant or accessor its class declares. */
|
|
2012
|
+
prop<T, K extends PropertyName<T>>(o: Ref<T>, name: K): T[K] {
|
|
2013
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see getProperty)
|
|
2014
|
+
let r: Value;
|
|
2015
|
+
r = this.getProperty(o, this.publicName(name));
|
|
2016
|
+
return r;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
/** Sets `o`'s public property `name`, which its class declares writable. */
|
|
2020
|
+
setProp<T, K extends WritableName<T>>(o: Ref<T>, name: K, v: T[K]): void {
|
|
2021
|
+
this.setProperty(o, this.publicName(name), v);
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
/** Calls `o`'s public method `name` with `args`. */
|
|
2025
|
+
callProp<T, K extends MethodName<T>>(
|
|
2026
|
+
o: Ref<T>,
|
|
2027
|
+
name: K,
|
|
2028
|
+
...args: T[K] extends (...a: infer A) => unknown ? A : never
|
|
2029
|
+
): T[K] extends (...a: never[]) => infer R ? R : never {
|
|
2030
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see getProperty)
|
|
2031
|
+
let r: Value;
|
|
2032
|
+
r = this.callProperty(o, this.publicName(name), ...args);
|
|
2033
|
+
return r;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
1761
2036
|
/** A property name as a string, as ToString makes one. */
|
|
1762
2037
|
private nameString(name: Value): string {
|
|
1763
2038
|
return typeof name === "string" ? name : this.toString(name);
|
|
@@ -2008,8 +2283,33 @@ export class Runtime {
|
|
|
2008
2283
|
return key;
|
|
2009
2284
|
}
|
|
2010
2285
|
|
|
2011
|
-
|
|
2012
|
-
|
|
2286
|
+
/**
|
|
2287
|
+
* The first method each factory made for a class's or a script's
|
|
2288
|
+
* traits, as avmplus' AbcEnv keeps the first MethodEnv of each method
|
|
2289
|
+
* a vtable makes (VTable::makeMethodEnv): what callstatic calls.
|
|
2290
|
+
*/
|
|
2291
|
+
private readonly staticMethods = new WeakMap<Factory, Method>();
|
|
2292
|
+
|
|
2293
|
+
/** Keep `method`, made by `factory`, for callstatic, unless it made one before. */
|
|
2294
|
+
keepStatic(factory: Factory, method: Method): void {
|
|
2295
|
+
if (!this.staticMethods.has(factory)) {
|
|
2296
|
+
this.staticMethods.set(factory, method);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
/**
|
|
2301
|
+
* callstatic: method `factory` made, called on `o` with its arguments,
|
|
2302
|
+
* which the compiler coerced. avmplus verifies a method when it first
|
|
2303
|
+
* runs and refuses one that calls a method no vtable has made yet
|
|
2304
|
+
* (1107); that is found here only once the call is reached.
|
|
2305
|
+
*/
|
|
2306
|
+
callStatic(factory: Factory, o: Value, ...args: Value[]): Value {
|
|
2307
|
+
const method = this.staticMethods.get(factory);
|
|
2308
|
+
if (method === undefined) {
|
|
2309
|
+
throw this.error("VerifyError", 1107);
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
return method.apply(o, args);
|
|
2013
2313
|
}
|
|
2014
2314
|
|
|
2015
2315
|
// The super operations, as MethodEnv's: by the base class's traits
|
|
@@ -2025,7 +2325,7 @@ export class Runtime {
|
|
|
2025
2325
|
}
|
|
2026
2326
|
|
|
2027
2327
|
if (b === 0) {
|
|
2028
|
-
throw this.error("ReferenceError", 1070, mn.name ?? "*", traits.
|
|
2328
|
+
throw this.error("ReferenceError", 1070, mn.name ?? "*", traits.errorName);
|
|
2029
2329
|
}
|
|
2030
2330
|
|
|
2031
2331
|
r = this.callValue(this.getBound(o, traits, b, mn), o, args, mn);
|
|
@@ -2036,7 +2336,7 @@ export class Runtime {
|
|
|
2036
2336
|
const traits: Traits = sup.$it;
|
|
2037
2337
|
const b = traits.find(mn);
|
|
2038
2338
|
if (b === 0) {
|
|
2039
|
-
throw this.error("ReferenceError", 1069, mn.name ?? "*", traits.
|
|
2339
|
+
throw this.error("ReferenceError", 1069, mn.name ?? "*", traits.errorName);
|
|
2040
2340
|
}
|
|
2041
2341
|
|
|
2042
2342
|
return this.getBound(o, traits, b, mn);
|
|
@@ -2055,11 +2355,11 @@ export class Runtime {
|
|
|
2055
2355
|
o[slotKey(id)] = this.coerce(v, traits.slotType(id));
|
|
2056
2356
|
return;
|
|
2057
2357
|
case BIND_Method:
|
|
2058
|
-
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.
|
|
2358
|
+
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.errorName);
|
|
2059
2359
|
case 0:
|
|
2060
|
-
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.
|
|
2360
|
+
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.errorName);
|
|
2061
2361
|
default:
|
|
2062
|
-
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.
|
|
2362
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.errorName);
|
|
2063
2363
|
}
|
|
2064
2364
|
}
|
|
2065
2365
|
|
|
@@ -2242,6 +2542,21 @@ export class Runtime {
|
|
|
2242
2542
|
return f;
|
|
2243
2543
|
}
|
|
2244
2544
|
|
|
2545
|
+
/**
|
|
2546
|
+
* The module a function's code is from, as avmplus has a method's code
|
|
2547
|
+
* context: a function's by the global object its scope begins with, a
|
|
2548
|
+
* bound method's by its receiver's class; null for a native, a class's
|
|
2549
|
+
* own method, or anything but a function.
|
|
2550
|
+
*/
|
|
2551
|
+
moduleOf(f: Value): object | null {
|
|
2552
|
+
const o = f as AsObject | null;
|
|
2553
|
+
if (o?.$of) {
|
|
2554
|
+
return (o.$of as Traits).abc;
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
return o?.$global ? this.traitsOf(o.$global).abc : null;
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2245
2560
|
/** A Function object calling `f`, with `global` as its receiver when it has none. */
|
|
2246
2561
|
newFunctionObject(f: Method, global: AsObject | null): AsObject {
|
|
2247
2562
|
const o = this.functionTraits.instance();
|
|
@@ -2519,7 +2834,7 @@ export class Runtime {
|
|
|
2519
2834
|
return v;
|
|
2520
2835
|
}
|
|
2521
2836
|
|
|
2522
|
-
throw this.error("TypeError", 1034, this.describe(v), traits.
|
|
2837
|
+
throw this.error("TypeError", 1034, this.describe(v), traits.errorName);
|
|
2523
2838
|
}
|
|
2524
2839
|
}
|
|
2525
2840
|
}
|
|
@@ -2544,7 +2859,7 @@ export class Runtime {
|
|
|
2544
2859
|
return v;
|
|
2545
2860
|
}
|
|
2546
2861
|
|
|
2547
|
-
throw this.error("TypeError", 1034, this.describe(v), traits.
|
|
2862
|
+
throw this.error("TypeError", 1034, this.describe(v), traits.errorName);
|
|
2548
2863
|
}
|
|
2549
2864
|
|
|
2550
2865
|
coerceString(v: Value): string | null {
|
|
@@ -2785,7 +3100,7 @@ export class Runtime {
|
|
|
2785
3100
|
}
|
|
2786
3101
|
}
|
|
2787
3102
|
|
|
2788
|
-
throw this.error("TypeError", 1050, o.$traits.
|
|
3103
|
+
throw this.error("TypeError", 1050, o.$traits.errorName);
|
|
2789
3104
|
}
|
|
2790
3105
|
|
|
2791
3106
|
add(a: Value, b: Value): Value {
|
|
@@ -3124,7 +3439,13 @@ export class Runtime {
|
|
|
3124
3439
|
return new AsError(`${name}: ${message}`);
|
|
3125
3440
|
}
|
|
3126
3441
|
|
|
3127
|
-
|
|
3442
|
+
const made = this.constructClass(cls, [message, id]);
|
|
3443
|
+
// What the number stands for, kept beside the message for a host's report (detailOf).
|
|
3444
|
+
if (!this.debugger) {
|
|
3445
|
+
Object.defineProperty(made, "$detail", { value: errorMessage(true, id, args) });
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
return made;
|
|
3128
3449
|
}
|
|
3129
3450
|
|
|
3130
3451
|
/** See stackOf in errors.ts. */
|
|
@@ -3132,6 +3453,11 @@ export class Runtime {
|
|
|
3132
3453
|
return stackOf(error);
|
|
3133
3454
|
}
|
|
3134
3455
|
|
|
3456
|
+
/** See detailOf in errors.ts. */
|
|
3457
|
+
detailOf(error: Value): string | null {
|
|
3458
|
+
return detailOf(error);
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3135
3461
|
/** See errorMessage in errors.ts. */
|
|
3136
3462
|
errorMessage(id: number, args: Value[] = []): string {
|
|
3137
3463
|
return errorMessage(this.debugger, id, args);
|
|
@@ -3162,6 +3488,10 @@ export class Runtime {
|
|
|
3162
3488
|
return this.error("RangeError", 1506);
|
|
3163
3489
|
}
|
|
3164
3490
|
|
|
3491
|
+
if (e instanceof UnsupportedError) {
|
|
3492
|
+
return this.unsupportedCaught(e);
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3165
3495
|
if (e instanceof Error && !(e instanceof AsError)) {
|
|
3166
3496
|
throw e;
|
|
3167
3497
|
}
|
|
@@ -3169,6 +3499,30 @@ export class Runtime {
|
|
|
3169
3499
|
return e;
|
|
3170
3500
|
}
|
|
3171
3501
|
|
|
3502
|
+
/** What a catch was told of already (unsupportedCaught). */
|
|
3503
|
+
private readonly unsupportedTold = new Set<string>();
|
|
3504
|
+
|
|
3505
|
+
/**
|
|
3506
|
+
* What is not supported as the AS3 error a catch gets: an
|
|
3507
|
+
* IllegalOperationError with its message, or an Error where the player's
|
|
3508
|
+
* classes are not loaded; said once to the host, as the code may say nothing.
|
|
3509
|
+
*/
|
|
3510
|
+
private unsupportedCaught(e: UnsupportedError): Value {
|
|
3511
|
+
if (!this.unsupportedTold.has(e.message)) {
|
|
3512
|
+
this.unsupportedTold.add(e.message);
|
|
3513
|
+
this.onUnsupported?.(e.message);
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
let cls: AsObject;
|
|
3517
|
+
try {
|
|
3518
|
+
cls = this.resolve(this.cls(namespace(NS_Public, "flash.errors"), "IllegalOperationError"));
|
|
3519
|
+
} catch {
|
|
3520
|
+
cls = this.builtinClass("Error");
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
return this.constructClass(cls, [e.message, 0]);
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3172
3526
|
catches(e: Value, type: TypeRef): boolean {
|
|
3173
3527
|
return this.isInstanceOf(e, this.traitsOfType(type));
|
|
3174
3528
|
}
|
|
@@ -3178,7 +3532,7 @@ export class Runtime {
|
|
|
3178
3532
|
}
|
|
3179
3533
|
|
|
3180
3534
|
unsupported(what: string): Error {
|
|
3181
|
-
return new
|
|
3535
|
+
return new UnsupportedError(`swf2es: ${what} is not supported yet`);
|
|
3182
3536
|
}
|
|
3183
3537
|
|
|
3184
3538
|
// Class aliases and the classes AMF makes (amf-classes.ts).
|