@awayfl/avm2
Version:
Virtual machine for executing AS3 code
105 lines (91 loc) • 3.38 kB
text/typescript
import { ensureBoxedReceiver } from '../run/ensureBoxedReceiver';
import { AXObject } from '../run/AXObject';
import { isNullOrUndefined, assert } from '@awayjs/graphics';
import { Errors } from '../errors';
import { checkValue } from '../run/checkValue';
import { AXCallable } from '../run/AXCallable';
import { MethodInfo } from '../abc/lazy/MethodInfo';
import { Scope } from '../run/Scope';
import { ASObject } from './ASObject';
import { addPrototypeFunctionAlias } from './addPrototypeFunctionAlias';
import { release, defineNonEnumerableProperty } from '@awayfl/swf-loader';
import { sliceArguments } from '../run/writers';
import { ASArray } from './ASArray';
export class ASFunction extends ASObject {
static classInitializer() {
const proto: any = this.dPrototype;
const asProto: any = ASFunction.prototype;
addPrototypeFunctionAlias(proto, '$BgtoString', asProto.toString);
addPrototypeFunctionAlias(proto, '$Bgcall', asProto.call);
addPrototypeFunctionAlias(proto, '$Bgapply', asProto.apply);
defineNonEnumerableProperty(proto, 'value', asProto.native_functionValue);
}
private _prototype: AXObject;
private _prototypeInitialzed: boolean = false;
/*internal*/ value: AXCallable;
/*internal*/ receiver: {scope: Scope};
protected methodInfo: MethodInfo;
public setReceiver(receiver: any) {
this.receiver = receiver;
}
axConstruct(args: any[]) {
let prototype = this.prototype;
// AS3 allows setting null/undefined prototypes. In order to make our value checking work,
// we need to set a null-prototype that has the right inheritance chain. Since AS3 doesn't
// have `__proto__` or `getPrototypeOf`, this is completely hidden from content.
if (isNullOrUndefined(prototype)) {
prototype = this.sec.AXFunctionUndefinedPrototype;
}
release || assert(typeof prototype === 'object');
release || checkValue(prototype);
const object = Object.create(prototype);
object.__ctorFunction = this;
this.value.apply(object, args);
return object;
}
axIsInstanceOf(obj: any) {
return obj && obj.__ctorFunction === this;
}
native_functionValue() {
// Empty base function.
}
get prototype(): AXObject {
if (!this._prototypeInitialzed) {
this._prototype = Object.create(this.sec.AXObject.tPrototype);
this._prototypeInitialzed = true;
}
return this._prototype;
}
set prototype(prototype: AXObject) {
if (isNullOrUndefined(prototype)) {
prototype = undefined;
} else if (typeof prototype !== 'object' || this.sec.isPrimitive(prototype)) {
this.sec.throwError('TypeError', Errors.PrototypeTypeError);
}
this._prototypeInitialzed = true;
this._prototype = prototype;
}
get length(): number {
if (this.value.methodInfo) {
return this.value.methodInfo.parameters.length;
}
return this.value.length;
}
toString() {
return 'function Function() {}';
}
call(thisArg: any) {
thisArg = ensureBoxedReceiver(this.sec, thisArg, this);
return this.value.apply(thisArg, sliceArguments(arguments, 1));
}
apply(thisArg: any, argArray?: ASArray): any {
thisArg = ensureBoxedReceiver(this.sec, thisArg, this);
return this.value.apply(thisArg, argArray ? argArray.value : undefined);
}
axCall(thisArg: any): any {
return this.value.apply(thisArg, sliceArguments(arguments, 1));
}
axApply(thisArg: any, argArray?: any[]): any {
return this.value.apply(thisArg, argArray);
}
}