docs: @Override
    protected HtmlToken produce() {
      HtmlToken token = parseToken();
      if (null == token) { return null; }
  
      // Handle escape-exempt blocks.
      // The parse() method is only dimly aware of escape-excempt blocks, so
      // here we detect the beginning and ends of escape exempt blocks, and
      // reclassify as UNESCAPED, any tokens that appear in the middle.
      if (inEscapeExemptBlock) {
        if (token.type != HtmlTokenType.SERVERCODE) {
          // classify RCDATA as text since it can contain entities
          token = reclassify(
              token, (this.textEscapingMode == HtmlTextEscapingMode.RCDATA
                      ? HtmlTokenType.TEXT
                      : HtmlTokenType.UNESCAPED));
        }
      } else {
        switch (token.type) {
          case TAGBEGIN:
            {
              String canonTagName = canonicalName(
                  token.start + 1, token.end);
              if (HtmlTextEscapingMode.isTagFollowedByLiteralContent(
                      canonTagName)) {
                this.escapeExemptTagName = canonTagName;
                this.textEscapingMode = HtmlTextEscapingMode.getModeForTag(
                    canonTagName);
              }
              break;
            }
          case TAGEND:
            this.inEscapeExemptBlock = null != this.escapeExemptTagName;
            break;
          default:
            break;
        }
      }
      return token;
    }