docs: function (token) {
      var self = this,
        fn = self._parsers[token.type] || self._parsers['*'],
        match = token.match,
        prevToken = self.prevToken,
        prevTokenType = prevToken ? prevToken.type : null,
        lastState = (self.state.length) ? self.state[self.state.length - 1] : null,
        temp;
  
      if (fn && typeof fn === 'function') {
        if (!fn.call(this, token)) {
          return;
        }
      }
  
      if (lastState && prevToken &&
          lastState === _t.FILTER &&
          prevTokenType === _t.FILTER &&
          token.type !== _t.PARENCLOSE &&
          token.type !== _t.COMMA &&
          token.type !== _t.OPERATOR &&
          token.type !== _t.FILTER &&
          token.type !== _t.FILTEREMPTY) {
        self.out.push(', ');
      }
  
      if (lastState && lastState === _t.METHODOPEN) {
        self.state.pop();
        if (token.type !== _t.PARENCLOSE) {
          self.out.push(', ');
        }
      }
  
      switch (token.type) {
      case _t.WHITESPACE:
        break;
  
      case _t.STRING:
        self.filterApplyIdx.push(self.out.length);
        self.out.push(match.replace(/\\/g, '\\\\'));
        break;
  
      case _t.NUMBER:
      case _t.BOOL:
        self.filterApplyIdx.push(self.out.length);
        self.out.push(match);
        break;
  
      case _t.FILTER:
        if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") {
          utils.throwError('Invalid filter "' + match + '"', self.line, self.filename);
        }
        self.escape = self.filters[match].safe ? false : self.escape;
        self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"](');
        self.state.push(token.type);
        break;
  
      case _t.FILTEREMPTY:
        if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") {
          utils.throwError('Invalid filter "' + match + '"', self.line, self.filename);
        }
        self.escape = self.filters[match].safe ? false : self.escape;
        self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"](');
        self.out.push(')');
        break;
  
      case _t.FUNCTION:
      case _t.FUNCTIONEMPTY:
        self.out.push('((typeof _ctx.' + match + ' !== "undefined") ? _ctx.' + match +
          ' : ((typeof ' + match + ' !== "undefined") ? ' + match +
          ' : _fn))(');
        self.escape = false;
        if (token.type === _t.FUNCTIONEMPTY) {
          self.out[self.out.length - 1] = self.out[self.out.length - 1] + ')';
        } else {
          self.state.push(token.type);
        }
        self.filterApplyIdx.push(self.out.length - 1);
        break;
  
      case _t.PARENOPEN:
        self.state.push(token.type);
        if (self.filterApplyIdx.length) {
          self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '(');
          if (prevToken && prevTokenType === _t.VAR) {
            temp = prevToken.match.split('.').slice(0, -1);
            self.out.push(' || _fn).call(' + self.checkMatch(temp));
            self.state.push(_t.METHODOPEN);
            self.escape = false;
          } else {
            self.out.push(' || _fn)(');
          }
          self.filterApplyIdx.push(self.out.length - 3);
        } else {
          self.out.push('(');
          self.filterApplyIdx.push(self.out.length - 1);
        }
        break;
  
      case _t.PARENCLOSE:
        temp = self.state.pop();
        if (temp !== _t.PARENOPEN && temp !== _t.FUNCTION && temp !== _t.FILTER) {
          utils.throwError('Mismatched nesting state', self.line, self.filename);
        }
        self.out.push(')');
        // Once off the previous entry
        self.filterApplyIdx.pop();
        if (temp !== _t.FILTER) {
          // Once for the open paren
          self.filterApplyIdx.pop();
        }
        break;
  
      case _t.COMMA:
        if (lastState !== _t.FUNCTION &&
            lastState !== _t.FILTER &&
            lastState !== _t.ARRAYOPEN &&
            lastState !== _t.CURLYOPEN &&
            lastState !== _t.PARENOPEN &&
            lastState !== _t.COLON) {
          utils.throwError('Unexpected comma', self.line, self.filename);
        }
        if (lastState === _t.COLON) {
          self.state.pop();
        }
        self.out.push(', ');
        self.filterApplyIdx.pop();
        break;
  
      case _t.LOGIC:
      case _t.COMPARATOR:
        if (!prevToken ||
            prevTokenType === _t.COMMA ||
            prevTokenType === token.type ||
            prevTokenType === _t.BRACKETOPEN ||
            prevTokenType === _t.CURLYOPEN ||
            prevTokenType === _t.PARENOPEN ||
            prevTokenType === _t.FUNCTION) {
          utils.throwError('Unexpected logic', self.line, self.filename);
        }
        self.out.push(token.match);
        break;
  
      case _t.NOT:
        self.out.push(token.match);
        break;
  
      case _t.VAR:
        self.parseVar(token, match, lastState);
        break;
  
      case _t.BRACKETOPEN:
        if (!prevToken ||
            (prevTokenType !== _t.VAR &&
              prevTokenType !== _t.BRACKETCLOSE &&
              prevTokenType !== _t.PARENCLOSE)) {
          self.state.push(_t.ARRAYOPEN);
          self.filterApplyIdx.push(self.out.length);
        } else {
          self.state.push(token.type);
        }
        self.out.push('[');
        break;
  
      case _t.BRACKETCLOSE:
        temp = self.state.pop();
        if (temp !== _t.BRACKETOPEN && temp !== _t.ARRAYOPEN) {
          utils.throwError('Unexpected closing square bracket', self.line, self.filename);
        }
        self.out.push(']');
        self.filterApplyIdx.pop();
        break;
  
      case _t.CURLYOPEN:
        self.state.push(token.type);
        self.out.push('{');
        self.filterApplyIdx.push(self.out.length - 1);
        break;
  
      case _t.COLON:
        if (lastState !== _t.CURLYOPEN) {
          utils.throwError('Unexpected colon', self.line, self.filename);
        }
        self.state.push(token.type);
        self.out.push(':');
        self.filterApplyIdx.pop();
        break;
  
      case _t.CURLYCLOSE:
        if (lastState === _t.COLON) {
          self.state.pop();
        }
        if (self.state.pop() !== _t.CURLYOPEN) {
          utils.throwError('Unexpected closing curly brace', self.line, self.filename);
        }
        self.out.push('}');
  
        self.filterApplyIdx.pop();
        break;
  
      case _t.DOTKEY:
        if (!prevToken || (
            prevTokenType !== _t.VAR &&
            prevTokenType !== _t.BRACKETCLOSE &&
            prevTokenType !== _t.DOTKEY &&
            prevTokenType !== _t.PARENCLOSE &&
            prevTokenType !== _t.FUNCTIONEMPTY &&
            prevTokenType !== _t.FILTEREMPTY &&
            prevTokenType !== _t.CURLYCLOSE
          )) {
          utils.throwError('Unexpected key "' + match + '"', self.line, self.filename);
        }
        self.out.push('.' + match);
        break;
  
      case _t.OPERATOR:
        self.out.push(' ' + match + ' ');
        self.filterApplyIdx.pop();
        break;
      }
    }