@awayfl/avm2
Version:
Virtual machine for executing AS3 code
129 lines (128 loc) • 4.91 kB
JavaScript
import { Errors } from '../errors';
import { IS_AX_CLASS } from './AXClass';
var Scope = /** @class */ (function () {
function Scope(parent, object, isWith) {
if (isWith === void 0) { isWith = false; }
this.parent = parent;
this.object = object;
this.isWith = isWith;
this.defaultNamespace = null;
this.cache = [];
Scope.ID++;
this[IS_AX_CLASS] = true;
this.global = parent ? parent.global : this;
object['__scope__'] = this;
}
Object.defineProperty(Scope.prototype, "superConstructor", {
get: function () {
var superCtr = this.object.superClass;
if (!superCtr) {
return null;
}
var r = superCtr[IS_AX_CLASS] ? superCtr.tPrototype.axInitializer : superCtr;
// hack!
// redefine field. Now it always return precomputed field.
Object.defineProperty(this, 'superConstructor', { value: r });
return r;
},
enumerable: false,
configurable: true
});
Scope.prototype.extend = function (object) {
if (object === this.object)
return this;
var c = object['__scope__'];
if (c && c.parent == this) {
return c;
}
return new Scope(this, object, false);
};
Scope.prototype.findDepth = function (object) {
var current = this;
var depth = 0;
while (current) {
if (current.object === object) {
return depth;
}
depth++;
current = current.parent;
}
return -1;
};
Scope.prototype.getScopeObjects = function () {
var objects = [];
var current = this;
while (current) {
objects.unshift(current.object);
current = current.parent;
}
return objects;
};
Scope.prototype.getScopeProperty = function (mn, strict, scopeOnly) {
return this.findScopeProperty(mn, strict, scopeOnly).axGetProperty(mn);
};
Scope.prototype.findScopeProperty = function (mn, strict, scopeOnly) {
if (mn.mutable || scopeOnly)
return this._findScopeProperty(mn, strict, scopeOnly);
if (mn.scope === this.object && !this.isWith)
return mn.value;
var value = this._findScopeProperty(mn, strict, scopeOnly);
if (!this.isWith) {
mn.value = value;
mn.scope = this.object;
}
return value;
};
Scope.prototype._findScopeProperty = function (mn, strict, scopeOnly) {
// Multinames with a `null` name are the any name, '*'. Need to catch those here, because
// otherwise we'll get a failing assert in `RuntimeTraits#getTrait` below.
if (mn.name === null) {
this.global.object.sec.throwError('ReferenceError', Errors.UndefinedVarError, '*');
}
var object = this.cache[mn.id];
if (object)
return object;
// Scope lookups should not be trapped by proxies. Except for with scopes, check only trait
// properties.
if (this.object && this.object[IS_AX_CLASS] && (this.isWith ?
this.object.axHasPropertyInternal(mn) :
this.object.traits.getTrait(mn.namespaces, mn.name))) {
return (this.isWith || mn.isRuntime()) ? this.object : (this.cache[mn.id] = this.object);
}
if (this.parent) {
object = this.parent.findScopeProperty(mn, strict, scopeOnly);
if (mn.kind === 7 /* CONSTANT.QName */) {
this.cache[mn.id] = object;
}
return object;
}
if (scopeOnly) {
return null;
}
// Attributes can't be stored on globals or be directly defined in scripts.
if (mn.isAttribute()) {
this.object.sec.throwError('ReferenceError', Errors.UndefinedVarError, mn.name);
}
// If we can't find the property look in the domain.
var globalObject = this.global.object;
if ((object = globalObject.applicationDomain.findProperty(mn, strict, true))) {
return object;
}
// If we still haven't found it, look for dynamic properties on the global.
// No need to do this for non-strict lookups as we'll end up returning the
// global anyways.
if (strict) {
if (!(mn.getPublicMangledName() in globalObject)) {
this.global.object.sec.throwError('ReferenceError', Errors.UndefinedVarError, mn.name);
}
}
// Can't find it still, return the global object.
return globalObject;
};
Scope.prototype.toString = function () {
return '' + this.parent + ' => ' + this.object + ' ' + this.isWith;
};
Scope.ID = 0;
return Scope;
}());
export { Scope };