if (!codeExistCheck(']', true)) newSyntaxException(ERR_EMPTY_CHAR_CLASS);
env.ccEscWarn("]");
token.type = TokenType.CHAR; /* allow []...] */
}
CClassNode cc = new CClassNode();
CClassNode prevCC = null;
CClassNode workCC = null;
CCStateArg arg = new CCStateArg();
boolean andStart = false;
arg.state = CCSTATE.START;
while (token.type != TokenType.CC_CLOSE) {
boolean fetched = false;
switch (token.type) {
case CHAR:
final int len;
if (Config.VANILLA) {
len = enc.codeToMbcLength(token.getC());
if (len > 1) {
arg.inType = CCVALTYPE.CODE_POINT;
} else {
arg.inType = CCVALTYPE.SB; // sb_char:
}
} else {
if (token.getCode() >= BitSet.SINGLE_BYTE_SIZE || (len = enc.codeToMbcLength(token.getC())) > 1) {
arg.inType = CCVALTYPE.CODE_POINT;
} else {
arg.inType = CCVALTYPE.SB; // sb_char:
}
}
arg.v = token.getC();
arg.vIsRaw = false;
parseCharClassValEntry2(cc, arg); // goto val_entry2
break;
case RAW_BYTE:
if (!enc.isSingleByte() && token.base != 0) { /* tok->base != 0 : octal or hexadec. */
byte[]buf = new byte[Config.ENC_MBC_CASE_FOLD_MAXLEN];
int psave = p;
int base = token.base;
buf[0] = (byte)token.getC();
int i;
for (i=1; i<enc.maxLength(); i++) {
fetchTokenInCC();
if (token.type != TokenType.RAW_BYTE || token.base != base) {
fetched = true;
break;
}
buf[i] = (byte)token.getC();
}
if (i < enc.minLength()) newValueException(ERR_TOO_SHORT_MULTI_BYTE_STRING);
len = enc.length(buf, 0, i);
if (i < len) {
newValueException(ERR_TOO_SHORT_MULTI_BYTE_STRING);
} else if (i > len) { /* fetch back */
p = psave;
for (i=1; i<len; i++) fetchTokenInCC();
fetched = false;
}
if (i == 1) {
arg.v = buf[0] & 0xff;
arg.inType = CCVALTYPE.SB; // goto raw_single
} else {
arg.v = enc.mbcToCode(buf, 0, buf.length);
arg.inType = CCVALTYPE.CODE_POINT;
}
} else {
arg.v = token.getC();
arg.inType = CCVALTYPE.SB; // raw_single:
}
arg.vIsRaw = true;
parseCharClassValEntry2(cc, arg); // goto val_entry2
break;
case CODE_POINT:
arg.v = token.getCode();
arg.vIsRaw = true;
parseCharClassValEntry(cc, arg); // val_entry:, val_entry2
break;
case POSIX_BRACKET_OPEN:
if (parsePosixBracket(cc)) { /* true: is not POSIX bracket */
env.ccEscWarn("[");
p = token.backP;
arg.v = token.getC();
arg.vIsRaw = false;
parseCharClassValEntry(cc, arg); // goto val_entry
break;
}
cc.nextStateClass(arg, env); // goto next_class
break;
case CHAR_TYPE:
cc.addCType(token.getPropCType(), token.getPropNot(), env, this);
cc.nextStateClass(arg, env); // next_class:
break;
case CHAR_PROPERTY:
int ctype = fetchCharPropertyToCType();
cc.addCType(ctype, token.getPropNot(), env, this);
cc.nextStateClass(arg, env); // goto next_class
break;
case CC_RANGE:
if (arg.state == CCSTATE.VALUE) {
fetchTokenInCC();
fetched = true;
if (token.type == TokenType.CC_CLOSE) { /* allow [x-] */
parseCharClassRangeEndVal(cc, arg); // range_end_val:, goto val_entry;
break;
} else if (token.type == TokenType.CC_AND) {
env.ccEscWarn("-");
parseCharClassRangeEndVal(cc, arg); // goto range_end_val
break;
}
arg.state = CCSTATE.RANGE;
} else if (arg.state == CCSTATE.START) {
arg.v = token.getC(); /* [-xa] is allowed */
arg.vIsRaw = false;
fetchTokenInCC();
fetched = true;
if (token.type == TokenType.CC_RANGE || andStart) env.ccEscWarn("-"); /* [--x] or [a&&-x] is warned. */
parseCharClassValEntry(cc, arg); // goto val_entry
break;
} else if (arg.state == CCSTATE.RANGE) {
env.ccEscWarn("-");
parseCharClassSbChar(cc, arg); // goto sb_char /* [!--x] is allowed */
break;
} else { /* CCS_COMPLETE */
fetchTokenInCC();
fetched = true;
if (token.type == TokenType.CC_CLOSE) { /* allow [a-b-] */
parseCharClassRangeEndVal(cc, arg); // goto range_end_val
break;
} else if (token.type == TokenType.CC_AND) {
env.ccEscWarn("-");
parseCharClassRangeEndVal(cc, arg); // goto range_end_val
break;
}
if (syntax.allowDoubleRangeOpInCC()) {
env.ccEscWarn("-");
parseCharClassSbChar(cc, arg); // goto sb_char /* [0-9-a] is allowed as [0-9\-a] */
break;
}
newSyntaxException(ERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS);
}
break;
case CC_CC_OPEN: /* [ */
CClassNode acc = parseCharClass();
cc.or(acc, enc);
break;
case CC_AND: /* && */
if (arg.state == CCSTATE.VALUE) {
arg.v = 0; // ??? safe v ?
arg.vIsRaw = false;
cc.nextStateValue(arg, env);
}
/* initialize local variables */
andStart = true;
arg.state = CCSTATE.START;
if (prevCC != null) {
prevCC.and(cc, enc);
} else {
prevCC = cc;
if (workCC == null) workCC = new CClassNode();
cc = workCC;
}
cc.clear();
break;