text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  
  var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            * 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.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            */
  
  exports.default = function (ast, strictCode, env, realm) {
    // evaluate left
    var lref = env.evaluate(ast.left, strictCode);
    var lval = (0, _index2.GetValue)(realm, lref);
  
    // evaluate right
    var rref = env.evaluate(ast.right, strictCode);
    var rval = (0, _index2.GetValue)(realm, rref);
  
    return computeBinary(realm, ast.operator, lval, rval);
  };
  
  exports.getPureBinaryOperationResultType = getPureBinaryOperationResultType;
  exports.computeBinary = computeBinary;
  
  var _index = require("../values/index.js");
  
  var _index2 = require("../methods/index.js");
  
  var _index3 = require("../domains/index.js");
  
  var _babelTypes = require("babel-types");
  
  var t = _interopRequireWildcard(_babelTypes);
  
  var _invariant = require("../invariant.js");
  
  var _invariant2 = _interopRequireDefault(_invariant);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
  
  // Returns result type if binary operation is pure (terminates, does not throw exception, does not read or write heap), otherwise undefined.
  function getPureBinaryOperationResultType(realm, op, lval, rval) {
    if (op === "+") {
      var ltype = (0, _index2.GetToPrimitivePureResultType)(realm, lval);
      var rtype = (0, _index2.GetToPrimitivePureResultType)(realm, rval);
      if (ltype === undefined || rtype === undefined) return undefined;
      if (ltype === _index.StringValue || rtype === _index.StringValue) return _index.StringValue;
      return _index.NumberValue;
    } else if (op === "<" || op === ">" || op === ">=" || op === "<=" || op === "!=" || op === "==") {
      if ((0, _index2.IsToPrimitivePure)(realm, lval) && (0, _index2.IsToPrimitivePure)(realm, rval)) return _index.BooleanValue;
      return undefined;
    } else if (op === "===" || op === "!==") {
      return _index.BooleanValue;
    } else if (op === ">>>" || op === "<<" || op === ">>" || op === "&" || op === "|" || op === "^" || op === "**" || op === "%" || op === "/" || op === "*" || op === "-") {
      if ((0, _index2.IsToNumberPure)(realm, lval) && (0, _index2.IsToNumberPure)(realm, rval)) return _index.NumberValue;
      return undefined;
    } else if (op === "in") {
      // TODO. Tricky. Needs deeper analysis. Can call arbitrary code e.g. when object is a Proxy => Side effects!
      return undefined;
    } else if (op === "instanceof") {
      // TODO. Tricky. Needs deeper analysis. Can throw exceptions, call arbitrary code => Side effects!
      return undefined;
    }
    (0, _invariant2.default)(false, "unimplemented " + op);
  }
  
  function computeBinary(realm, op, lval, rval) {
    // partial evaluation shortcut for a particular pattern (avoiding general throwIfNotConcrete check)
    if (op === "==" || op === "===" || op === "!=" || op === "!==") {
      if (!lval.mightNotBeObject() && (0, _index2.HasSomeCompatibleType)(realm, rval, _index.NullValue, _index.UndefinedValue) || (0, _index2.HasSomeCompatibleType)(realm, lval, _index.NullValue, _index.UndefinedValue) && !rval.mightNotBeObject()) return new _index.BooleanValue(realm, op[0] !== "=");
    }
  
    if (lval instanceof _index.AbstractValue || rval instanceof _index.AbstractValue) {
      var type = getPureBinaryOperationResultType(realm, op, lval, rval);
      if (type !== undefined) {
        return realm.createAbstract(new _index3.TypesDomain(type), _index3.ValuesDomain.topVal, [lval, rval], function (_ref) {
          var _ref2 = _slicedToArray(_ref, 2),
              lnode = _ref2[0],
              rnode = _ref2[1];
  
          return t.binaryExpression(op, lnode, rnode);
        });
      }
    }
  
    lval = lval.throwIfNotConcrete();
    rval = rval.throwIfNotConcrete();
  
    if (op === "+") {
      // ECMA262 12.8.3 The Addition Operator
      var lprim = (0, _index2.ToPrimitive)(realm, lval);
      var rprim = (0, _index2.ToPrimitive)(realm, rval);
  
      if (lprim instanceof _index.StringValue || rprim instanceof _index.StringValue) {
        var lstr = (0, _index2.ToString)(realm, lprim);
        var rstr = (0, _index2.ToString)(realm, rprim);
        return new _index.StringValue(realm, lstr + rstr);
      }
  
      var lnum = (0, _index2.ToNumber)(realm, lprim);
      var rnum = (0, _index2.ToNumber)(realm, rprim);
      return (0, _index2.Add)(realm, lnum, rnum);
    } else if (op === "<" || op === ">" || op === ">=" || op === "<=") {
      // ECMA262 12.10.3
      if (op === "<") {
        var r = (0, _index2.AbstractRelationalComparison)(realm, lval, rval, true);
        if (r instanceof _index.UndefinedValue) {
          return realm.intrinsics.false;
        } else {
          return r;
        }
      } else if (op === "<=") {
        var _r = (0, _index2.AbstractRelationalComparison)(realm, rval, lval, false);
        if (_r instanceof _index.UndefinedValue || _r instanceof _index.BooleanValue && _r.value) {
          return realm.intrinsics.false;
        } else {
          return realm.intrinsics.true;
        }
      } else if (op === ">") {
        var _r2 = (0, _index2.AbstractRelationalComparison)(realm, rval, lval, false);
        if (_r2 instanceof _index.UndefinedValue) {
          return realm.intrinsics.false;
        } else {
          return _r2;
        }
      } else if (op === ">=") {
        var _r3 = (0, _index2.AbstractRelationalComparison)(realm, lval, rval, true);
        if (_r3 instanceof _index.UndefinedValue || _r3 instanceof _index.BooleanValue && _r3.value) {
          return realm.intrinsics.false;
        } else {
          return realm.intrinsics.true;
        }
      }
    } else if (op === ">>>") {
      // ECMA262 12.9.5.1
      var _lnum = (0, _index2.ToUint32)(realm, lval);
      var _rnum = (0, _index2.ToUint32)(realm, rval);
  
      return new _index.NumberValue(realm, _lnum >>> _rnum);
    } else if (op === "<<" || op === ">>") {
      var _lnum2 = (0, _index2.ToInt32)(realm, lval);
      var _rnum2 = (0, _index2.ToUint32)(realm, rval);
  
      if (op === "<<") {
        // ECMA262 12.9.3.1
        return new _index.NumberValue(realm, _lnum2 << _rnum2);
      } else if (op === ">>") {
        // ECMA262 12.9.4.1
        return new _index.NumberValue(realm, _lnum2 >> _rnum2);
      }
    } else if (op === "**") {
      // ECMA262 12.6.3
  
      // 5. Let base be ? ToNumber(leftValue).
      var base = (0, _index2.ToNumber)(realm, lval);
  
      // 6. Let exponent be ? ToNumber(rightValue).
      var exponent = (0, _index2.ToNumber)(realm, rval);
  
      // 7. Return the result of Applying the ** operator with base and exponent as specified in 12.7.3.4.
      return new _index.NumberValue(realm, Math.pow(base, exponent));
    } else if (op === "%" || op === "/" || op === "*" || op === "-") {
      // ECMA262 12.7.3
      var _lnum3 = (0, _index2.ToNumber)(realm, lval);
      var _rnum3 = (0, _index2.ToNumber)(realm, rval);
  
      if (isNaN(_rnum3)) return realm.intrinsics.NaN;
      if (isNaN(_lnum3)) return realm.intrinsics.NaN;
  
      if (op === "-") {
        return (0, _index2.Add)(realm, _lnum3, _rnum3, true);
      } else if (op === "%") {
        // The sign of the result equals the sign of the dividend.
        // If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN.
        // If the dividend is finite and the divisor is an infinity, the result equals the dividend.
        // If the dividend is a zero and the divisor is nonzero and finite, the result is the same as the dividend.
        return new _index.NumberValue(realm, _lnum3 % _rnum3);
      } else if (op === "/") {
        // The sign of the result is positive if both operands have the same sign, negative if the operands have different signs.
        // Division of an infinity by an infinity results in NaN.
        // Division of an infinity by a zero results in an infinity. The sign is determined by the rule already stated above.
        // Division of an infinity by a nonzero finite value results in a signed infinity. The sign is determined by the rule already stated above.
        // Division of a finite value by an infinity results in zero. The sign is determined by the rule already stated above.
        // Division of a zero by a zero results in NaN; division of zero by any other finite value results in zero, with the sign determined by the rule already stated above.
        // Division of a nonzero finite value by a zero results in a signed infinity. The sign is determined by the rule already stated above.
        return new _index.NumberValue(realm, _lnum3 / _rnum3);
      } else if (op === "*") {
        // The sign of the result is positive if both operands have the same sign, negative if the operands have different signs.
        // Multiplication of an infinity by a zero results in NaN.
        // Multiplication of an infinity by an infinity results in an infinity. The sign is determined by the rule already stated above.
        // Multiplication of an infinity by a finite nonzero value results in a signed infinity. The sign is determined by the rule already stated above.
        return new _index.NumberValue(realm, _lnum3 * _rnum3);
      }
    } else if (op === "!==") {
      return new _index.BooleanValue(realm, !(0, _index2.StrictEqualityComparison)(realm, lval, rval));
    } else if (op === "===") {
      return new _index.BooleanValue(realm, (0, _index2.StrictEqualityComparison)(realm, lval, rval));
    } else if (op === "!=") {
      return new _index.BooleanValue(realm, !(0, _index2.AbstractEqualityComparison)(realm, lval, rval));
    } else if (op === "==") {
      return new _index.BooleanValue(realm, (0, _index2.AbstractEqualityComparison)(realm, lval, rval));
    } else if (op === "&" || op === "|" || op === "^") {
      // ECMA262 12.12.3
  
      var _lnum4 = (0, _index2.ToInt32)(realm, lval);
  
      // 6. Let rnum be ? ToInt32(rval).
      var _rnum4 = (0, _index2.ToInt32)(realm, rval);
  
      // 7. Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.
      if (op === "&") {
        return new _index.NumberValue(realm, _lnum4 & _rnum4);
      } else if (op === "|") {
        return new _index.NumberValue(realm, _lnum4 | _rnum4);
      } else if (op === "^") {
        return new _index.NumberValue(realm, _lnum4 ^ _rnum4);
      }
    } else if (op === "in") {
      // ECMA262 12.10.3
  
      // 5. If Type(rval) is not Object, throw a TypeError exception.
      if (!(rval instanceof _index.ObjectValue)) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
      }
  
      // 6. Return ? HasProperty(rval, ToPropertyKey(lval)).
      return new _index.BooleanValue(realm, (0, _index2.HasProperty)(realm, rval, (0, _index2.ToPropertyKey)(realm, lval)));
    } else if (op === "instanceof") {
      // ECMA262 12.10.3
  
      // 5. Return ? InstanceofOperator(lval, rval).;
      return new _index.BooleanValue(realm, (0, _index2.InstanceofOperator)(realm, lval, rval));
    }
  
    (0, _invariant2.default)(false, "unimplemented " + op);
  }
  //# sourceMappingURL=BinaryExpression.js.map