"use strict";

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

var _realm = require("../realm.js");

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

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

var _completions = require("../completions.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 }; }

class Logger {
  constructor(realm, internalDebug) {
    this.realm = realm;
    this._hasErrors = false;
    this.internalDebug = internalDebug;
  }

  // Wraps a query that might potentially execute user code.
  tryQuery(f, defaultValue) {
    let realm = this.realm;
    let context = new _realm.ExecutionContext();
    context.isStrict = realm.isStrict;
    let env = realm.$GlobalEnv;
    context.lexicalEnvironment = env;
    context.variableEnvironment = env;
    context.realm = realm;
    realm.pushContext(context);
    // We use partial evaluation so that we can throw away any state mutations
    let oldErrorHandler = realm.errorHandler;
    realm.errorHandler = d => {
      if (d.severity === "Information" || d.severity === "Warning") return "Recover";
      return "Fail";
    };
    try {
      let result;
      let effects = realm.evaluateForEffects(() => {
        try {
          result = f();
        } catch (e) {
          if (e instanceof _completions.Completion) {
            result = defaultValue;
          } else if (e instanceof _errors.FatalError) {
            result = defaultValue;
          } else {
            throw e;
          }
        }
        return realm.intrinsics.undefined;
      }, undefined, "tryQuery");
      (0, _invariant2.default)(effects[0] === realm.intrinsics.undefined);
      return result;
    } finally {
      realm.errorHandler = oldErrorHandler;
      realm.popContext(context);
    }
  }

  logCompletion(res) {
    let realm = this.realm;
    let value = res.value;
    if (this.internalDebug) console.error(`=== ${res.constructor.name} ===`);
    if (this.tryQuery(() => value instanceof _index2.ObjectValue && (0, _index.InstanceofOperator)(realm, value, realm.intrinsics.Error), false)) {
      let object = value;
      try {
        let err = new _errors.FatalError(this.tryQuery(() => _singletons.To.ToStringPartial(realm, (0, _index.Get)(realm, object, "message")), "(unknown message)"));
        err.stack = this.tryQuery(() => _singletons.To.ToStringPartial(realm, (0, _index.Get)(realm, object, "stack")), "(unknown stack)");
        console.error(err.message);
        console.error(err.stack);
        if (this.internalDebug && res instanceof _completions.ThrowCompletion) console.error(res.nativeStack);
      } catch (err) {
        let message = object.properties.get("message");
        console.error(message && message.descriptor && message.descriptor.value instanceof _index2.StringValue ? message.descriptor.value.value : "(no message available)");
        console.error(err.stack);
        if (object.$ErrorData) {
          console.error(object.$ErrorData.contextStack);
        }
      }
    } else {
      try {
        value = _singletons.To.ToStringPartial(realm, value);
      } catch (err) {
        value = err.message;
      }
      console.error(value);
      if (this.internalDebug && res instanceof _completions.ThrowCompletion) console.error(res.nativeStack);
    }
    this._hasErrors = true;
  }

  logError(value, message) {
    this._log(value, message, "RecoverableError");
    this._hasErrors = true;
  }

  logWarning(value, message) {
    this._log(value, message, "Warning");
  }

  logInformation(message) {
    this._log(this.realm.intrinsics.undefined, message, "Information");
  }

  _log(value, message, severity) {
    let loc = value.expressionLocation;
    if (value.intrinsicName) {
      message = `${message}\nintrinsic name: ${value.intrinsicName}`;
    }
    let diagnostic = new _errors.CompilerDiagnostic(message, loc, "PP9000", severity);
    if (this.realm.handleError(diagnostic) === "Fail") throw new _errors.FatalError();
  }

  hasErrors() {
    return this._hasErrors;
  }
}
exports.Logger = Logger; /**
                          * 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.
                          */
//# sourceMappingURL=logger.js.map