docs: function $ParseProvider() {
    var cache = {};
  
    var $parseOptions = {
      csp: false,
      unwrapPromises: false,
      logPromiseWarnings: true
    };
  
  
    /**
     * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
     *
     * @ngdoc method
     * @name ng.$parseProvider#unwrapPromises
     * @methodOf ng.$parseProvider
     * @description
     *
     * **This feature is deprecated, see deprecation notes below for more info**
     *
     * If set to true (default is false), $parse will unwrap promises automatically when a promise is
     * found at any part of the expression. In other words, if set to true, the expression will always
     * result in a non-promise value.
     *
     * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
     * the fulfillment value is used in place of the promise while evaluating the expression.
     *
     * **Deprecation notice**
     *
     * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
     * dichotomy between data access in templates (accessed as raw values) and controller code
     * (accessed as promises).
     *
     * In most code we ended up resolving promises manually in controllers anyway and thus unifying
     * the model access there.
     *
     * Other downsides of automatic promise unwrapping:
     *
     * - when building components it's often desirable to receive the raw promises
     * - adds complexity and slows down expression evaluation
     * - makes expression code pre-generation unattractive due to the amount of code that needs to be
     *   generated
     * - makes IDE auto-completion and tool support hard
     *
     * **Warning Logs**
     *
     * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
     * promise (to reduce the noise, each expression is logged only once). To disable this logging use
     * `$parseProvider.logPromiseWarnings(false)` api.
     *
     *
     * @param {boolean=} value New value.
     * @returns {boolean|self} Returns the current setting when used as getter and self if used as
     *                         setter.
     */
    this.unwrapPromises = function(value) {
      if (isDefined(value)) {
        $parseOptions.unwrapPromises = !!value;
        return this;
      } else {
        return $parseOptions.unwrapPromises;
      }
    };
  
  
    /**
     * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
     *
     * @ngdoc method
     * @name ng.$parseProvider#logPromiseWarnings
     * @methodOf ng.$parseProvider
     * @description
     *
     * Controls whether Angular should log a warning on any encounter of a promise in an expression.
     *
     * The default is set to `true`.
     *
     * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
     *
     * @param {boolean=} value New value.
     * @returns {boolean|self} Returns the current setting when used as getter and self if used as
     *                         setter.
     */
   this.logPromiseWarnings = function(value) {
      if (isDefined(value)) {
        $parseOptions.logPromiseWarnings = value;
        return this;
      } else {
        return $parseOptions.logPromiseWarnings;
      }
    };
  
  
    this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
      $parseOptions.csp = $sniffer.csp;
  
      promiseWarning = function promiseWarningFn(fullExp) {
        if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
        promiseWarningCache[fullExp] = true;
        $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
            'Automatic unwrapping of promises in Angular expressions is deprecated.');
      };
  
      return function(exp) {
        var parsedExpression;
  
        switch (typeof exp) {
          case 'string':
  
            if (cache.hasOwnProperty(exp)) {
              return cache[exp];
            }
  
            var lexer = new Lexer($parseOptions);
            var parser = new Parser(lexer, $filter, $parseOptions);
            parsedExpression = parser.parse(exp, false);
  
            if (exp !== 'hasOwnProperty') {
              // Only cache the value if it's not going to mess up the cache object
              // This is more performant that using Object.prototype.hasOwnProperty.call
              cache[exp] = parsedExpression;
            }
  
            return parsedExpression;
  
          case 'function':
            return exp;
  
          default:
            return noop;
        }
      };
    }];
  }