function _eval(expression, scope) {
  return new Promise((resolve, reject) => {
    if (!expression) return reject(new Error('evaluator - eval() - must pass an expression'));
    if (!_.isString(expression)) return reject(new Error('evaluator - eval() - expression must be a string'));

    var evalScope = {
      ObjectId: ObjectId,
      console: _getConsole()
    };

    if (scope && _.isObject(scope)) {
      _.extend(evalScope, scope);
    }

    var options = {
      displayErrors: false
    };

    // Evalutate the expression with the given scope
    var script;
    var result;

    try {
      script = new vm.Script(expression, options);
    } catch (err) {
      return reject(err);
    }

    //NOTE: ast could contain multiple expressions (top level nodes)

    try {
      result = script.runInNewContext(evalScope, options);
    } catch (err) {
      return reject(err);
    }

    if (typeUtils.isPromise(result)) {
      result.then(promiseResult => {
        return resolve(promiseResult);
      });

      if (result.catch) result.catch(reject);
    } else if (typeUtils.isStream(result)) {
      // result.on('end', )
    } else {
      return resolve(result);
    }
  });
}
@private
@param {String} expression
@param {Object} scope