UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

514 lines (513 loc) 21.4 kB
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 }); 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 };