"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = function (ast, strictCode, env, realm) {
  realm.setNextExecutionContextLocation(ast.loc);

  // ECMA262 12.3.3.1 We just implement this method inline since it's only called here.
  // 1. Return ? EvaluateNew(NewExpression, empty).

  // ECMA262 2.3.3.1.1

  let constructProduction = ast.callee;
  let args = ast.arguments;

  // These steps not necessary due to our AST representation.
  // 1. Assert: constructProduction is either a NewExpression or a MemberExpression.
  // 2. Assert: arguments is either empty or an Arguments production.

  // 3. Let ref be the result of evaluating constructProduction.
  let ref = env.evaluate(constructProduction, strictCode);

  // 4. Let constructor be ? GetValue(ref).
  let constructor = _singletons.Environment.GetValue(realm, ref);

  let argsList;

  // 5. If arguments is empty, let argList be a new empty List.
  if (!args.length) {
    argsList = [];
  } else {
    // 6. Else,
    // a. Let argList be ArgumentListEvaluation of arguments.
    argsList = (0, _index3.ArgumentListEvaluation)(realm, strictCode, env, args); // BabelNodeNewExpression needs updating

    // This step not necessary since we propagate completions with exceptions.
    // b. ReturnIfAbrupt(argList).
  }

  // If we are in pure scope, attempt to recover from creating the construct if
  // it fails by creating a temporal abstract
  if (realm.isInPureScope()) {
    return tryToEvaluateConstructOrLeaveAsAbstract(constructor, argsList, strictCode, realm);
  } else {
    return createConstruct(constructor, argsList, realm);
  }
};

var _completions = require("../completions.js");

var _index = require("../domains/index.js");

var _index2 = require("../values/index.js");

var _singletons = require("../singletons.js");

var _index3 = require("../methods/index.js");

var _invariant = require("../invariant.js");

var _invariant2 = _interopRequireDefault(_invariant);

var _errors = require("../errors.js");

var _babelTypes = require("babel-types");

var t = _interopRequireWildcard(_babelTypes);

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; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function tryToEvaluateConstructOrLeaveAsAbstract(constructor, argsList, strictCode, realm) {
  let effects;
  try {
    effects = realm.evaluateForEffects(() => createConstruct(constructor, argsList, realm), undefined, "tryToEvaluateConstructOrLeaveAsAbstract");
  } catch (error) {
    // if a FatalError occurs when constructing the constructor
    // then try and recover and create an abstract for this construct
    if (error instanceof _errors.FatalError) {
      // we need to havoc all the arguments and the constructor
      _singletons.Havoc.value(realm, constructor);
      for (let arg of argsList) {
        _singletons.Havoc.value(realm, arg);
      }
      let abstractValue = realm.evaluateWithPossibleThrowCompletion(() => _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.ObjectValue, [constructor, ...argsList], ([constructorNode, ...argListNodes]) => t.newExpression(constructorNode, argListNodes)), _index.TypesDomain.topVal, _index.ValuesDomain.topVal);
      (0, _invariant2.default)(abstractValue instanceof _index2.AbstractObjectValue);
      return abstractValue;
    } else {
      throw error;
    }
  }
  let completion = effects[0];
  if (completion instanceof _completions.PossiblyNormalCompletion) {
    // in this case one of the branches may complete abruptly, which means that
    // not all control flow branches join into one flow at this point.
    // Consequently we have to continue tracking changes until the point where
    // all the branches come together into one.
    completion = realm.composeWithSavedCompletion(completion);
  }

  // Note that the effects of (non joining) abrupt branches are not included
  // in joinedEffects, but are tracked separately inside completion.
  realm.applyEffects(effects);
  // return or throw completion
  if (completion instanceof _completions.AbruptCompletion) throw completion;
  (0, _invariant2.default)(completion instanceof _index2.ObjectValue || completion instanceof _index2.AbstractObjectValue);
  return completion;
} /**
   * 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 createConstruct(constructor, argsList, realm) {
  // 7. If IsConstructor(constructor) is false, throw a TypeError exception.
  if ((0, _index3.IsConstructor)(realm, constructor) === false) {
    throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
  }
  (0, _invariant2.default)(constructor instanceof _index2.ObjectValue);

  // 8. Return ? Construct(constructor, argList).
  return (0, _index3.Construct)(realm, constructor, argsList);
}
//# sourceMappingURL=NewExpression.js.map