docs: private static int parseClass(char[] data, int i, int out, BlockSet bs,
                                    boolean icase, boolean skipspaces,
                                    boolean unicode, boolean xml) throws PatternSyntaxException {
          char c;
          int prev = -1, oct = 0;
          boolean isFirst = true, setFirst = false, inRange = false;
          BlockSet bs1 = null;
          StringBuilder sb = null;
  
          for (; i < out; isFirst = setFirst, setFirst = false) {
              handle_special:
              switch (c = data[i++]) {
                  case ']':
                      if (isFirst) break; //treat as normal char
                      if (inRange) {
                          bs.setChar('-');
                      }
                      if (prev >= 0) {
                          char c1 = (char) prev;
                          if (icase) {
                              /*
                              bs.setChar(Character.toLowerCase(c1));
                              bs.setChar(Character.toUpperCase(c1));
                              bs.setChar(Character.toTitleCase(c1));
                              */
                              bs.setChar(Category.caseFold(c1));
                          } else bs.setChar(c1);
                      }
                      return i;
  
                  case '-':
                      if (isFirst) break;
                      //if(isFirst) throw new PatternSyntaxException("[-...] is illegal");
                      if (inRange) break;
                      //if(inRange) throw new PatternSyntaxException("[...--...] is illegal");
                      inRange = true;
                      continue;
  
                  case '[':
                      if (inRange && xml) { //[..-[..]]
                          if (prev >= 0) bs.setChar((char) prev);
                          if (bs1 == null) bs1 = new BlockSet();
                          else bs1.reset();
                          i = parseClass(data, i, out, bs1, icase, skipspaces, unicode, xml);
                          bs.subtract(bs1);
                          inRange = false;
                          prev = -1;
                          continue;
                      } else break;
  
                  case '^':
                      //if(!isFirst) throw new PatternSyntaxException("'^' isn't a first char in a class def");
                      //bs.setPositive(false);
                      //setFirst=true;
                      //continue;
                      if (isFirst) {
                          bs.setPositive(false);
                          setFirst = true;
                          continue;
                      }
                      //treat as normal char
                      break;
  
                  case ' ':
                  case '\r':
                  case '\n':
                  case '\t':
                  case '\f':
                      if (skipspaces) continue;
                      else break;
                  case '\\':
                      BlockSet negativeClass = null;
                      boolean inv = false;
                      switch (c = data[i++]) {
                          case 'r':
                              c = '\r';
                              break handle_special;
  
                          case 'n':
                              c = '\n';
                              break handle_special;
  
                          case 't':
                              c = '\t';
                              break handle_special;
  
                          case 'f':
                              c = '\f';
                              break handle_special;
  
                          case 'u':
                              if (i >= out - 4) throw new PatternSyntaxException("incomplete escape sequence \\uXXXX");
                              c = (char) ((toHexDigit(data[i++]) << 12)
                                      + (toHexDigit(data[i++]) << 8)
                                      + (toHexDigit(data[i++]) << 4)
                                      + toHexDigit(data[i++]));
                              break handle_special;
  
                          case 'b':
                              c = 8; // backspace
                              break handle_special;
  
                          case 'x': {   // hex 2-digit number
                              int hex = 0;
                              char d;
                              if ((d = data[i++]) == '{') {
                                  while (i < out && (d = data[i++]) != '}') {
                                      hex = (hex << 4) + toHexDigit(d);
                                  }
                                  if (hex > 0xffff || i == out)
                                      throw new PatternSyntaxException("\\x{<out of range or incomplete>}");
                              } else {
                                  if(i >= out - 2) throw new PatternSyntaxException("incomplete escape sequence \\xHH");
                                  hex = (toHexDigit(d) << 4) + toHexDigit(data[i++]);
                              }
                              c = (char) hex;
                              break handle_special;
                          }
                          case 'o':   // oct 2- or 3-digit number
                              oct = 0;
                              for (; ; ) {
                                  char d = data[i++];
                                  if (d >= '0' && d <= '7') {
                                      oct *= 8;
                                      oct += d - '0';
                                      if (oct > 0xffff){
                                          oct -= d - '0';
                                          oct /= 8;
                                          break;
                                      }
                                  } else break;
                              }
                              c = (char) oct;
                              break handle_special;
                          case '0':
                          case '1':
                          case '2':
                          case '3':
                          case '4':
                          case '5':
                          case '6':
                          case '7':
                              oct = 0;
                              for (; ; ) {
                                  char d = data[i - 1];
                                  if (d >= '0' && d <= '7') {
                                      i++;
                                      oct *= 8;
                                      oct += d - '0';
                                      if (oct > 0xffff){
                                          oct -= d - '0';
                                          oct /= 8;
                                          break;
                                      }
                                  } else {
                                      i--;
                                      break;
                                  }
                              }
                              c = (char) oct;
                              break handle_special;
  
                          case 'm':   // decimal number -> char
                              int dec = 0;
                              for (; ; ) {
                                  char d = data[i++];
                                  if (d >= '0' && d <= '9') {
                                      dec *= 10;
                                      dec += d - '0';
                                      if (dec > 0xffff) {
                                          dec -= d - '0';
                                          dec /= 10;
                                          break;
                                      }
                                  } else break;
                              }
                              c = (char) dec;
                              break handle_special;
  
                          case 'c':   // ctrl-char
                              c = (char) (data[i++] & 0x1f);
                              break handle_special;
  
                          //classes;
                          //
                          case 'D':   // non-digit
                              negativeClass = unicode ? UNONDIGIT : NONDIGIT;
                              break;
  
                          case 'S':   // space
                              negativeClass = unicode ? UNONSPACE : NONSPACE;
                              break;
  
                          case 'W':   // space
                              negativeClass = unicode ? UNONWORDCHAR : NONWORDCHAR;
                              break;
  
                          case 'd':   // digit
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\d...]");
                              bs.setDigit(unicode);
                              continue;
  
                          case 's':   // digit
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\s...]");
                              bs.setSpace(unicode);
                              continue;
  
                          case 'w':   // digit
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                              bs.setWordChar(unicode);
                              continue;
  
                          case 'h':   // horizontal whitespace
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                              bs.setHorizontalSpace(unicode);
                              continue;
  
                          case 'v':   // vertical whitespace
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                              bs.setVerticalSpace(unicode);
                              continue;
  
                          case 'P':   // \\P{..}
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\P...]");
                              inv = true;
                          case 'p':   // \\p{..}
                              if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\p...]");
                              if (sb == null) sb = new StringBuilder();
                              else sb.setLength(0);
                              i = parseName(data, i, out, sb, skipspaces);
                              BlockSet nc = getNamedClass(sb.toString());
                              if (nc == null) throw new PatternSyntaxException("unknown named class: {" + sb + "}");
                              bs.add(nc, inv);
                              continue;
                          case 'Q':
                          case 'E':
                              throw new PatternSyntaxException("Escaped \\Q\\E literals cannot be inside character classes");
                          default:
                              //other escaped treat as normal
                              break handle_special;
                      }
                      //negativeClass;
                      //\S,\D,\W
                      if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\" + c + "...]");
                      bs.add(negativeClass);
                      continue;
  
                      /*
                  case '{':
                      if (inRange) throw new PatternSyntaxException("illegal range: [..." + prev + "-\\w...]");
                      if (sb == null) sb = new StringBuilder();
                      else sb.setLength(0);
                      i = parseName(data, i - 1, out, sb, skipspaces);
                      BlockSet nc = getNamedClass(sb.toString());
                      if (nc == null) throw new PatternSyntaxException("unknown named class: {" + sb + "}");
                      bs.add(nc, false);
                      continue;
                      */
                  default:
              }
              //c is a normal char
              if (prev < 0) {
                  prev = c;
                  inRange = false;
                  continue;
              }
              if (!inRange) {
                  char c1 = (char) prev;
                  if (icase) {
                      /*
                      bs.setChar(Character.toLowerCase(c1));
                      bs.setChar(Character.toUpperCase(c1));
                      bs.setChar(Character.toTitleCase(c1));
                      */
                      bs.setChar(Category.caseFold(c1));
                  } else bs.setChar(c1);
                  prev = c;
              } else {
                  if (prev > c)
                      throw new PatternSyntaxException("illegal range: " + prev + ">" + c);
                  char c0 = (char) prev;
                  inRange = false;
                  prev = -1;
                  if (icase) {
                      /*
                      bs.setRange(Character.toLowerCase(c0), Character.toLowerCase(c));
                      bs.setRange(Character.toUpperCase(c0), Character.toUpperCase(c));
                      bs.setRange(Character.toTitleCase(c0), Character.toTitleCase(c));
                      */
                      bs.setRange(Category.caseFold(c0), Category.caseFold(c));
  
                  } else bs.setRange(c0, c);
              }
          }
          throw new PatternSyntaxException("unbalanced brackets in a class def");
      }