prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
763 lines (539 loc) • 29.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ToImplementation = void 0;
var _index = require("../domains/index.js");
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 _index2 = require("../values/index.js");
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _generator = require("../utils/generator.js");
var _descriptors = require("../descriptors.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 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.
*/
function modulo(x, y) {
return x < 0 ? x % y + y : x % y;
}
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 _index2.BooleanValue) return value; // 2. If Type(value) is Object and value has a [[BooleanData]] internal slot, then
if (value instanceof _index2.ObjectValue && value.$BooleanData) {
const booleanData = value.$BooleanData.throwIfNotConcreteBoolean(); // a. Assert: value's [[BooleanData]] internal slot is a Boolean value.
(0, _invariant.default)(booleanData instanceof _index2.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 _index2.NumberValue) return value; // 2. If Type(value) is Object and value has a [[NumberData]] internal slot, then
if (value instanceof _index2.ObjectValue && value.$NumberData) {
const numberData = value.$NumberData.throwIfNotConcreteNumber(); // a. Assert: value's [[NumberData]] internal slot is a Number value.
(0, _invariant.default)(numberData instanceof _index2.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 _index2.StringValue) return value; // 2. If Type(value) is Object and value has a [[StringData]] internal slot, then
if (value instanceof _index2.ObjectValue && value.$StringData) {
const stringData = value.$StringData.throwIfNotConcreteString(); // a. Assert: value's [[StringData]] internal slot is a String value.
(0, _invariant.default)(stringData instanceof _index2.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 _index2.ObjectValue)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} // 2. Let desc be a new Property Descriptor that initially has no fields.
let desc = new _descriptors.PropertyDescriptor({}); // 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 (desc.value !== undefined || desc.writable !== undefined) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
}
} // 16. Return desc.
return desc;
} // ECMA262 7.1.13
ToObject(realm, arg) {
if (arg instanceof _index2.AbstractObjectValue) return arg;
if (arg instanceof _index2.AbstractValue) {
return this._WrapAbstractInObject(realm, arg);
}
if (arg instanceof _index2.UndefinedValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (arg instanceof _index2.NullValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (arg instanceof _index2.BooleanValue) {
let obj = new _index2.ObjectValue(realm, realm.intrinsics.BooleanPrototype);
obj.$BooleanData = arg;
return obj;
} else if (arg instanceof _index2.NumberValue) {
let obj = new _index2.ObjectValue(realm, realm.intrinsics.NumberPrototype);
obj.$NumberData = arg;
return obj;
} else if (arg instanceof _index2.StringValue) {
let obj = _singletons.Create.StringCreate(realm, arg, realm.intrinsics.StringPrototype);
return obj;
} else if (arg instanceof _index2.SymbolValue) {
let obj = new _index2.ObjectValue(realm, realm.intrinsics.SymbolPrototype);
obj.$SymbolData = arg;
return obj;
} else if (arg instanceof _index2.ObjectValue) {
return arg;
}
(0, _invariant.default)(false);
}
_WrapAbstractInObject(realm, arg) {
let obj;
switch (arg.getType()) {
case _index2.IntegralValue:
case _index2.NumberValue:
obj = new _index2.ObjectValue(realm, realm.intrinsics.NumberPrototype);
obj.$NumberData = arg;
break;
case _index2.StringValue:
obj = new _index2.ObjectValue(realm, realm.intrinsics.StringPrototype);
obj.$StringData = arg;
break;
case _index2.BooleanValue:
obj = new _index2.ObjectValue(realm, realm.intrinsics.BooleanPrototype);
obj.$BooleanData = arg;
break;
case _index2.SymbolValue:
obj = new _index2.ObjectValue(realm, realm.intrinsics.SymbolPrototype);
obj.$SymbolData = arg;
break;
case _index2.UndefinedValue:
case _index2.NullValue:
case _index2.PrimitiveValue:
if (arg.mightBeNull() || arg.mightHaveBeenDeleted() || arg.mightBeUndefined()) throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
/*eslint-disable */
default:
/*eslint-enable */
if (realm.isInPureScope()) {
// will be serialized as Object.assign(serialized_arg)
obj = _index2.AbstractValue.createFromType(realm, _index2.ObjectValue, "explicit conversion to object", [arg]);
(0, _invariant.default)(obj instanceof _index2.AbstractObjectValue);
} else {
obj = arg.throwIfNotConcreteObject();
}
break;
}
return obj;
} // 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 _index2.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 _index2.NumberValue(realm, integerIndex), new _index2.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") {
_index2.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 _index2.AbstractValue) {
return val;
} else if (val instanceof _index2.UndefinedValue) {
return NaN;
} else if (val instanceof _index2.NullValue) {
return +0;
} else if (val instanceof _index2.ObjectValue) {
let prim = this.ToPrimitiveOrAbstract(realm, val, "number");
return this.ToNumberOrAbstract(realm, prim);
} else if (val instanceof _index2.BooleanValue) {
if (val.value === true) {
return 1;
} else {
// `val.value === false`
return 0;
}
} else if (val instanceof _index2.NumberValue) {
return val.value;
} else if (val instanceof _index2.StringValue) {
return Number(val.value);
} else if (val instanceof _index2.SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else {
(0, _invariant.default)(false, "unexpected type of value");
}
}
IsToNumberPure(realm, val) {
if (val instanceof _index2.Value) {
if (this.IsToPrimitivePure(realm, val)) {
let type = val.getType();
return type !== _index2.SymbolValue && type !== _index2.PrimitiveValue && type !== _index2.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 _index2.PrimitiveValue) {
return input;
} // When Type(input) is Object, the following steps are taken
(0, _invariant.default)(input instanceof _index2.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 _index2.UndefinedValue)) {
// a. Let result be ? Call(exoticToPrim, input, « hint »).
let result = (0, _call.Call)(realm, exoticToPrim, input, [new _index2.StringValue(realm, hint)]); // b. If Type(result) is not Object, return result.
if (!(result instanceof _index2.ObjectValue)) {
(0, _invariant.default)(result instanceof _index2.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 _index2.PrimitiveValue) return type;
if (input instanceof _index2.AbstractValue && !input.mightBeObject()) return _index2.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, _invariant.default)(input instanceof _index2.ObjectValue, "Expected object"); // 2. Assert: Type(hint) is String and its value is either "string" or "number".
(0, _invariant.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 _index2.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 === _index2.Value) {
(0, _invariant.default)(result instanceof _index2.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 (_index2.Value.isTypeCompatibleWith(resultType, _index2.PrimitiveValue)) {
(0, _invariant.default)(result instanceof _index2.AbstractValue || result instanceof _index2.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 _index2.StringValue) {
return val.value;
} else if (val instanceof _index2.NumberValue) {
return val.value + "";
} else if (val instanceof _index2.UndefinedValue) {
return "undefined";
} else if (val instanceof _index2.NullValue) {
return "null";
} else if (val instanceof _index2.SymbolValue) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
} else if (val instanceof _index2.BooleanValue) {
return val.value ? "true" : "false";
} else if (val instanceof _index2.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");
}
}
IsToStringPure(realm, input) {
if (input instanceof _index2.Value) {
if (this.IsToPrimitivePure(realm, input)) {
let type = input.getType();
return type !== _index2.SymbolValue && type !== _index2.PrimitiveValue && type !== _index2.Value;
}
}
return true;
}
ToStringPartial(realm, val) {
return this.ToString(realm, typeof val === "string" ? val : val.throwIfNotConcrete());
}
ToStringValue(realm, val) {
if (val.getType() === _index2.StringValue) return val;
if (val instanceof _index2.ObjectValue) {
let primValue = this.ToPrimitiveOrAbstract(realm, val, "string");
if (primValue.getType() === _index2.StringValue) return primValue;
return this.ToStringValue(realm, primValue);
} else if (val instanceof _index2.ConcreteValue) {
let str = this.ToString(realm, val);
return new _index2.StringValue(realm, str);
} else if (val instanceof _index2.AbstractValue) {
return this.ToStringAbstract(realm, val);
} else {
(0, _invariant.default)(false, "unknown value type, can't coerce to string");
}
}
ToStringAbstract(realm, value) {
if (value.mightNotBeString()) {
let result; // If the property is not a string we need to coerce it.
let coerceToString = (0, _generator.createOperationDescriptor)("COERCE_TO_STRING");
if (value.mightBeObject() && !value.isSimpleObject()) {
// If this might be a non-simple object, we need to coerce this at a
// temporal point since it can have side-effects.
// We can't rely on comparison to do it later, even if
// it is non-strict comparison since we'll do multiple
// comparisons. So we have to be explicit about when this
// happens.
result = realm.evaluateWithPossibleThrowCompletion(() => _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.StringValue, [value], coerceToString), _index.TypesDomain.topVal, _index.ValuesDomain.topVal);
} else {
result = _index2.AbstractValue.createFromBuildFunction(realm, _index2.StringValue, [value], coerceToString);
}
(0, _invariant.default)(result instanceof _index2.AbstractValue);
return result;
}
return value;
} // ECMA262 7.1.2
ToBoolean(realm, val) {
if (val instanceof _index2.BooleanValue) {
return val.value;
} else if (val instanceof _index2.UndefinedValue) {
return false;
} else if (val instanceof _index2.NullValue) {
return false;
} else if (val instanceof _index2.NumberValue) {
return val.value !== 0 && !isNaN(val.value);
} else if (val instanceof _index2.StringValue) {
return val.value.length > 0;
} else if (val instanceof _index2.ObjectValue) {
return true;
} else if (val instanceof _index2.SymbolValue) {
return true;
} else {
(0, _invariant.default)(!(val instanceof _index2.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 _index2.SymbolValue) {
// a. Return key.
return key;
} // 3. Return ! ToString(key).
return this.ToString(realm, key);
}
ToPropertyKeyPartial(realm, arg)
/* but not StringValue */
{
if (arg instanceof _index2.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, _invariant.default)(arg instanceof _index2.AbstractValue);
return arg;
} // ECMA262 7.1.16
CanonicalNumericIndexString(realm, argument) {
// 1. Assert: Type(argument) is String.
(0, _invariant.default)(argument instanceof _index2.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 _index2.StringValue(realm, this.ToString(realm, new _index2.NumberValue(realm, n))), argument) === false) return undefined; // 5. Return n.
return n;
}
}
exports.ToImplementation = ToImplementation;
//# sourceMappingURL=to.js.map