@awayfl/avm1
Version:
Virtual machine for executing AS1 and AS2 code
1,310 lines • 73.2 kB
JavaScript
/*
* Copyright 2015 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.
*/
import { __extends } from "tslib";
// Implementation of the built-in ActionScript classes. Here we will implement
// functions and object prototypes that will be exposed to the AVM1 code.
// Object natives
import { alCallProperty, alCoerceString, alDefineObjectProperties, alGetObjectClass, alInstanceOf, alIsArray, alIsArrayLike, alIsFunction, alIsIndex, alIsString, alIterateArray, alNewObject, alToBoolean, alToInt32, alToInteger, alToNumber, alToObject, alToPrimitive, alToString } from './runtime';
import { Debug, release, isIndex } from '@awayfl/swf-loader';
import { AVM1Object } from './runtime/AVM1Object';
import { AVM1Globals } from './lib/AVM1Globals';
import { AVM1Function } from './runtime/AVM1Function';
import { AVM1PropertyDescriptor } from './runtime/AVM1PropertyDescriptor';
var AVM1ObjectPrototype = /** @class */ (function (_super) {
__extends(AVM1ObjectPrototype, _super);
function AVM1ObjectPrototype(context) {
return _super.call(this, context) || this;
// Initialization must be perfromed later after the Function creation.
// See the _initializePrototype and createBuiltins below.
}
AVM1ObjectPrototype.prototype._initializePrototype = function () {
var context = this.context;
alDefineObjectProperties(this, {
constructor: {
value: context.builtins.Object,
writable: true
},
valueOf: {
value: this._valueOf,
writable: true
},
toString: {
value: this._toString,
writable: true
},
addProperty: {
value: this.addProperty
},
hasOwnProperty: {
value: this.hasOwnProperty
},
isPropertyEnumerable: {
value: this.isPropertyEnumerable
},
isPrototypeOf: {
value: this.isPrototypeOf
},
unwatch: {
value: this.unwatch
},
watch: {
value: this.watch
}
});
};
AVM1ObjectPrototype.prototype._valueOf = function () {
return this;
};
AVM1ObjectPrototype.prototype._toString = function () {
if (alIsFunction(this)) {
// Really weird case of functions.
return '[type ' + alGetObjectClass(this) + ']';
}
return '[object ' + alGetObjectClass(this) + ']';
};
AVM1ObjectPrototype.prototype.addProperty = function (name, getter, setter) {
if (typeof name !== 'string' || name === '') {
return false;
}
if (!alIsFunction(getter)) {
return false;
}
if (!alIsFunction(setter) && setter !== null) {
return false;
}
var desc = this.alGetOwnProperty(name);
if (desc && !!(desc.flags & 2 /* AVM1PropertyFlags.DONT_DELETE */)) {
return false; // protected property
}
this.alSetOwnProperty(name, new AVM1PropertyDescriptor(128 /* AVM1PropertyFlags.ACCESSOR */, null, getter, setter || undefined));
return true;
};
AVM1ObjectPrototype.prototype.hasOwnProperty = function (name) {
return this.alHasOwnProperty(name);
};
AVM1ObjectPrototype.prototype.isPropertyEnumerable = function (name) {
var desc = this.alGetProperty(name);
return !(desc.flags & 1 /* AVM1PropertyFlags.DONT_ENUM */);
};
AVM1ObjectPrototype.prototype.isPrototypeOf = function (theClass) {
return alInstanceOf(this.context, this, theClass);
};
AVM1ObjectPrototype.prototype.unwatch = function (name) {
name = alCoerceString(this.context, name);
return this.alRemotePropertyWatcher(name);
};
AVM1ObjectPrototype.prototype.watch = function (name, callback, userData) {
name = alCoerceString(this.context, name);
if (!alIsFunction(callback)) {
return false;
}
return this.alAddPropertyWatcher(name, callback, userData);
};
return AVM1ObjectPrototype;
}(AVM1Object));
var AVM1ObjectFunction = /** @class */ (function (_super) {
__extends(AVM1ObjectFunction, _super);
function AVM1ObjectFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
prototype: {
value: proto
},
registerClass: {
value: _this.registerClass
}
});
return _this;
}
AVM1ObjectFunction.prototype.registerClass = function (name, theClass) {
this.context.registerClass(name, theClass);
};
AVM1ObjectFunction.prototype.alConstruct = function (args) {
if (args) {
var value = args[0];
if (value instanceof AVM1Object) {
return value;
}
switch (typeof value) {
case 'string':
case 'boolean':
case 'number':
return alToObject(this.context, value);
}
}
// null or undefined
return alNewObject(this.context);
};
AVM1ObjectFunction.prototype.alCall = function (thisArg, args) {
if (!args || args[0] === null || args[0] === undefined) {
return alNewObject(this.context);
}
return alToObject(this.context, args[0]);
};
return AVM1ObjectFunction;
}(AVM1Function));
export { AVM1ObjectFunction };
// Function natives
var AVM1FunctionPrototype = /** @class */ (function (_super) {
__extends(AVM1FunctionPrototype, _super);
function AVM1FunctionPrototype(context) {
return _super.call(this, context) || this;
}
AVM1FunctionPrototype.prototype._initializePrototype = function () {
var context = this.context;
this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(this, {
constructor: {
value: context.builtins.Function,
writable: true
},
call: this.call,
apply: this.apply
});
};
AVM1FunctionPrototype.prototype.call = function (thisArg) {
var args = [];
for (var _a = 1; _a < arguments.length; _a++) {
args[_a - 1] = arguments[_a];
}
var fn = alEnsureType(this, AVM1Function);
return fn.alCall(thisArg, args);
};
AVM1FunctionPrototype.prototype.apply = function (thisArg, args) {
var fn = alEnsureType(this, AVM1Function);
var nativeArgs = !args ? undefined :
alEnsureType(args, AVM1ArrayNative).value;
return fn.alCall(thisArg, nativeArgs);
};
return AVM1FunctionPrototype;
}(AVM1Object));
var AVM1FunctionFunction = /** @class */ (function (_super) {
__extends(AVM1FunctionFunction, _super);
function AVM1FunctionFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = context.builtins.Function.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
prototype: {
value: proto
}
});
return _this;
}
AVM1FunctionFunction.prototype.alConstruct = function (args) {
// ActionScript just returns the first argument.
return args ? args[0] : undefined;
};
AVM1FunctionFunction.prototype.alCall = function (thisArg, args) {
// ActionScript just returns the first argument.
return args ? args[0] : undefined;
};
return AVM1FunctionFunction;
}(AVM1Function));
export { AVM1FunctionFunction };
// Boolean natives
var AVM1BooleanNative = /** @class */ (function (_super) {
__extends(AVM1BooleanNative, _super);
function AVM1BooleanNative(context, value) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Boolean.alGetPrototypeProperty();
_this.alSetOwnConstructorProperty(context.builtins.Boolean);
_this.value = value;
return _this;
}
AVM1BooleanNative.prototype.valueOf = function () {
return this.value;
};
return AVM1BooleanNative;
}(AVM1Object));
export { AVM1BooleanNative };
var AVM1BooleanPrototype = /** @class */ (function (_super) {
__extends(AVM1BooleanPrototype, _super);
function AVM1BooleanPrototype(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
constructor: {
value: context.builtins.Boolean,
writable: true
},
valueOf: {
value: _this._valueOf,
writable: true
},
toString: {
value: _this._toString,
writable: true
}
});
return _this;
}
AVM1BooleanPrototype.prototype._valueOf = function () {
var native = alEnsureType(this, AVM1BooleanNative);
return native.value;
};
AVM1BooleanPrototype.prototype._toString = function () {
var native = alEnsureType(this, AVM1BooleanNative);
return native.value ? 'true' : 'false';
};
return AVM1BooleanPrototype;
}(AVM1Object));
export { AVM1BooleanPrototype };
var AVM1BooleanFunction = /** @class */ (function (_super) {
__extends(AVM1BooleanFunction, _super);
function AVM1BooleanFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = new AVM1BooleanPrototype(context);
alDefineObjectProperties(_this, {
prototype: {
value: proto
}
});
return _this;
}
AVM1BooleanFunction.prototype.alConstruct = function (args) {
var value = args ? alToBoolean(this.context, args[0]) : false;
return new AVM1BooleanNative(this.context, value);
};
AVM1BooleanFunction.prototype.alCall = function (thisArg, args) {
// TODO returns boolean value?
var value = args ? alToBoolean(this.context, args[0]) : false;
return value;
};
return AVM1BooleanFunction;
}(AVM1Function));
export { AVM1BooleanFunction };
// Number natives
var AVM1NumberNative = /** @class */ (function (_super) {
__extends(AVM1NumberNative, _super);
function AVM1NumberNative(context, value) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Number.alGetPrototypeProperty();
_this.alSetOwnConstructorProperty(context.builtins.Number);
_this.value = value;
return _this;
}
AVM1NumberNative.prototype.valueOf = function () {
return this.value;
};
return AVM1NumberNative;
}(AVM1Object));
export { AVM1NumberNative };
var AVM1NumberPrototype = /** @class */ (function (_super) {
__extends(AVM1NumberPrototype, _super);
function AVM1NumberPrototype(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
constructor: {
value: context.builtins.Number,
writable: true
},
valueOf: {
value: _this._valueOf,
writable: true
},
toString: {
value: _this._toString,
writable: true
}
});
return _this;
}
AVM1NumberPrototype.prototype._valueOf = function () {
var native = alEnsureType(this, AVM1NumberNative);
return native.value;
};
AVM1NumberPrototype.prototype._toString = function (radix) {
var native = alEnsureType(this, AVM1NumberNative);
return native.value.toString(radix || 10);
};
return AVM1NumberPrototype;
}(AVM1Object));
export { AVM1NumberPrototype };
var AVM1NumberFunction = /** @class */ (function (_super) {
__extends(AVM1NumberFunction, _super);
function AVM1NumberFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = new AVM1NumberPrototype(context);
alDefineObjectProperties(_this, {
prototype: {
value: proto
},
MAX_VALUE: Number.MAX_VALUE,
MIN_VALUE: Number.MIN_VALUE,
NaN: Number.NaN,
NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
POSITIVE_INFINITY: Number.POSITIVE_INFINITY
});
return _this;
}
AVM1NumberFunction.prototype.alConstruct = function (args) {
var value = args ? alToNumber(this.context, args[0]) : 0;
return new AVM1NumberNative(this.context, value);
};
AVM1NumberFunction.prototype.alCall = function (thisArg, args) {
// TODO returns number value?
var value = args ? alToNumber(this.context, args[0]) : 0;
return value;
};
return AVM1NumberFunction;
}(AVM1Function));
export { AVM1NumberFunction };
// String natives
var AVM1StringNative = /** @class */ (function (_super) {
__extends(AVM1StringNative, _super);
function AVM1StringNative(context, value) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.String.alGetPrototypeProperty();
_this.alSetOwnConstructorProperty(context.builtins.String);
_this.value = value;
return _this;
}
AVM1StringNative.prototype.toString = function () {
return this.value;
};
return AVM1StringNative;
}(AVM1Object));
export { AVM1StringNative };
// Most of the methods of String prototype are generic and accept any object.
var AVM1StringPrototype = /** @class */ (function (_super) {
__extends(AVM1StringPrototype, _super);
function AVM1StringPrototype(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
constructor: {
value: context.builtins.String,
writable: true
},
valueOf: {
value: _this._valueOf,
writable: true
},
toString: {
value: _this._toString,
writable: true
},
length: {
get: _this.getLength
},
charAt: {
value: _this.charAt,
writable: true
},
charCodeAt: {
value: _this.charCodeAt,
writable: true
},
concat: {
value: _this.concat,
writable: true
},
indexOf: {
value: _this.indexOf,
writable: true
},
lastIndexOf: {
value: _this.lastIndexOf,
writable: true
},
slice: {
value: _this.slice,
writable: true
},
split: {
value: _this.split,
writable: true
},
substr: {
value: _this.substr,
writable: true
},
substring: {
value: _this.substring,
writable: true
},
toLowerCase: {
value: _this.toLowerCase,
writable: true
},
toUpperCase: {
value: _this.toUpperCase,
writable: true
}
});
return _this;
}
AVM1StringPrototype.prototype._valueOf = function () {
var native = alEnsureType(this, AVM1StringNative);
return native.value;
};
AVM1StringPrototype.prototype._toString = function () {
var native = alEnsureType(this, AVM1StringNative);
return native.value;
};
AVM1StringPrototype.prototype.getLength = function () {
var native = alEnsureType(this, AVM1StringNative);
return native.value.length;
};
AVM1StringPrototype.prototype.charAt = function (index) {
var value = alToString(this.context, this);
return value.charAt(alToInteger(this.context, index));
};
AVM1StringPrototype.prototype.charCodeAt = function (index) {
var value = alToString(this.context, this);
return value.charCodeAt(alToInteger(this.context, index));
};
AVM1StringPrototype.prototype.concat = function () {
var items = [];
for (var _a = 0; _a < arguments.length; _a++) {
items[_a] = arguments[_a];
}
var stringItems = [alToString(this.context, this)];
for (var i = 0; i < items.length; ++i) {
stringItems.push(alToString(this.context, items[i]));
}
return stringItems.join('');
};
AVM1StringPrototype.prototype.indexOf = function (searchString, position) {
var value = alToString(this.context, this);
searchString = alToString(this.context, searchString);
position = alToInteger(this.context, position);
return value.indexOf(searchString, position);
};
AVM1StringPrototype.prototype.lastIndexOf = function (searchString, position) {
var value = alToString(this.context, this);
searchString = alToString(this.context, searchString);
position = arguments.length < 2 ? NaN : alToNumber(this.context, position); // SWF6 alToNumber(undefined) === 0
if (position < 0) {
// Different from JS
return -1;
}
return value.lastIndexOf(searchString, isNaN(position) ? undefined : position);
};
AVM1StringPrototype.prototype.slice = function (start, end) {
if (arguments.length === 0) {
// Different from JS
return undefined;
}
var value = alToString(this.context, this);
start = alToInteger(this.context, start);
end = end === undefined ? undefined : alToInteger(this.context, end);
return value.slice(start, end);
};
AVM1StringPrototype.prototype.split = function (separator, limit) {
var value = alToString(this.context, this);
// TODO separator as regular expression?
// for undefined seperator, flash does not do any split at all
if (typeof separator !== 'undefined') {
separator = alToString(this.context, separator);
limit = (limit === undefined ? ~0 : alToInt32(this.context, limit)) >>> 0;
return new AVM1ArrayNative(this.context, value.split(separator, limit));
}
return new AVM1ArrayNative(this.context, [value]);
};
AVM1StringPrototype.prototype.substr = function (start, length) {
// Different from JS
var value = alToString(this.context, this);
var valueLength = value.length;
start = alToInteger(this.context, start);
length = length === undefined ? valueLength : alToInteger(this.context, length);
if (start < 0) {
start = Math.max(0, valueLength + start);
}
if (length < 0) {
if (-length <= start) { // this one is weird -- don't ask
return '';
}
length = Math.max(0, valueLength + length);
}
return value.substr(start, length);
};
AVM1StringPrototype.prototype.substring = function (start, end) {
var value = alToString(this.context, this);
start = alToInteger(this.context, start);
if (start >= value.length) {
// Different from JS
return '';
}
end = end === undefined ? undefined : alToInteger(this.context, end);
return value.substring(start, end);
};
AVM1StringPrototype.prototype.toLowerCase = function () {
var value = alToString(this.context, this);
return value.toLowerCase();
};
AVM1StringPrototype.prototype.toUpperCase = function () {
var value = alToString(this.context, this);
return value.toUpperCase();
};
return AVM1StringPrototype;
}(AVM1Object));
export { AVM1StringPrototype };
var AVM1StringFunction = /** @class */ (function (_super) {
__extends(AVM1StringFunction, _super);
function AVM1StringFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = new AVM1StringPrototype(context);
alDefineObjectProperties(_this, {
prototype: {
value: proto
},
fromCharCode: {
value: _this.fromCharCode
}
});
return _this;
}
AVM1StringFunction.prototype.alConstruct = function (args) {
var value = args ? alToString(this.context, args[0]) : '';
return new AVM1StringNative(this.context, value);
};
AVM1StringFunction.prototype.alCall = function (thisArg, args) {
var value = args ? alToString(this.context, args[0]) : '';
return value;
};
AVM1StringFunction.prototype.fromCharCode = function () {
var _this = this;
var codes = [];
for (var _a = 0; _a < arguments.length; _a++) {
codes[_a] = arguments[_a];
}
codes = codes.map(function (code) { return alToInt32(_this.context, code) & 0xFFFF; });
return String.fromCharCode.apply(String, codes);
};
return AVM1StringFunction;
}(AVM1Function));
export { AVM1StringFunction };
// Array natives
var cachedArrayPropertyDescriptor = new AVM1PropertyDescriptor(64 /* AVM1PropertyFlags.DATA */, undefined);
var AVM1ArrayNative = /** @class */ (function (_super) {
__extends(AVM1ArrayNative, _super);
function AVM1ArrayNative(context, value) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Array.alGetPrototypeProperty();
_this.alSetOwnConstructorProperty(context.builtins.Array);
_this.value = value;
return _this;
}
AVM1ArrayNative.prototype.alGetOwnProperty = function (p) {
if (alIsIndex(this.context, p)) {
var index = alToInt32(this.context, p);
if (Object.getOwnPropertyDescriptor(this.value, index)) {
cachedArrayPropertyDescriptor.value = this.value[index];
return cachedArrayPropertyDescriptor;
}
}
return _super.prototype.alGetOwnProperty.call(this, p);
};
AVM1ArrayNative.prototype.alSetOwnProperty = function (p, v) {
if (alIsIndex(this.context, p)) {
var index = alToInt32(this.context, p);
if (!(v.flags & 64 /* AVM1PropertyFlags.DATA */) ||
!!(v.flags & 1 /* AVM1PropertyFlags.DONT_ENUM */) ||
!!(v.flags & 2 /* AVM1PropertyFlags.DONT_DELETE */)) {
throw new Error('Special property is non-supported for array');
}
this.value[index] = v.value;
return;
}
_super.prototype.alSetOwnProperty.call(this, p, v);
};
AVM1ArrayNative.prototype.alDeleteOwnProperty = function (p) {
if (alIsIndex(this.context, p)) {
var index = alToInt32(this.context, p);
delete this.value[index];
return;
}
_super.prototype.alDeleteOwnProperty.call(this, p);
};
AVM1ArrayNative.prototype.alGetOwnPropertiesKeys = function () {
var keys = _super.prototype.alGetOwnPropertiesKeys.call(this);
var itemIndices = [];
for (var i in this.value) {
itemIndices.push(i);
}
return itemIndices.concat(keys);
};
/**
* Creates a JavaScript array from the AVM1 list object.
* @param arr An array-like AVM1 object.
* @param fn A function that converts AVM1 list object item to JavaScript object.
* @param thisArg Optional. Value to use as this when executing fn.
* @returns {any[]} A JavaScript array.
*/
AVM1ArrayNative.mapToJSArray = function (arr, fn, thisArg) {
if (arr instanceof AVM1ArrayNative) {
return arr.value.map(fn, thisArg);
}
// This method is generic, so array-like objects can use it.
if (!alIsArrayLike(arr.context, arr)) {
// TODO generate proper AVM1 exception.
throw new Error('Invalid type'); // Interpreter will catch this.
}
var result = [];
alIterateArray(arr.context, arr, function (item, index) {
result.push(fn.call(thisArg, item, index));
});
return result;
};
return AVM1ArrayNative;
}(AVM1Object));
export { AVM1ArrayNative };
var AVM1ArraySortOnOptions;
(function (AVM1ArraySortOnOptions) {
AVM1ArraySortOnOptions[AVM1ArraySortOnOptions["CASEINSENSITIVE"] = 1] = "CASEINSENSITIVE";
AVM1ArraySortOnOptions[AVM1ArraySortOnOptions["DESCENDING"] = 2] = "DESCENDING";
AVM1ArraySortOnOptions[AVM1ArraySortOnOptions["UNIQUESORT"] = 4] = "UNIQUESORT";
AVM1ArraySortOnOptions[AVM1ArraySortOnOptions["RETURNINDEXEDARRAY"] = 8] = "RETURNINDEXEDARRAY";
AVM1ArraySortOnOptions[AVM1ArraySortOnOptions["NUMERIC"] = 16] = "NUMERIC";
})(AVM1ArraySortOnOptions || (AVM1ArraySortOnOptions = {}));
var sortArray = function (arr_in, comparefn) {
var arr = alEnsureType(arr_in, AVM1ArrayNative).value;
if (!alIsFunction(comparefn)) {
var doNumeric = typeof comparefn === 'number'
&& (comparefn & AVM1ArraySortOnOptions.NUMERIC || comparefn == -1);
var doDescending = typeof comparefn === 'number' && (comparefn & AVM1ArraySortOnOptions.DESCENDING);
if (doNumeric) {
arr.sort(function (a, b) {
while (a instanceof AVM1ArrayNative) {
a = alEnsureType(a, AVM1ArrayNative).value;
if (a && a.length > 0)
a = a[0];
}
while (b instanceof AVM1ArrayNative) {
b = alEnsureType(b, AVM1ArrayNative).value;
if (b && b.length > 0)
b = b[0];
}
return a - b;
});
}
else {
// ugly hack for moving undefined values to the beginning of the array
var i = arr.length;
while (i > 0) {
i--;
if (typeof arr[i] === 'undefined' || arr[i] === null) {
arr[i] = '00000000000AwayInternal';
}
}
arr.sort(function (a, b) {
while (a instanceof AVM1ArrayNative) {
a = alEnsureType(a, AVM1ArrayNative).value;
if (a && a.length > 0)
a = a[0];
}
while (b instanceof AVM1ArrayNative) {
b = alEnsureType(b, AVM1ArrayNative).value;
if (b && b.length > 0)
b = b[0];
}
return (a < b) ? -1 : 1;
});
i = arr.length;
while (i > 0) {
i--;
if (arr[i] == '00000000000AwayInternal') {
arr[i] = undefined;
}
}
}
if (doDescending)
arr.reverse();
}
else {
var args_1 = [undefined, undefined];
arr.sort(function (a, b) {
args_1[0] = a;
args_1[1] = b;
return comparefn.alCall(null, args_1);
});
}
return arr_in;
};
// TODO implement all the Array class and its prototype natives
var AVM1ArrayPrototype = /** @class */ (function (_super) {
__extends(AVM1ArrayPrototype, _super);
function AVM1ArrayPrototype(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
constructor: {
value: context.builtins.Array,
writable: true
},
join: {
value: _this.join,
writable: true
},
length: {
get: _this.getLength,
set: _this.setLength
},
concat: {
value: _this.concat,
writable: true
},
pop: {
value: _this.pop,
writable: true
},
push: {
value: _this.push,
writable: true
},
reverse: {
value: _this.reverse,
writable: true
},
shift: {
value: _this.shift,
writable: true
},
slice: {
value: _this.slice,
writable: true
},
splice: {
value: _this.splice,
writable: true
},
sort: {
value: _this.sort,
writable: true
},
sortOn: {
value: _this.sortOn,
writable: true
},
toString: {
value: _this._toString,
writable: true
},
unshift: {
value: _this.unshift,
writable: true
},
});
return _this;
}
AVM1ArrayPrototype.prototype._toString = function () {
var len = this.alGet('length');
var _i = 0;
var outputStr = '';
var tmpitem;
for (_i = 0; _i < len; _i++) {
tmpitem = this.alGet(_i);
if (typeof tmpitem !== 'undefined') {
outputStr += alToString(this.context, tmpitem) + ((_i == len - 1) ? '' : ',');
}
else {
outputStr += ((_i == len - 1) ? '' : ',');
}
}
return outputStr;
};
AVM1ArrayPrototype.prototype.getLength = function () {
var arr = alEnsureType(this, AVM1ArrayNative).value;
return arr.length;
};
AVM1ArrayPrototype.prototype.setLength = function (length) {
if (length === null) {
length = 0;
}
if (!isIndex(length)) {
return; // no action on invalid length
}
length = alToInt32(this.context, length) >>> 0;
var arr = alEnsureType(this, AVM1ArrayNative).value;
arr.length = length;
};
AVM1ArrayPrototype.prototype.concat = function () {
var items = [];
for (var _a = 0; _a < arguments.length; _a++) {
items[_a] = arguments[_a];
}
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
for (var i_1 = 0; i_1 < items.length; i_1++) {
if (items[i_1] instanceof AVM1ArrayNative) {
items[i_1] = alEnsureType(items[i_1], AVM1ArrayNative).value;
}
}
//this.value=arr.concat(items);
return new AVM1ArrayNative(this.context, Array.prototype.concat.apply(arr, items));
//return this;
}
// Generic behavior
var a = [];
var e = this;
var isArrayObject = alIsArrayLike(this.context, this);
var i = 0;
while (true) {
if (isArrayObject) {
alIterateArray(this.context, e, function (value) { return a.push(value); });
}
else {
a.push(alToString(this.context, e));
}
if (i >= items.length) {
break;
}
e = items[i++];
isArrayObject = alIsArray(this.context, e); // not-logical behavior
}
return new AVM1ArrayNative(this.context, a);
};
AVM1ArrayPrototype.prototype.join = function (separator) {
separator = separator === undefined ? ',' : alCoerceString(this.context, separator);
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
if (arr.length === 0) {
return '';
}
if (arr.every(function (i) { return !(i instanceof AVM1Object); })) {
return arr.join(separator);
}
}
var context = this.context;
var length = alToInt32(context, this.alGet('length')) >>> 0;
if (length === 0) {
return '';
}
var result = [];
for (var i = 0; i < length; i++) {
var item = this.alGet(i);
result[i] = item === null || item === undefined ? '' : alCoerceString(context, item);
}
return result.join(separator);
};
AVM1ArrayPrototype.prototype.pop = function () {
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return arr.pop();
}
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
if (length === 0) {
return undefined;
}
var i = length - 1;
var result = this.alGet(i);
this.alDeleteProperty(i);
this.alPut('length', i);
return result;
};
AVM1ArrayPrototype.prototype.push = function () {
var items = [];
for (var _a = 0; _a < arguments.length; _a++) {
items[_a] = arguments[_a];
}
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return Array.prototype.push.apply(arr, items);
}
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
for (var i = 0; i < items.length; i++) {
this.alPut(length, items[i]);
length++; // TODO check overflow
}
this.alPut('length', length);
return length;
};
AVM1ArrayPrototype.prototype.reverse = function () {
var items = [];
var len = this.alGet('length');
var _i = 0;
for (_i = 0; _i < len; _i++) {
items[_i] = this.alGet(_i);
}
_i = len - 1;
while (_i >= 0) {
this.alPut((len - 1 - _i), items[_i]);
_i--;
}
return this.value;
};
AVM1ArrayPrototype.prototype.shift = function () {
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return arr.shift();
}
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
if (length === 0) {
return undefined;
}
var result = this.alGet(0);
for (var i = 1; i < length; i++) {
if (this.alHasProperty(i)) {
this.alPut(i - 1, this.alGet(i));
}
else {
this.alDeleteProperty(i - 1);
}
}
this.alDeleteProperty(length - 1);
this.alPut('length', length - 1);
return result;
};
AVM1ArrayPrototype.prototype.slice = function (start, end) {
start = alToInteger(this.context, start);
end = end !== undefined ? alToInteger(this.context, end) : undefined;
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return new AVM1ArrayNative(this.context, arr.slice(start, end));
}
var a = [];
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
start = start < 0 ? Math.max(length + start, 0) : Math.min(length, start);
end = end === undefined ? length :
(end < 0 ? Math.max(length + end, 0) : Math.min(length, end));
for (var i = start, j = 0; i < end; i++, j++) {
if (this.alHasProperty(i)) {
a[j] = this.alGet(i);
}
}
return new AVM1ArrayNative(this.context, a);
};
AVM1ArrayPrototype.prototype.splice = function (start, deleteCount) {
var items = [];
for (var _a = 2; _a < arguments.length; _a++) {
items[_a - 2] = arguments[_a];
}
start = alToInteger(this.context, start);
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
start = start < 0 ? Math.max(length + start, 0) : Math.min(length, start);
//if(deleteCount || typeof deleteCount==="number")
// deleteCount = alToInteger(this.context, deleteCount);
if (deleteCount || typeof deleteCount === 'number')
deleteCount = alToInteger(this.context, deleteCount);
else
deleteCount = length - start;
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return new AVM1ArrayNative(this.context, Array.prototype.splice.apply(arr, [start, deleteCount].concat(items)));
}
var a = [];
for (var i = 0; i < deleteCount; i++) {
if (this.alHasProperty(start + i)) {
a[i] = this.alGet(start + i);
}
}
var delta = items.length - deleteCount;
if (delta < 0) {
for (var i = start - delta; i < length; i++) {
if (this.alHasProperty(i)) {
this.alPut(i + delta, this.alGet(i));
}
else {
this.alDeleteProperty(i + delta);
}
}
for (var i = delta; i < 0; i++) {
this.alDeleteProperty(length + i);
}
}
else if (delta > 0) {
// TODO check overflow
for (var i = length - 1; i >= start + delta; i--) {
if (this.alHasProperty(i)) {
this.alPut(i + delta, this.alGet(i));
}
else {
this.alDeleteProperty(i + delta);
}
}
}
for (var i = 0; i < items.length; i++) {
this.alPut(start + i, items[i]);
}
this.alPut('length', length + delta);
return new AVM1ArrayNative(this.context, a);
};
AVM1ArrayPrototype.prototype.sort = function (comparefn) {
return sortArray(this, comparefn);
};
AVM1ArrayPrototype.prototype.sortOn = function (fieldNames, options) {
var context = this.context;
// The field names and options we'll end up using.
var fieldNamesList = [];
var optionsList = [];
if (alIsString(context, fieldNames)) {
fieldNamesList = [alToString(context, fieldNames)];
optionsList = [alToInt32(context, options)];
}
else if (alIsArray(context, fieldNames)) {
fieldNamesList = [];
optionsList = [];
var optionsArray = alIsArray(context, options) ? options : null;
var length_1 = alToInteger(context, fieldNames.alGet('length'));
if (optionsArray) {
// checking in length of fieldNames == options
var optionsLength = alToInteger(context, optionsArray.alGet('length'));
if (length_1 !== optionsLength) {
optionsArray = null;
}
}
for (var i = 0; i < length_1; i++) {
fieldNamesList.push(alToString(context, fieldNames.alGet(i)));
optionsList.push(optionsArray ? alToInt32(context, optionsArray.alGet(i)) : 0);
}
}
else {
// Field parameters are incorrect.
return sortArray(this, options);
}
// TODO revisit this code
var optionsVal = optionsList[0];
release || Debug.assertNotImplemented(!(optionsVal & AVM1ArraySortOnOptions.UNIQUESORT), 'UNIQUESORT');
release || Debug.assertNotImplemented(!(optionsVal & AVM1ArraySortOnOptions.RETURNINDEXEDARRAY), 'RETURNINDEXEDARRAY');
var comparer = function (a, b) {
while (a instanceof AVM1ArrayNative) {
a = alEnsureType(a, AVM1ArrayNative).value;
if (a && a.length > 0)
a = a[0];
}
while (b instanceof AVM1ArrayNative) {
b = alEnsureType(b, AVM1ArrayNative).value;
if (b && b.length > 0)
b = b[0];
}
var aObj = alToObject(context, a);
var bObj = alToObject(context, b);
for (var i = 0; i < fieldNamesList.length; i++) {
var aField = aObj.alGet(fieldNamesList[i]);
var bField = bObj.alGet(fieldNamesList[i]);
var result = void 0;
if (optionsList[i] & AVM1ArraySortOnOptions.NUMERIC) {
var aNum = alToNumber(context, aField);
var bNum = alToNumber(context, bField);
result = aNum < bNum ? -1 : aNum > bNum ? +1 : 0;
}
else {
var aStr = alToString(context, aField);
var bStr = alToString(context, bField);
if (optionsList[i] & AVM1ArraySortOnOptions.CASEINSENSITIVE) {
aStr = aStr.toLowerCase();
bStr = bStr.toLowerCase();
}
result = aStr < bStr ? -1 : aStr > bStr ? +1 : 0;
}
if (result !== 0) {
return !(optionsList[i] & AVM1ArraySortOnOptions.DESCENDING) ? result : -result;
}
}
return 0;
};
var arr = alEnsureType(this, AVM1ArrayNative).value;
arr.sort(comparer);
// Strange, the documentation said to do not return anything.
return this;
};
AVM1ArrayPrototype.prototype.unshift = function () {
var items = [];
for (var _a = 0; _a < arguments.length; _a++) {
items[_a] = arguments[_a];
}
if (this instanceof AVM1ArrayNative) {
// Faster case for native array implementation
var arr = alEnsureType(this, AVM1ArrayNative).value;
return Array.prototype.unshift.apply(arr, items);
}
var length = alToInt32(this.context, this.alGet('length')) >>> 0;
var insertCount = items.length;
// TODO check overflow
for (var i = length - 1; i >= 0; i--) {
if (this.alHasProperty(i)) {
this.alPut(i + insertCount, this.alGet(i));
}
else {
this.alDeleteProperty(i + insertCount);
}
}
for (var i = 0; i < items.length; i++) {
this.alPut(i, items[i]);
}
length += insertCount;
this.alPut('length', length); // ActionScript does not do that?
return length;
};
return AVM1ArrayPrototype;
}(AVM1Object));
export { AVM1ArrayPrototype };
var AVM1ArrayFunction = /** @class */ (function (_super) {
__extends(AVM1ArrayFunction, _super);
function AVM1ArrayFunction(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Function.alGetPrototypeProperty();
var proto = new AVM1ArrayPrototype(context);
alDefineObjectProperties(_this, {
prototype: {
value: proto
}
});
alDefineObjectProperties(_this, {
NUMERIC: {
value: AVM1ArraySortOnOptions.NUMERIC
}
});
alDefineObjectProperties(_this, {
DESCENDING: {
value: AVM1ArraySortOnOptions.DESCENDING
}
});
return _this;
}
AVM1ArrayFunction.prototype.alConstruct = function (args) {
if (!args) {
return new AVM1ArrayNative(this.context, []);
}
if (args.length === 1 && typeof args[0] === 'number') {
var len = args[0];
if (len >>> 0 !== len) {
throw new Error('Range error'); // TODO avm1 native
}
return new AVM1ArrayNative(this.context, new Array(len));
}
return new AVM1ArrayNative(this.context, args);
};
AVM1ArrayFunction.prototype.alCall = function (thisArg, args) {
return this.alConstruct.apply(this, args);
};
return AVM1ArrayFunction;
}(AVM1Function));
export { AVM1ArrayFunction };
// Math natives
var AVM1MathObject = /** @class */ (function (_super) {
__extends(AVM1MathObject, _super);
function AVM1MathObject(context) {
var _this = _super.call(this, context) || this;
_this.alPrototype = context.builtins.Object.alGetPrototypeProperty();
alDefineObjectProperties(_this, {
E: Math.E,
LN10: Math.LN10,
LN2: Math.LN2,
LOG10E: Math.LOG10E,
LOG2E: Math.LOG2E,
PI: Math.PI,
SQRT1_2: Math.SQRT1_2,
SQRT2: Math.SQRT2,
abs: _this.abs,
acos: _this.acos,
asin: _this.asin,
atan: _this.atan,
atan2: _this.atan2,
ceil: _this.ceil,
cos: _this.cos,
exp: _this.exp,
floor: _this.floor,
log: _this.log,
max: _this.max,
min: _this.min,
pow: _this.pow,
random: _this.random,
round: _this.round,
sin: _this.sin,
sqrt: _this.sqrt,
tan: _this.tan
});
return _this;
}
AVM1MathObject.prototype.abs = function (x) {
return Math.abs(alToNumber(this.context, x));
};
AVM1MathObject.prototype.acos = function (x) {
return Math.acos(alToNumber(this.context, x));
};
AVM1MathObject.prototype.asin = function (x) {
return Math.asin(alToNumber(this.context, x));
};
AVM1MathObject.prototype.atan = function (x) {
return Math.atan(alToNumber(this.context, x));
};
AVM1MathObject.prototype.atan2 = function (y, x) {
return Math.atan2(alToNumber(this.context, y), alToNumber(this.context, x));
};
AVM1MathObject.prototype.ceil = function (x) {
return Math.ceil(alToNumber(this.context, x));
};
AVM1MathObject.prototype.cos = function (x) {
return Math.cos(alToNumber(this.context, x));
};
AVM1MathObject.prototype.exp = function (x) {
return Math.exp(alToNumber(this.context, x));
};
AVM1MathObject.prototype.floor = function (x) {
return Math.floor(alToNumber(this.context, x));
};
AVM1MathObject.prototype.log = function (x) {
return Math.log(alToNumber(this.context, x));
};
AVM1MathObject.prototype.max = function () {
var _this = this;
var values = [];
for (var _a = 0; _a < arguments.length; _a++) {
values[_a] = arguments[_a];
}
values = values.map(function (x) { return alToNumber(_this.context, x); });
return Math.max.apply(null, values);
};
AVM1MathObject.prototype.min = function () {
var _this = this;
var values = [];
for (var _a = 0; _a < arguments.length; _a++) {
values[_a] = arguments[_a];
}
values = values.map(function (x) { return alToNumber(_this.context, x); });
return Math.min.apply(null, values);
};
AVM1MathObject.prototype.pow = function (x, y) {
return Math.pow(alToNumber(this.context, x), alToNumber(this.context, y));
};
AVM1MathObject.prototype.random = function () {
if (AVM1Globals.randomProvider) {
return AVM1Globals.randomProvider.random();
}
return Math.random();
};
AVM1MathObject.prototype.round = function (x) {
return Math.round(alToNumber(this.context, x));
};
AVM1MathObject.prototype.sin = function (x) {
return Math.sin(alToNumber(this.context, x));
};
AVM1MathObject.prototype.sqrt = function (x) {
return Math.sqrt(alToNumber(this.context, x));
};
AVM1MathObject.prototype.tan = function (x) {
return Math.tan(alToNumber(this.context, x));
};
return AVM1MathObject;
}(AVM1Object));
// Date natives
var AVM1DateNative = /** @class */ (function (_su