137 lines
6.4 KiB
JavaScript
137 lines
6.4 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
exports.default = function (ast, strictCode, env, realm) {
|
|
// evaluate left
|
|
var lref = env.evaluate(ast.left, strictCode);
|
|
var lval = _singletons.Environment.GetValue(realm, lref);
|
|
|
|
// evaluate right
|
|
var rref = env.evaluate(ast.right, strictCode);
|
|
var rval = _singletons.Environment.GetValue(realm, rref);
|
|
|
|
return computeBinary(realm, ast.operator, lval, rval, ast.left.loc, ast.right.loc, ast.loc);
|
|
};
|
|
|
|
exports.getPureBinaryOperationResultType = getPureBinaryOperationResultType;
|
|
exports.computeBinary = computeBinary;
|
|
|
|
var _index = require("../domains/index.js");
|
|
|
|
var _errors = require("../errors.js");
|
|
|
|
var _index2 = require("../values/index.js");
|
|
|
|
var _singletons = require("../singletons.js");
|
|
|
|
var _invariant = require("../invariant.js");
|
|
|
|
var _invariant2 = _interopRequireDefault(_invariant);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
var unknownValueOfOrToString = "might be an object with an unknown valueOf or toString or Symbol.toPrimitive method";
|
|
|
|
// Returns result type if binary operation is pure (terminates, does not throw exception, does not read or write heap), otherwise undefined.
|
|
/**
|
|
* 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 getPureBinaryOperationResultType(realm, op, lval, rval, lloc, rloc) {
|
|
function reportErrorIfNotPure(purityTest, typeIfPure) {
|
|
var leftPure = purityTest(realm, lval);
|
|
var rightPure = purityTest(realm, rval);
|
|
if (leftPure && rightPure) return typeIfPure;
|
|
var loc = !leftPure ? lloc : rloc;
|
|
var error = new _errors.CompilerDiagnostic(unknownValueOfOrToString, loc, "PP0002", "RecoverableError");
|
|
if (realm.handleError(error) === "Recover") {
|
|
// Assume that an unknown value is actually a primitive or otherwise a well behaved object.
|
|
return typeIfPure;
|
|
}
|
|
throw new _errors.FatalError();
|
|
}
|
|
if (op === "+") {
|
|
var ltype = _singletons.To.GetToPrimitivePureResultType(realm, lval);
|
|
var rtype = _singletons.To.GetToPrimitivePureResultType(realm, rval);
|
|
if (ltype === undefined || rtype === undefined) {
|
|
var loc = ltype === undefined ? lloc : rloc;
|
|
var error = new _errors.CompilerDiagnostic(unknownValueOfOrToString, loc, "PP0002", "RecoverableError");
|
|
if (realm.handleError(error) === "Recover") {
|
|
// Assume that the unknown value is actually a primitive or otherwise a well behaved object.
|
|
ltype = lval.getType();
|
|
rtype = rval.getType();
|
|
if (ltype === _index2.StringValue || rtype === _index2.StringValue) return _index2.StringValue;
|
|
if (ltype === _index2.NumberValue && rtype === _index2.NumberValue) return _index2.NumberValue;
|
|
return _index2.Value;
|
|
}
|
|
throw new _errors.FatalError();
|
|
}
|
|
if (ltype === _index2.StringValue || rtype === _index2.StringValue) return _index2.StringValue;
|
|
return _index2.NumberValue;
|
|
} else if (op === "<" || op === ">" || op === ">=" || op === "<=") {
|
|
return reportErrorIfNotPure(_singletons.To.IsToPrimitivePure.bind(_singletons.To), _index2.BooleanValue);
|
|
} else if (op === "!=" || op === "==") {
|
|
var _ltype = lval.getType();
|
|
var _rtype = rval.getType();
|
|
if (_ltype === _index2.NullValue || _ltype === _index2.UndefinedValue || _rtype === _index2.NullValue || _rtype === _index2.UndefinedValue) return _index2.BooleanValue;
|
|
return reportErrorIfNotPure(_singletons.To.IsToPrimitivePure.bind(_singletons.To), _index2.BooleanValue);
|
|
} else if (op === "===" || op === "!==") {
|
|
return _index2.BooleanValue;
|
|
} else if (op === ">>>" || op === "<<" || op === ">>" || op === "&" || op === "|" || op === "^" || op === "**" || op === "%" || op === "/" || op === "*" || op === "-") {
|
|
return reportErrorIfNotPure(_singletons.To.IsToNumberPure.bind(_singletons.To), _index2.NumberValue);
|
|
} else if (op === "in" || op === "instanceof") {
|
|
if (rval.mightNotBeObject()) {
|
|
var _error2 = new _errors.CompilerDiagnostic("might not be an object, hence the " + op + " operator might throw a TypeError", rloc, "PP0003", "RecoverableError");
|
|
if (realm.handleError(_error2) === "Recover") {
|
|
// Assume that the object is actually a well behaved object.
|
|
return _index2.BooleanValue;
|
|
}
|
|
throw new _errors.FatalError();
|
|
}
|
|
if (!rval.mightNotBeObject()) {
|
|
// Simple object won't throw here, aren't proxy objects or typed arrays and do not have @@hasInstance properties.
|
|
if (rval.isSimpleObject()) return _index2.BooleanValue;
|
|
}
|
|
var _error = new _errors.CompilerDiagnostic("might be an object that behaves badly for the " + op + " operator", rloc, "PP0004", "RecoverableError");
|
|
if (realm.handleError(_error) === "Recover") {
|
|
// Assume that the object is actually a well behaved object.
|
|
return _index2.BooleanValue;
|
|
}
|
|
throw new _errors.FatalError();
|
|
}
|
|
(0, _invariant2.default)(false, "unimplemented " + op);
|
|
}
|
|
|
|
function computeBinary(realm, op, lval, rval, lloc, rloc, loc) {
|
|
// partial evaluation shortcut for a particular pattern
|
|
if (realm.useAbstractInterpretation && (op === "==" || op === "===" || op === "!=" || op === "!==")) {
|
|
if (!lval.mightNotBeObject() && (rval instanceof _index2.NullValue || rval instanceof _index2.UndefinedValue) || (lval instanceof _index2.NullValue || lval instanceof _index2.UndefinedValue) && !rval.mightNotBeObject()) {
|
|
return new _index2.BooleanValue(realm, op[0] !== "=");
|
|
}
|
|
}
|
|
|
|
if (lval instanceof _index2.AbstractValue || rval instanceof _index2.AbstractValue) {
|
|
// generate error if binary operation might throw or have side effects
|
|
getPureBinaryOperationResultType(realm, op, lval, rval, lloc, rloc);
|
|
return _index2.AbstractValue.createFromBinaryOp(realm, op, lval, rval, loc);
|
|
}
|
|
|
|
// ECMA262 12.10.3
|
|
|
|
// 5. If Type(rval) is not Object, throw a TypeError exception.
|
|
if (op === "in" && !(rval instanceof _index2.ObjectValue)) {
|
|
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
|
}
|
|
(0, _invariant2.default)(lval instanceof _index2.ConcreteValue);
|
|
(0, _invariant2.default)(rval instanceof _index2.ConcreteValue);
|
|
return _index.ValuesDomain.computeBinary(realm, op, lval, rval);
|
|
}
|
|
//# sourceMappingURL=BinaryExpression.js.map
|