"use strict";

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

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /**
                                                                                                                                                                                                                                                                   * 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.
                                                                                                                                                                                                                                                                   */

/* APIs for running Prepack for code where a model of the environment is supplied as part of the code. */

exports.prepackSources = prepackSources;

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

var _index2 = _interopRequireDefault(_index);

var _construct_realm = require("./construct_realm.js");

var _construct_realm2 = _interopRequireDefault(_construct_realm);

var _globals = require("./globals.js");

var _globals2 = _interopRequireDefault(_globals);

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

var _prepackOptions = require("./prepack-options");

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

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

var _options = require("./options");

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

var _invariant2 = _interopRequireDefault(_invariant);

var _package = require("../package.json");

var _types = require("./serializer/types.js");

var _ResidualHeapVisitor = require("./serializer/ResidualHeapVisitor.js");

var _modules = require("./utils/modules.js");

var _logger = require("./utils/logger.js");

var _generator = require("./utils/generator.js");

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

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

function prepackSources(sources, options = _options.defaultOptions, debugChannel = undefined) {
  let realmOptions = (0, _prepackOptions.getRealmOptions)(options);
  realmOptions.errorHandler = options.errorHandler;
  let realm = (0, _construct_realm2.default)(realmOptions, debugChannel);
  (0, _globals2.default)(realm);
  if (typeof options.additionalGlobals === "function") {
    options.additionalGlobals(realm);
  }

  if (options.check) {
    realm.generator = new _generator.Generator(realm, "main");
    let logger = new _logger.Logger(realm, !!options.internalDebug);
    let modules = new _modules.Modules(realm, logger, new _types.SerializerStatistics(), !!options.logModules, !!options.delayUnsupportedRequires, !!options.accelerateUnsupportedRequires);
    let [result] = realm.$GlobalEnv.executeSources(sources);
    if (result instanceof _completions.AbruptCompletion) throw result;
    (0, _invariant2.default)(options.check);
    checkResidualFunctions(modules, options.check[0], options.check[1]);
    return { code: "", map: undefined };
  } else if (options.serialize || !options.residual) {
    let serializer = new _index2.default(realm, (0, _prepackOptions.getSerializerOptions)(options));
    let serialized = serializer.init(sources, options.sourceMaps);

    //Turn off the debugger if there is one
    if (realm.debuggerInstance) {
      realm.debuggerInstance.shutdown();
    }

    if (!serialized) {
      throw new _errors.FatalError("serializer failed");
    }

    if (!options.residual) return serialized;
    let residualSources = [{
      filePath: options.outputFilename || "unknown",
      fileContents: serialized.code,
      sourceMapContents: serialized.map && JSON.stringify(serialized.map)
    }];
    realm = (0, _construct_realm2.default)(realmOptions, debugChannel);
    (0, _globals2.default)(realm);
    if (typeof options.additionalGlobals === "function") {
      options.additionalGlobals(realm);
    }
    realm.generator = new _generator.Generator(realm, "main");
    let result = realm.$GlobalEnv.executePartialEvaluator(residualSources, options);
    if (result instanceof _completions.AbruptCompletion) throw result;
    return _extends({}, result);
  } else {
    (0, _invariant2.default)(options.residual);
    realm.generator = new _generator.Generator(realm, "main");
    let result = realm.$GlobalEnv.executePartialEvaluator(sources, options);
    if (result instanceof _completions.AbruptCompletion) throw result;
    return _extends({}, result);
  }
}

function checkResidualFunctions(modules, startFunc, totalToAnalyze) {
  let realm = modules.realm;
  let env = realm.$GlobalEnv;
  realm.$GlobalObject.makeSimple();
  let errorHandler = realm.errorHandler;
  if (!errorHandler) errorHandler = diag => realm.handleError(diag);
  realm.errorHandler = diag => {
    (0, _invariant2.default)(errorHandler);
    if (diag.severity === "FatalError") return errorHandler(diag);else return "Recover";
  };
  modules.resolveInitializedModules();
  let residualHeapVisitor = new _ResidualHeapVisitor.ResidualHeapVisitor(realm, modules.logger, modules, new Map(), "NO_REFERENTIALIZE");
  residualHeapVisitor.visitRoots();
  if (modules.logger.hasErrors()) return;
  let totalFunctions = 0;
  let nonFatalFunctions = 0;
  for (let fi of residualHeapVisitor.functionInstances.values()) {
    totalFunctions++;
    if (totalFunctions <= startFunc) continue;
    let fv = fi.functionValue;
    console.log("analyzing: " + totalFunctions);
    let thisValue = realm.intrinsics.null;
    let n = fv.getLength() || 0;
    let args = [];
    for (let i = 0; i < n; i++) {
      let name = "dummy parameter";
      let ob = _index4.AbstractValue.createFromType(realm, _index4.ObjectValue, name);
      ob.makeSimple("transitive");
      ob.intrinsicName = name;
      args[i] = ob;
    }
    // todo: eventually join these effects, apply them to the global state and iterate to a fixed point
    try {
      realm.evaluateForEffectsInGlobalEnv(() => (0, _index3.EvaluateDirectCallWithArgList)(modules.realm, true, env, fv, fv, thisValue, args));
      nonFatalFunctions++;
    } catch (e) {}
    if (totalFunctions >= startFunc + totalToAnalyze) break;
  }
  console.log(`Analyzed ${totalToAnalyze} functions starting at ${startFunc} of which ${nonFatalFunctions} did not have fatal errors.`);
}

const prepackVersion = exports.prepackVersion = _package.version;
//# sourceMappingURL=prepack-standalone.js.map