@awayfl/avm2
Version:
Virtual machine for executing AS3 code
521 lines (520 loc) • 21.6 kB
JavaScript
import { __extends } from "tslib";
import { assert } from '@awayjs/graphics';
import { isNumeric, toNumber, isIndex, isNullOrUndefined, release, assertNotImplemented, unexpected, defineNonEnumerableProperty } from '@awayfl/swf-loader';
import { Errors } from '../errors';
import { ASObject } from '../nat/ASObject';
import { axCoerceName } from '../run/axCoerceName';
import { checkValue } from '../run/checkValue';
import { axIsCallable } from '../run/axIsCallable';
import { IS_AX_CLASS } from '../run/AXClass';
import { axCoerceNumber } from '../run/axCoerceNumber';
import { axCoerceString } from '../run/axCoerceString';
/*
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var BaseVector = /** @class */ (function (_super) {
__extends(BaseVector, _super);
function BaseVector() {
return _super !== null && _super.apply(this, arguments) || this;
}
BaseVector.prototype.axGetProperty = function (mn) {
var nm = mn.name;
nm = typeof nm === 'number' ? nm : axCoerceName(nm);
if ((nm | 0) === nm || isNumeric(nm)) {
release || assert(mn.isRuntimeName());
return this.axGetNumericProperty(typeof nm === 'number' ? nm : nm | 0);
}
return _super.prototype.axGetProperty.call(this, mn);
};
BaseVector.prototype.axSetProperty = function (mn, value, bc) {
release || checkValue(value);
var nm = mn.name;
nm = typeof nm === 'number' ? nm : axCoerceName(nm);
if ((nm | 0) === nm || isNumeric(nm)) {
release || assert(mn.isRuntimeName());
this.axSetNumericProperty(typeof nm === 'number' ? nm : nm | 0, value);
return;
}
_super.prototype.axSetProperty.call(this, mn, value, bc);
};
BaseVector.prototype.axGetPublicProperty = function (nm) {
nm = typeof nm === 'number' ? nm : axCoerceName(nm);
if ((nm | 0) === nm || isNumeric(nm)) {
return this.axGetNumericProperty(typeof nm === 'number' ? nm : nm | 0);
}
return this['$Bg' + nm];
};
BaseVector.prototype.axSetPublicProperty = function (nm, value) {
release || checkValue(value);
nm = typeof nm === 'number' ? nm : axCoerceName(nm);
if ((nm | 0) === nm || isNumeric(nm)) {
this.axSetNumericProperty(typeof nm === 'number' ? nm : nm | 0, value);
return;
}
this['$Bg' + nm] = value;
};
BaseVector.prototype.axNextName = function (index) {
return index - 1;
};
/**
* Throws exceptions for the cases where Flash does, and returns false if the callback
* is null or undefined. In that case, the calling function returns its default value.
*/
BaseVector.prototype.checkVectorMethodArgs = function (callback, thisObject) {
if (isNullOrUndefined(callback)) {
return false;
}
var sec = this.sec;
if (!axIsCallable(callback)) {
sec.throwError('TypeError', Errors.CheckTypeFailedError, callback, 'Function');
}
if (callback.axClass === sec.AXMethodClosure &&
!isNullOrUndefined(thisObject)) {
sec.throwError('TypeError', Errors.ArrayFilterNonNullObjectError);
}
return true;
};
return BaseVector;
}(ASObject));
export { BaseVector };
var Vector = /** @class */ (function (_super) {
__extends(Vector, _super);
function Vector() {
return _super !== null && _super.apply(this, arguments) || this;
}
Vector.axIsType = function (x) {
return this.dPrototype.isPrototypeOf(x) ||
this.sec.Int32Vector.axClass.dPrototype.isPrototypeOf(x) ||
this.sec.Uint32Vector.axClass.dPrototype.isPrototypeOf(x) ||
this.sec.Float64Vector.axClass.dPrototype.isPrototypeOf(x) ||
this.sec.ObjectVector.axClass.dPrototype.isPrototypeOf(x);
};
return Vector;
}(ASObject));
export { Vector };
var GenericVector = /** @class */ (function (_super) {
__extends(GenericVector, _super);
function GenericVector(length, fixed) {
if (length === void 0) { length = 0; }
if (fixed === void 0) { fixed = false; }
var _this = _super.call(this) || this;
length = length >>> 0;
fixed = !!fixed;
_this._fixed = !!fixed;
_this._buffer = new Array(length);
_this._fill(0, length, _this.axClass.defaultValue);
return _this;
}
GenericVector.classInitializer = function () {
var proto = this.dPrototype;
var tProto = this.tPrototype;
// Fix up MOP handlers to not apply to the dynamic prototype, which is a plain object.
tProto.axGetProperty = proto.axGetProperty;
tProto.axGetNumericProperty = proto.axGetNumericProperty;
tProto.axSetProperty = proto.axSetProperty;
tProto.axSetNumericProperty = proto.axSetNumericProperty;
tProto.axHasPropertyInternal = proto.axHasPropertyInternal;
tProto.axNextName = proto.axNextName;
tProto.axNextNameIndex = proto.axNextNameIndex;
tProto.axNextValue = proto.axNextValue;
proto.axGetProperty = ASObject.prototype.axGetProperty;
proto.axGetNumericProperty = ASObject.prototype.axGetNumericProperty;
proto.axSetProperty = ASObject.prototype.axSetProperty;
proto.axSetNumericProperty = ASObject.prototype.axSetNumericProperty;
proto.axHasPropertyInternal = ASObject.prototype.axHasPropertyInternal;
proto.axNextName = ASObject.prototype.axNextName;
proto.axNextNameIndex = ASObject.prototype.axNextNameIndex;
proto.axNextValue = ASObject.prototype.axNextValue;
var asProto = GenericVector.prototype;
defineNonEnumerableProperty(proto, '$Bgjoin', asProto.join);
// Same as join, see VectorImpl.as in Tamarin repository.
defineNonEnumerableProperty(proto, '$BgtoString', asProto.join);
defineNonEnumerableProperty(proto, '$BgtoLocaleString', asProto.toLocaleString);
defineNonEnumerableProperty(proto, '$Bgpop', asProto.pop);
defineNonEnumerableProperty(proto, '$Bgpush', asProto.push);
defineNonEnumerableProperty(proto, '$Bgreverse', asProto.reverse);
defineNonEnumerableProperty(proto, '$Bgconcat', asProto.concat);
defineNonEnumerableProperty(proto, '$Bgsplice', asProto.splice);
defineNonEnumerableProperty(proto, '$Bgslice', asProto.slice);
defineNonEnumerableProperty(proto, '$Bgshift', asProto.shift);
defineNonEnumerableProperty(proto, '$Bgunshift', asProto.unshift);
defineNonEnumerableProperty(proto, '$BgindexOf', asProto.indexOf);
defineNonEnumerableProperty(proto, '$BglastIndexOf', asProto.lastIndexOf);
defineNonEnumerableProperty(proto, '$BgforEach', asProto.forEach);
defineNonEnumerableProperty(proto, '$Bgmap', asProto.map);
defineNonEnumerableProperty(proto, '$Bgfilter', asProto.filter);
defineNonEnumerableProperty(proto, '$Bgsome', asProto.some);
defineNonEnumerableProperty(proto, '$Bgevery', asProto.every);
defineNonEnumerableProperty(proto, '$Bgsort', asProto.sort);
defineNonEnumerableProperty(proto, 'checkVectorMethodArgs', asProto.checkVectorMethodArgs);
};
GenericVector.axApply = function (_, args) {
var object = args[0];
if (this.axIsType(object)) {
return object;
}
var length = object.axGetPublicProperty('length');
if (length !== undefined) {
var v = this.axConstruct([length, false]);
for (var i = 0; i < length; i++) {
v.axSetNumericProperty(i, object.axGetPublicProperty(i));
}
return v;
}
unexpected();
};
GenericVector.defaultCompareFunction = function (a, b) {
return String(a).localeCompare(String(b));
};
GenericVector.compare = function (a, b, options, compareFunction) {
release || assertNotImplemented(!(options & GenericVector.CASEINSENSITIVE), 'CASEINSENSITIVE');
release || assertNotImplemented(!(options & GenericVector.UNIQUESORT), 'UNIQUESORT');
release || assertNotImplemented(!(options & GenericVector.RETURNINDEXEDARRAY), 'RETURNINDEXEDARRAY');
var result = 0;
if (!compareFunction) {
compareFunction = GenericVector.defaultCompareFunction;
}
if (options & GenericVector.NUMERIC) {
a = toNumber(a);
b = toNumber(b);
result = a < b ? -1 : (a > b ? 1 : 0);
}
else {
result = compareFunction(a, b);
}
if (options & GenericVector.DESCENDING) {
result *= -1;
}
return result;
};
GenericVector.prototype._fill = function (index, length, value) {
for (var i = 0; i < length; i++) {
this._buffer[index + i] = value;
}
};
/**
* Can't use Array.prototype.toString because it doesn't print |null|s the same way as AS3.
*/
GenericVector.prototype.toString = function () {
var result = [];
for (var i = 0; i < this._buffer.length; i++) {
var entry = this._buffer[i];
result.push(entry === null ? 'null' : (entry + ''));
}
return result.join(',');
};
GenericVector.prototype.toLocaleString = function () {
var result = [];
for (var i = 0; i < this._buffer.length; i++) {
var entry = this._buffer[i];
if (entry && typeof entry === 'object') {
result.push(entry.$BgtoLocaleString());
}
else {
result.push(entry + '');
}
}
return result.join(',');
};
GenericVector.prototype.sort = function (sortBehavior) {
if (typeof sortBehavior === 'undefined') {
this._buffer.sort();
return this;
}
if (this.sec.AXFunction.axIsType(sortBehavior)) {
var func = sortBehavior.value;
var res = sortBehavior.receiver;
this._buffer.sort(func.bind(res));
return this;
}
var options = sortBehavior | 0;
// 80pro: todo:
//release || assertNotImplemented (!(options & Int32Vector.UNIQUESORT), "UNIQUESORT");
//release || assertNotImplemented (!(options & Int32Vector.RETURNINDEXEDARRAY), "RETURNINDEXEDARRAY");
if (options & GenericVector.NUMERIC) {
if (options & GenericVector.DESCENDING) {
this._buffer.sort(function (a, b) { return axCoerceNumber(b) - axCoerceNumber(a); });
return this;
}
this._buffer.sort(function (a, b) { return axCoerceNumber(a) - axCoerceNumber(b); });
return this;
}
if (options & GenericVector.CASEINSENSITIVE) {
if (options & GenericVector.DESCENDING) {
this._buffer.sort(function (a, b) { return axCoerceString(b).toLowerCase() -
axCoerceString(a).toLowerCase(); });
return this;
}
this._buffer.sort(function (a, b) { return axCoerceString(a).toLowerCase() -
axCoerceString(b).toLowerCase(); });
return this;
}
if (options & GenericVector.DESCENDING) {
this._buffer.sort(function (a, b) { return b - a; });
return this;
}
this._buffer.sort();
return this;
};
/**
* Executes a |callback| function with three arguments: element, index, the vector itself as
* well as passing the |thisObject| as |this| for each of the elements in the vector. If any of
* the callbacks return |false| the function terminates, otherwise it returns |true|.
*/
GenericVector.prototype.every = function (callback, thisObject) {
if (!this.checkVectorMethodArgs(callback, thisObject)) {
return true;
}
for (var i = 0; i < this._buffer.length; i++) {
if (!callback.axCall(thisObject, this.axGetNumericProperty(i), i, this)) {
return false;
}
}
return true;
};
/**
* Filters the elements for which the |callback| method returns |true|. The |callback| function
* is called with three arguments: element, index, the vector itself as well as passing the
* |thisObject| as |this| for each of the elements in the vector.
*/
GenericVector.prototype.filter = function (callback, thisObject) {
var v = this.axClass.axConstruct([0, false]);
if (!this.checkVectorMethodArgs(callback, thisObject)) {
return v;
}
for (var i = 0; i < this._buffer.length; i++) {
if (callback.call(thisObject, this.axGetNumericProperty(i), i, this)) {
v.push(this.axGetNumericProperty(i));
}
}
return v;
};
GenericVector.prototype.map = function (callback, thisObject) {
var v = this.axClass.axConstruct([this.length, false]);
if (!this.checkVectorMethodArgs(callback, thisObject)) {
return v;
}
for (var i = 0; i < this._buffer.length; i++) {
v.push(this._coerce(callback.call(thisObject, this.axGetNumericProperty(i), i, this)));
}
return v;
};
GenericVector.prototype.some = function (callback, thisObject) {
if (!this.checkVectorMethodArgs(callback, thisObject)) {
return false;
}
for (var i = 0; i < this._buffer.length; i++) {
if (callback.call(thisObject, this.axGetNumericProperty(i), i, this)) {
return true;
}
}
return false;
};
GenericVector.prototype.forEach = function (callback, thisObject) {
if (!this.checkVectorMethodArgs(callback, thisObject)) {
return;
}
for (var i = 0; i < this._buffer.length; i++) {
callback.call(thisObject, this.axGetNumericProperty(i), i, this);
}
};
GenericVector.prototype.join = function (separator) {
if (separator === void 0) { separator = ','; }
var buffer = this._buffer;
var limit = this._buffer.length;
var result = '';
for (var i = 0; i < limit - 1; i++) {
result += buffer[i] + separator;
}
if (limit > 0) {
result += buffer[limit - 1];
}
return result;
};
GenericVector.prototype.indexOf = function (searchElement, fromIndex) {
if (fromIndex === void 0) { fromIndex = 0; }
return this._buffer.indexOf(searchElement, fromIndex);
};
GenericVector.prototype.lastIndexOf = function (searchElement, fromIndex) {
if (fromIndex === void 0) { fromIndex = 0x7fffffff; }
return this._buffer.lastIndexOf(searchElement, fromIndex);
};
GenericVector.prototype.push = function (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 /*...rest*/) {
this._checkFixed();
for (var i = 0; i < arguments.length; i++) {
this._buffer.push(this._coerce(arguments[i]));
}
};
GenericVector.prototype.pop = function () {
this._checkFixed();
if (this._buffer.length === 0) {
return undefined;
}
return this._buffer.pop();
};
GenericVector.prototype.concat = function () {
// TODO: need to type check the arguments, but isType doesn't exist.
var buffers = [];
for (var i = 0; i < arguments.length; i++) {
//buffers.push(this._coerce(arguments[i])._buffer);
// coerce doesn't works normaly yet
buffers.push(arguments[i]._buffer);
}
var buffer = this._buffer.concat.apply(this._buffer, buffers);
var result = this.axClass.axConstruct([]);
result._buffer = buffer;
return result;
};
GenericVector.prototype.reverse = function () {
this._buffer.reverse();
return this;
};
GenericVector.prototype._coerce = function (v) {
if (this.axClass.type)
return this.axClass.type[IS_AX_CLASS] ? this.axClass.type.axCoerce(v) : v;
return v;
};
GenericVector.prototype.shift = function () {
this._checkFixed();
if (this._buffer.length === 0) {
return undefined;
}
return this._buffer.shift();
};
GenericVector.prototype.unshift = function () {
if (!arguments.length) {
return;
}
this._checkFixed();
for (var i = 0; i < arguments.length; i++) {
this._buffer.unshift(this._coerce(arguments[i]));
}
};
GenericVector.prototype.slice = function (start, end) {
if (start === void 0) { start = 0; }
if (end === void 0) { end = 0x7fffffff; }
var buffer = this._buffer;
var length = buffer.length;
var first = Math.min(Math.max(start, 0), length);
var last = Math.min(Math.max(end, first), length);
var result = this.axClass.axConstruct([last - first, this.fixed]);
result._buffer = buffer.slice(first, last);
return result;
};
GenericVector.prototype.splice = function (start, deleteCount_ /*, ...items */) {
var buffer = this._buffer;
var length = buffer.length;
var first = Math.min(Math.max(start, 0), length);
var deleteCount = Math.min(Math.max(deleteCount_, 0), length - first);
var insertCount = arguments.length - 2;
if (deleteCount !== insertCount) {
this._checkFixed();
}
var items = [first, deleteCount];
for (var i = 2; i < insertCount + 2; i++) {
items[i] = this._coerce(arguments[i]);
}
var result = this.axClass.axConstruct([deleteCount, this.fixed]);
result._buffer = buffer.splice.apply(buffer, items);
return result;
};
Object.defineProperty(GenericVector.prototype, "length", {
get: function () {
return this._buffer.length;
},
set: function (value) {
value = value >>> 0;
if (value > this._buffer.length) {
for (var i = this._buffer.length; i < value; i++) {
this._buffer[i] = this.axClass.defaultValue;
}
}
else {
this._buffer.length = value;
}
release || assert(this._buffer.length === value);
},
enumerable: false,
configurable: true
});
Object.defineProperty(GenericVector.prototype, "fixed", {
get: function () {
return this._fixed;
},
set: function (f) {
this._fixed = !!f;
},
enumerable: false,
configurable: true
});
Object.defineProperty(GenericVector.prototype, "value", {
get: function () {
return this._buffer;
},
enumerable: false,
configurable: true
});
GenericVector.prototype._checkFixed = function () {
if (this._fixed) {
this.sec.throwError('RangeError', Errors.VectorFixedError);
}
};
GenericVector.prototype.axGetNumericProperty = function (nm) {
var idx = nm | 0;
if (idx < 0 || idx >= this._buffer.length || idx != nm) {
this.sec.throwError('RangeError', Errors.OutOfRangeError, nm, this._buffer.length);
}
return this._buffer[idx];
};
GenericVector.prototype.axSetNumericProperty = function (nm, v) {
var length = this._buffer.length;
var idx = nm | 0;
if (idx < 0 || idx > length || idx != nm || (idx === length && this._fixed)) {
this.sec.throwError('RangeError', Errors.OutOfRangeError, nm, length);
}
this._buffer[idx] = this._coerce(v);
};
GenericVector.prototype.axHasPropertyInternal = function (mn) {
// Optimization for the common case of indexed element accesses.
if ((mn.name | 0) === mn.name) {
release || assert(mn.isRuntimeName());
return mn.name >= 0 && mn.name < this._buffer.length;
}
var name = axCoerceName(mn.name);
if (mn.isRuntimeName() && isIndex(name)) {
var index = name >>> 0;
return index >= 0 && index < this._buffer.length;
}
return this.axResolveMultiname(mn) in this;
};
GenericVector.prototype.axNextValue = function (index) {
return this._buffer[index - 1];
};
GenericVector.prototype.axNextNameIndex = function (index) {
var nextNameIndex = index + 1;
if (nextNameIndex <= this._buffer.length) {
return nextNameIndex;
}
return 0;
};
GenericVector.CASEINSENSITIVE = 1;
GenericVector.DESCENDING = 2;
GenericVector.UNIQUESORT = 4;
GenericVector.RETURNINDEXEDARRAY = 8;
GenericVector.NUMERIC = 16;
GenericVector.defaultValue = null;
return GenericVector;
}(BaseVector));
export { GenericVector };