prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
792 lines (639 loc) • 28.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ToImplementation = undefined;
var _get = require("./get.js");
var _singletons = require("../singletons.js");
var _has = require("./has.js");
var _call = require("./call.js");
var _errors = require("../errors.js");
var _is = require("./is.js");
var _abstract = require("./abstract.js");
var _index = require("../values/index.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function modulo(x, y) {
return x < 0 ? x % y + y : x % y;
} /**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
class ToImplementation {
constructor() {
this.ElementConv = {
Int8: this.ToInt8.bind(this),
Int16: this.ToInt16.bind(this),
Int32: this.ToInt32.bind(this),
Uint8: this.ToUint8.bind(this),
Uint16: this.ToUint16.bind(this),
Uint32: this.ToUint32.bind(this),
Uint8Clamped: this.ToUint8Clamp.bind(this)
};
}
// ECMA262 7.1.5
ToInt32(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int16bit be int modulo 2^32.
let int32bit = modulo(int, Math.pow(2, 32));
// 5. If int32bit ≥ 2^31, return int32bit - 2^32; otherwise return int32bit.
return int32bit >= Math.pow(2, 31) ? int32bit - Math.pow(2, 32) : int32bit;
}
// ECMA262 7.1.6
ToUint32(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int16bit be int modulo 2^32.
let int32bit = modulo(int, Math.pow(2, 32));
// 5. Return int32bit.
return int32bit;
}
// ECMA262 7.1.7
ToInt16(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int16bit be int modulo 2^16.
let int16bit = modulo(int, Math.pow(2, 16));
// 5. If int16bit ≥ 2^15, return int16bit - 2^16; otherwise return int16bit.
return int16bit >= Math.pow(2, 15) ? int16bit - Math.pow(2, 16) : int16bit;
}
// ECMA262 7.1.8
ToUint16(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int16bit be int modulo 2^16.
let int16bit = modulo(int, Math.pow(2, 16));
// 5. Return int16bit.
return int16bit;
}
// ECMA262 7.1.9
ToInt8(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int8bit be int modulo 2^8.
let int8bit = modulo(int, Math.pow(2, 8));
// 5. If int8bit ≥ 2^7, return int8bit - 2^8; otherwise return int8bit.
return int8bit >= Math.pow(2, 7) ? int8bit - Math.pow(2, 8) : int8bit;
}
// ECMA262 7.1.10
ToUint8(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, +0, -0, +∞, or -∞, return +0.
if (isNaN(number) || number === 0 || !isFinite(number)) return +0;
// 3. Let int be the mathematical value that is the same sign as number and whose magnitude is floor(abs(number)).
let int = number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
// 4. Let int8bit be int modulo 2^8.
let int8bit = modulo(int, Math.pow(2, 8));
// 5. Return int8bit.
return int8bit;
}
// ECMA262 7.1.11
ToUint8Clamp(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, return +0.
if (isNaN(number)) return +0;
// 3. If number ≤ 0, return +0.
if (number <= 0) return +0;
// 4. If number ≥ 255, return 255.
if (number >= 255) return 255;
// 5. Let f be floor(number).
let f = Math.floor(number);
// 6. If f + 0.5 < number, return f + 1.
if (f + 0.5 < number) return f + 1;
// 7. If number < f + 0.5, return f.
if (number < f + 0.5) return f;
// 8. If f is odd, return f + 1.
if (f % 2 === 1) return f + 1;
// 9. Return f.
return f;
}
// ECMA262 19.3.3.1
thisBooleanValue(realm, value) {
// 1. If Type(value) is Boolean, return value.
if (value instanceof _index.BooleanValue) return value;
// 2. If Type(value) is Object and value has a [[BooleanData]] internal slot, then
if (value instanceof _index.ObjectValue && value.$BooleanData) {
const booleanData = value.$BooleanData.throwIfNotConcreteBoolean();
// a. Assert: value's [[BooleanData]] internal slot is a Boolean value.
(0, _invariant2.default)(booleanData instanceof _index.BooleanValue, "expected boolean data internal slot to be a boolean value");
// b. Return the value of value's [[BooleanData]] internal slot.
return booleanData;
}
value.throwIfNotConcrete();
// 3. Throw a TypeError exception.
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// ECMA262 20.1.3
thisNumberValue(realm, value) {
// 1. If Type(value) is Number, return value.
if (value instanceof _index.NumberValue) return value;
// 2. If Type(value) is Object and value has a [[NumberData]] internal slot, then
if (value instanceof _index.ObjectValue && value.$NumberData) {
const numberData = value.$NumberData.throwIfNotConcreteNumber();
// a. Assert: value's [[NumberData]] internal slot is a Number value.
(0, _invariant2.default)(numberData instanceof _index.NumberValue, "expected number data internal slot to be a number value");
// b. Return the value of value's [[NumberData]] internal slot.
return numberData;
}
value = value.throwIfNotConcrete();
// 3. Throw a TypeError exception.
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// ECMA262 21.1.3
thisStringValue(realm, value) {
// 1. If Type(value) is String, return value.
if (value instanceof _index.StringValue) return value;
// 2. If Type(value) is Object and value has a [[StringData]] internal slot, then
if (value instanceof _index.ObjectValue && value.$StringData) {
const stringData = value.$StringData.throwIfNotConcreteString();
// a. Assert: value's [[StringData]] internal slot is a String value.
(0, _invariant2.default)(stringData instanceof _index.StringValue, "expected string data internal slot to be a string value");
// b. Return the value of value's [[StringData]] internal slot.
return stringData;
}
value = value.throwIfNotConcrete();
// 3. Throw a TypeError exception.
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// ECMA262 6.2.4.5
ToPropertyDescriptor(realm, Obj) {
Obj = Obj.throwIfNotConcrete();
// 1. If Type(Obj) is not Object, throw a TypeError exception.
if (!(Obj instanceof _index.ObjectValue)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// 2. Let desc be a new Property Descriptor that initially has no fields.
let desc = {};
// 3. Let hasEnumerable be ? HasProperty(Obj, "enumerable").
let hasEnumerable = (0, _has.HasProperty)(realm, Obj, "enumerable");
// 4. If hasEnumerable is true, then
if (hasEnumerable === true) {
// a. Let enum be ToBoolean(? Get(Obj, "enumerable")).
let enu = this.ToBooleanPartial(realm, (0, _get.Get)(realm, Obj, "enumerable"));
// b. Set the [[Enumerable]] field of desc to enum.
desc.enumerable = enu === true;
}
// 5. Let hasConfigurable be ? HasProperty(Obj, "configurable").
let hasConfigurable = (0, _has.HasProperty)(realm, Obj, "configurable");
// 6. If hasConfigurable is true, then
if (hasConfigurable === true) {
// a. Let conf be ToBoolean(? Get(Obj, "configurable")).
let conf = this.ToBooleanPartial(realm, (0, _get.Get)(realm, Obj, "configurable"));
// b. Set the [[Configurable]] field of desc to conf.
desc.configurable = conf === true;
}
// 7. Let hasValue be ? HasProperty(Obj, "value").
let hasValue = (0, _has.HasProperty)(realm, Obj, "value");
// 8. If hasValue is true, then
if (hasValue === true) {
// a. Let value be ? Get(Obj, "value").
let value = (0, _get.Get)(realm, Obj, "value");
// b. Set the [[Value]] field of desc to value.
desc.value = value;
}
// 9. Let hasWritable be ? HasProperty(Obj, "writable").
let hasWritable = (0, _has.HasProperty)(realm, Obj, "writable");
// 10. If hasWritable is true, then
if (hasWritable === true) {
// a. Let writable be ToBoolean(? Get(Obj, "writable")).
let writable = this.ToBooleanPartial(realm, (0, _get.Get)(realm, Obj, "writable"));
// b. Set the [[Writable]] field of desc to writable.
desc.writable = writable === true;
}
// 11. Let hasGet be ? HasProperty(Obj, "get").
let hasGet = (0, _has.HasProperty)(realm, Obj, "get");
// 12. If hasGet is true, then
if (hasGet === true) {
// a. Let getter be ? Get(Obj, "get").
let getter = (0, _get.Get)(realm, Obj, "get");
// b. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception.
if ((0, _is.IsCallable)(realm, getter) === false && !getter.mightBeUndefined()) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
getter.throwIfNotConcrete();
// c. Set the [[Get]] field of desc to getter.
desc.get = getter;
}
// 13. Let hasSet be ? HasProperty(Obj, "set").
let hasSet = (0, _has.HasProperty)(realm, Obj, "set");
// 14. If hasSet is true, then
if (hasSet === true) {
// a. Let setter be ? Get(Obj, "set").
let setter = (0, _get.Get)(realm, Obj, "set");
// b. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception.
if ((0, _is.IsCallable)(realm, setter) === false && !setter.mightBeUndefined()) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
setter.throwIfNotConcrete();
// c. Set the [[Set]] field of desc to setter.
desc.set = setter;
}
// 15. If either desc.[[Get]] or desc.[[Set]] is present, then
if (desc.get || desc.set) {
// a. If either desc.[[Value]] or desc.[[Writable]] is present, throw a TypeError exception.
if ("value" in desc || "writable" in desc) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
}
// 16. Return desc.
return desc;
}
// ECMA262 7.1.13
ToObject(realm, arg) {
if (arg instanceof _index.UndefinedValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (arg instanceof _index.NullValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (arg instanceof _index.BooleanValue) {
let obj = new _index.ObjectValue(realm, realm.intrinsics.BooleanPrototype);
obj.$BooleanData = arg;
return obj;
} else if (arg instanceof _index.NumberValue) {
let obj = new _index.ObjectValue(realm, realm.intrinsics.NumberPrototype);
obj.$NumberData = arg;
return obj;
} else if (arg instanceof _index.StringValue) {
let obj = _singletons.Create.StringCreate(realm, arg, realm.intrinsics.StringPrototype);
return obj;
} else if (arg instanceof _index.SymbolValue) {
let obj = new _index.ObjectValue(realm, realm.intrinsics.SymbolPrototype);
obj.$SymbolData = arg;
return obj;
} else if (arg instanceof _index.ObjectValue) {
return arg;
}
(0, _invariant2.default)(false);
}
_WrapAbstractInObject(realm, arg) {
let obj;
switch (arg.types.getType()) {
case _index.IntegralValue:
case _index.NumberValue:
obj = new _index.ObjectValue(realm, realm.intrinsics.NumberPrototype);
obj.$NumberData = arg;
break;
case _index.StringValue:
obj = new _index.ObjectValue(realm, realm.intrinsics.StringPrototype);
obj.$StringData = arg;
break;
case _index.BooleanValue:
obj = new _index.ObjectValue(realm, realm.intrinsics.BooleanPrototype);
obj.$BooleanData = arg;
break;
case _index.SymbolValue:
obj = new _index.ObjectValue(realm, realm.intrinsics.SymbolPrototype);
obj.$SymbolData = arg;
break;
case _index.UndefinedValue:
case _index.NullValue:
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
default:
if (realm.isInPureScope()) {
// Create a placeholder value to represent the ObjectValue that we would've
// received, but this object should never leak so as an optimization we will
// let operations on top of this object force the ToObject operations instead.
obj = _index.AbstractValue.createFromType(realm, _index.ObjectValue, "implicit conversion to object");
(0, _invariant2.default)(obj instanceof _index.AbstractObjectValue);
obj.args = [arg];
} else {
obj = arg.throwIfNotConcreteObject();
}
break;
}
return obj;
}
ToObjectPartial(realm, arg) {
if (arg instanceof _index.AbstractObjectValue) return arg;
if (arg instanceof _index.AbstractValue) {
return this._WrapAbstractInObject(realm, arg);
}
arg = arg.throwIfNotConcrete();
return this.ToObject(realm, arg);
}
// ECMA262 7.1.15
ToLength(realm, argument) {
// Let len be ? ToInteger(argument).
let len = this.ToInteger(realm, argument);
// If len ≤ +0, return +0.
if (len <= 0) return +0;
// If len is +∞, return 2^53-1.
if (len === +Infinity) return Math.pow(2, 53) - 1;
// Return min(len, 2^53-1).
return Math.min(len, Math.pow(2, 53) - 1);
}
// ECMA262 7.1.4
ToInteger(realm, argument) {
// 1. Let number be ? ToNumber(argument).
let number = this.ToNumber(realm, argument);
// 2. If number is NaN, return +0.
if (isNaN(number)) return +0;
// 3. If number is +0, -0, +∞, or -∞, return number.
if (!isFinite(number) || number === 0) return number;
// 4. Return the number value that is the same sign as number and whose magnitude is floor(abs(number)).
return number < 0 ? -Math.floor(Math.abs(number)) : Math.floor(Math.abs(number));
}
// ECMA262 7.1.17
ToIndex(realm, value) {
let index;
// 1. If value is undefined, then
if (value instanceof _index.UndefinedValue) {
// a. Let index be 0.
index = 0;
} else {
// 2. Else,
// a. Let integerIndex be ? ToInteger(value).
let integerIndex = this.ToInteger(realm, value);
// b. If integerIndex < 0, throw a RangeError exception.
if (integerIndex < 0) {
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError, "integerIndex < 0");
}
// c. Let index be ! ToLength(integerIndex).
index = this.ToLength(realm, integerIndex);
// d. If SameValueZero(integerIndex, index) is false, throw a RangeError exception.
if ((0, _abstract.SameValueZero)(realm, new _index.NumberValue(realm, integerIndex), new _index.NumberValue(realm, index)) === false) {
throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError, "integerIndex < 0");
}
}
// 3. Return index.
return index;
}
ToIndexPartial(realm, value) {
return this.ToIndex(realm, typeof value === "number" ? value : value.throwIfNotConcrete());
}
ToNumber(realm, val) {
const num = this.ToNumberOrAbstract(realm, val);
if (typeof num !== "number") {
_index.AbstractValue.reportIntrospectionError(num);
throw new _errors.FatalError();
}
return num;
}
// ECMA262 7.1.3
ToNumberOrAbstract(realm, val) {
if (typeof val === "number") {
return val;
} else if (val instanceof _index.AbstractValue) {
return val;
} else if (val instanceof _index.UndefinedValue) {
return NaN;
} else if (val instanceof _index.NullValue) {
return +0;
} else if (val instanceof _index.ObjectValue) {
let prim = this.ToPrimitiveOrAbstract(realm, val, "number");
return this.ToNumberOrAbstract(realm, prim);
} else if (val instanceof _index.BooleanValue) {
if (val.value === true) {
return 1;
} else {
// `val.value === false`
return 0;
}
} else if (val instanceof _index.NumberValue) {
return val.value;
} else if (val instanceof _index.StringValue) {
return Number(val.value);
} else if (val instanceof _index.SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else {
(0, _invariant2.default)(false, "unexpected type of value");
}
}
IsToNumberPure(realm, val) {
if (val instanceof _index.Value) {
if (this.IsToPrimitivePure(realm, val)) {
let type = val.getType();
return type !== _index.SymbolValue && type !== _index.PrimitiveValue && type !== _index.Value;
}
return false;
}
return true;
}
// ECMA262 7.1.1
ToPrimitive(realm, input, hint) {
return this.ToPrimitiveOrAbstract(realm, input, hint).throwIfNotConcretePrimitive();
}
ToPrimitiveOrAbstract(realm, input, hint) {
if (input instanceof _index.PrimitiveValue) {
return input;
}
// When Type(input) is Object, the following steps are taken
(0, _invariant2.default)(input instanceof _index.ObjectValue, "expected an object");
// 1. If PreferredType was not passed, let hint be "default".
hint = hint || "default";
// Following two steps are redundant since we just pass string hints.
// 2. Else if PreferredType is hint String, let hint be "string".
// 3. Else PreferredType is hint Number, let hint be "number".
// 4. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
let exoticToPrim = (0, _get.GetMethod)(realm, input, realm.intrinsics.SymbolToPrimitive);
// 5. If exoticToPrim is not undefined, then
if (!(exoticToPrim instanceof _index.UndefinedValue)) {
// a. Let result be ? Call(exoticToPrim, input, « hint »).
let result = (0, _call.Call)(realm, exoticToPrim, input, [new _index.StringValue(realm, hint)]);
// b. If Type(result) is not Object, return result.
if (!(result instanceof _index.ObjectValue)) {
(0, _invariant2.default)(result instanceof _index.PrimitiveValue);
return result;
}
// c. Throw a TypeError exception.
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
// 6. If hint is "default", let hint be "number".
if (hint === "default") hint = "number";
// 7. Return ? OrdinaryToPrimitive(input, hint).
return this.OrdinaryToPrimitiveOrAbstract(realm, input, hint);
}
// Returns result type of ToPrimitive if it is pure (terminates, does not throw exception, does not read or write heap), otherwise undefined.
GetToPrimitivePureResultType(realm, input) {
let type = input.getType();
if (input instanceof _index.PrimitiveValue) return type;
if (input instanceof _index.AbstractValue && !input.mightBeObject()) return _index.PrimitiveValue;
return undefined;
}
IsToPrimitivePure(realm, input) {
return this.GetToPrimitivePureResultType(realm, input) !== undefined;
}
// ECMA262 7.1.1
OrdinaryToPrimitive(realm, input, hint) {
return this.OrdinaryToPrimitiveOrAbstract(realm, input, hint).throwIfNotConcretePrimitive();
}
OrdinaryToPrimitiveOrAbstract(realm, input, hint) {
let methodNames;
// 1. Assert: Type(O) is Object.
(0, _invariant2.default)(input instanceof _index.ObjectValue, "Expected object");
// 2. Assert: Type(hint) is String and its value is either "string" or "number".
(0, _invariant2.default)(hint === "string" || hint === "number", "Expected string or number hint");
// 3. If hint is "string", then
if (hint === "string") {
// a. Let methodNames be « "toString", "valueOf" ».
methodNames = ["toString", "valueOf"];
} else {
// 4. Else,
// a. Let methodNames be « "valueOf", "toString" ».
methodNames = ["valueOf", "toString"];
}
// 5. For each name in methodNames in List order, do
for (let name of methodNames) {
// a. Let method be ? Get(O, name).
let method = (0, _get.Get)(realm, input, new _index.StringValue(realm, name));
// b. If IsCallable(method) is true, then
if ((0, _is.IsCallable)(realm, method)) {
// i. Let result be ? Call(method, O).
let result = (0, _call.Call)(realm, method, input);
let resultType = result.getType();
// ii. If Type(result) is not Object, return result.
if (resultType === _index.Value) {
(0, _invariant2.default)(result instanceof _index.AbstractValue);
let error = new _errors.CompilerDiagnostic(`${name} might return either an object or primitive`, realm.currentLocation, "PP0028", "RecoverableError");
realm.handleError(error);
throw new _errors.FatalError();
}
if (_index.Value.isTypeCompatibleWith(resultType, _index.PrimitiveValue)) {
(0, _invariant2.default)(result instanceof _index.AbstractValue || result instanceof _index.PrimitiveValue);
return result;
}
}
}
// 6. Throw a TypeError exception.
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "can't turn to primitive");
}
// ECMA262 7.1.12
ToString(realm, val) {
if (typeof val === "string") {
return val;
} else if (val instanceof _index.StringValue) {
return val.value;
} else if (val instanceof _index.NumberValue) {
return val.value + "";
} else if (val instanceof _index.UndefinedValue) {
return "undefined";
} else if (val instanceof _index.NullValue) {
return "null";
} else if (val instanceof _index.SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (val instanceof _index.BooleanValue) {
return val.value ? "true" : "false";
} else if (val instanceof _index.ObjectValue) {
let primValue = this.ToPrimitive(realm, val, "string");
return this.ToString(realm, primValue);
} else {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "unknown value type, can't coerce to string");
}
}
ToStringPartial(realm, val) {
return this.ToString(realm, typeof val === "string" ? val : val.throwIfNotConcrete());
}
ToStringValue(realm, val) {
if (val.getType() === _index.StringValue) return val;
let str;
if (typeof val === "string") {
str = val;
} else if (val instanceof _index.NumberValue) {
str = val.value + "";
} else if (val instanceof _index.UndefinedValue) {
str = "undefined";
} else if (val instanceof _index.NullValue) {
str = "null";
} else if (val instanceof _index.SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (val instanceof _index.BooleanValue) {
str = val.value ? "true" : "false";
} else if (val instanceof _index.ObjectValue) {
let primValue = this.ToPrimitiveOrAbstract(realm, val, "string");
if (primValue.getType() === _index.StringValue) return primValue;
str = this.ToStringPartial(realm, primValue);
} else {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "unknown value type, can't coerce to string");
}
return new _index.StringValue(realm, str);
}
// ECMA262 7.1.2
ToBoolean(realm, val) {
if (val instanceof _index.BooleanValue) {
return val.value;
} else if (val instanceof _index.UndefinedValue) {
return false;
} else if (val instanceof _index.NullValue) {
return false;
} else if (val instanceof _index.NumberValue) {
return val.value !== 0 && !isNaN(val.value);
} else if (val instanceof _index.StringValue) {
return val.value.length > 0;
} else if (val instanceof _index.ObjectValue) {
return true;
} else if (val instanceof _index.SymbolValue) {
return true;
} else {
(0, _invariant2.default)(!(val instanceof _index.AbstractValue));
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "unknown value type, can't coerce to a boolean");
}
}
ToBooleanPartial(realm, val) {
if (!val.mightNotBeObject()) return true;
return this.ToBoolean(realm, val.throwIfNotConcrete());
}
// ECMA262 7.1.14
ToPropertyKey(realm, arg) /* but not StringValue */{
// 1. Let key be ? ToPrimitive(argument, hint String).
let key = this.ToPrimitive(realm, arg, "string");
// 2. If Type(key) is Symbol, then
if (key instanceof _index.SymbolValue) {
// a. Return key.
return key;
}
// 3. Return ! ToString(key).
return this.ToString(realm, key);
}
ToPropertyKeyPartial(realm, arg) /* but not StringValue */{
if (arg instanceof _index.ConcreteValue) return this.ToPropertyKey(realm, arg);
// if we are in pure scope, we can assume that ToPropertyKey
// won't cause side-effects even if it's not simple
if (arg.mightNotBeString() && arg.mightNotBeNumber() && !arg.isSimpleObject() && !realm.isInPureScope()) {
arg.throwIfNotConcrete();
}
(0, _invariant2.default)(arg instanceof _index.AbstractValue);
return arg;
}
// ECMA262 7.1.16
CanonicalNumericIndexString(realm, argument) {
// 1. Assert: Type(argument) is String.
(0, _invariant2.default)(argument instanceof _index.StringValue);
// 2. If argument is "-0", return −0.
if (argument.value === "-0") return -0;
// 3. Let n be ToNumber(argument).
let n = this.ToNumber(realm, argument);
// 4. If SameValue(ToString(n), argument) is false, return undefined.
if ((0, _abstract.SameValue)(realm, new _index.StringValue(realm, this.ToString(realm, new _index.NumberValue(realm, n))), argument) === false) return undefined;
// 5. Return n.
return n;
}
}
exports.ToImplementation = ToImplementation;
//# sourceMappingURL=to.js.map