UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

118 lines (100 loc) 3.59 kB
import { ClassInfo } from '../abc/lazy/ClassInfo'; import { InstanceInfo } from '../abc/lazy/InstanceInfo'; import { MethodTraitInfo } from '../abc/lazy/MethodTraitInfo'; import { namespaceTypeNames } from '../abc/lazy/NamespaceType'; import { TRAIT, TRAITNames } from '../abc/lazy/TRAIT'; import { MethodInfo } from './../abc/lazy/MethodInfo'; let SCRIPT_ID = 0; const validTest = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/; export interface IMethodReadableMeta { index: number; name: string; filePath: string; classPath: string; type: string; superClass?: string; returnType?: string; isValidName: boolean; isValidPath: boolean; kind?: string; } export function validateName(name: string) { return validTest.test(name); } export const CLASSES_NAMES_COLLISIONS: Record<string, number> = {}; export function nextScriptID(): number { return SCRIPT_ID++; } export function reconstructMetadata (methodInfo: MethodInfo, id: number): IMethodReadableMeta { const prefix = ('' + (id)).padLeft('0', 4); const funcName = (methodInfo.name).replace(/([^a-z0-9]+)/gi, '_'); let pathIsDefault = true; let fullPath = `__root__/${prefix}_${funcName || 'unknown'}`; let path = fullPath; let methodName = funcName; let isMemeber = true; let methodType = 'Public'; let superClass = undefined; if (methodInfo.trait) { if (methodInfo.trait.holder instanceof ClassInfo) { path = methodInfo.trait.holder.instanceInfo.getClassName().replace(/\./g, '/'); isMemeber = false; } else if (methodInfo.trait.holder instanceof InstanceInfo) { path = methodInfo.trait.holder.getClassName().replace(/\./g, '/'); superClass = methodInfo.trait.holder.superName?. toFQNString(false).replace(/\./g, '/'); } if (methodInfo.trait instanceof MethodTraitInfo) { methodName = methodInfo.trait.multiname.name; methodType = namespaceTypeNames[methodInfo.trait.multiname.namespace.type]; } if (methodInfo.trait && methodInfo.trait.kind === TRAIT.Getter) { methodName = 'get_' + methodName; } if (methodInfo.trait && methodInfo.trait.kind === TRAIT.Setter) { methodName = 'set_' + methodName; } if (methodInfo.isConstructor) { //constructor methodName = 'constructor'; } else { // member methodName = isMemeber ? ('m_' + methodName) : methodName; } pathIsDefault = false; fullPath = path + '/' + methodName; if (CLASSES_NAMES_COLLISIONS[fullPath] !== undefined) { const index = CLASSES_NAMES_COLLISIONS[fullPath] = CLASSES_NAMES_COLLISIONS[fullPath] + 1; fullPath += '$' + index; } else { CLASSES_NAMES_COLLISIONS[fullPath] = 0; } } // for instances if (methodInfo.instanceInfo) { path = methodInfo.instanceInfo.getClassName().replace(/\./g, '/'); methodName = methodInfo.isConstructor ? 'constructor' : funcName; superClass = methodInfo.instanceInfo.superName?. toFQNString(false).replace(/\./g, '/'); pathIsDefault = false; fullPath = path + '/' + methodName; } let hookMethodPath = `${path}${isMemeber ? '::' : '.'}${methodName}`; // reconstruct path to owner method if (methodInfo.parentInfo && pathIsDefault) { fullPath = methodInfo.parentInfo!.meta.filePath + '/' + `${prefix}_${methodName}`; hookMethodPath = fullPath; } return { index: methodInfo.index(), filePath: fullPath, classPath: hookMethodPath, name: methodName, type: methodType, superClass: superClass, returnType: methodInfo.typeName?.toString() || '*', isValidName: validateName(methodName), isValidPath: validateName(path.replace('/','_')), kind: methodInfo.trait && TRAITNames[methodInfo.trait.kind] }; }