@awayfl/avm2
Version:
Virtual machine for executing AS3 code
101 lines (76 loc) • 2.21 kB
text/typescript
import { Multiname } from '../abc/lazy/Multiname';
export const IS_EXTERNAL_CLASS = Symbol('External class marker');
type Ctr = { new (): Object };
export const LONG_NAMES = /nape./;
export const extClasses = {
_lib: null,
set lib(v: any) {
v && console.debug('[AVM2] Register external lib:', { ...v });
this._lib = v;
},
get lib() {
return this._lib;
}
};
export function getExtClassField(name: string, namespace: string = undefined): Ctr | null {
const lib = extClasses._lib;
if (!lib || !name)
return null;
// fast check for flattened modules
if (!namespace || typeof lib[name] !== 'undefined')
return lib[name];
if (!namespace)
return null;
let trace = lib;
const path = namespace.split('.');
for (const child of path) {
trace = trace[child];
if (!trace) {
return null;
}
}
return trace[name] as Ctr;
}
/**
* Try construct object from external lib, like as Box2D or Nape
* @param mn
* @param args
*/
export function extClassConstructor(mn: Multiname, args: any[]) {
if (!extClasses._lib)
return null;
const ns = mn.namespace?.uri;
const name = mn.name;
const isLong = ns && LONG_NAMES.test(ns);
const Constructor = getExtClassField(name, isLong ? ns : undefined);
if (typeof Constructor !== 'function') {
return null;
}
Object.defineProperty(Constructor.prototype, IS_EXTERNAL_CLASS, {
value: true
});
const obj = Reflect.construct(Constructor, args);
// force fast mode;
// legacy
obj.__fast__ = true;
return obj;
}
export function emitIsAX(name: string) {
if (!extClasses._lib)
return 'true';
return `(${name} != undefined && ${name}[AX_CLASS_SYMBOL])`;
}
export function needFastCheck() {
return !!extClasses._lib;
}
export function emitIsAXOrPrimitive(name: string, explictNull = false): string {
if (!extClasses._lib)
return 'true';
const nullTest = explictNull ? '' : `|| ${name} == null`;
return `(_a = typeof ${name}, ((_a !== 'object' && _a !== 'function' ) ${nullTest} || ${name}[AX_CLASS_SYMBOL]))`;
}
export function emitIsCallableNative(name: string, func: string) {
if (!extClasses._lib)
return 'false';
return `( !${name}[AX_CLASS_SYMBOL] && typeof ${name}['${func}'] === 'function')`;
}