331 |
// Buffer a token so we can create a TokenRepeated, etc. |
// Buffer a token so we can create a TokenRepeated, etc. |
332 |
REToken currentToken = null; |
REToken currentToken = null; |
333 |
char ch; |
char ch; |
334 |
|
boolean quot = false; |
335 |
|
|
336 |
while (index < pLength) { |
while (index < pLength) { |
337 |
// read the next character unit (including backslash escapes) |
// read the next character unit (including backslash escapes) |
338 |
index = getCharUnit(pattern,index,unit); |
index = getCharUnit(pattern,index,unit,quot); |
339 |
|
|
340 |
|
if (unit.bk) |
341 |
|
if (unit.ch == 'Q') { |
342 |
|
quot = true; |
343 |
|
continue; |
344 |
|
} else if (unit.ch == 'E') { |
345 |
|
quot = false; |
346 |
|
continue; |
347 |
|
} |
348 |
|
if (quot) |
349 |
|
unit.bk = false; |
350 |
|
|
351 |
// ALTERNATION OPERATOR |
// ALTERNATION OPERATOR |
352 |
// \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT) |
// \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT) |
354 |
|
|
355 |
// TODO: the '\n' literal here should be a test against REToken.newline, |
// TODO: the '\n' literal here should be a test against REToken.newline, |
356 |
// which unfortunately may be more than a single character. |
// which unfortunately may be more than a single character. |
357 |
if ( ( (unit.ch == '|' && (syntax.get(RESyntax.RE_NO_BK_VBAR) ^ unit.bk)) |
if ( ( (unit.ch == '|' && (syntax.get(RESyntax.RE_NO_BK_VBAR) ^ (unit.bk || quot))) |
358 |
|| (syntax.get(RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') && !unit.bk) ) |
|| (syntax.get(RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') && !(unit.bk || quot)) ) |
359 |
&& !syntax.get(RESyntax.RE_LIMITED_OPS)) { |
&& !syntax.get(RESyntax.RE_LIMITED_OPS)) { |
360 |
// make everything up to here be a branch. create vector if nec. |
// make everything up to here be a branch. create vector if nec. |
361 |
addToken(currentToken); |
addToken(currentToken); |
375 |
// OPEN QUESTION: |
// OPEN QUESTION: |
376 |
// what is proper interpretation of '{' at start of string? |
// what is proper interpretation of '{' at start of string? |
377 |
|
|
378 |
else if ((unit.ch == '{') && syntax.get(RESyntax.RE_INTERVALS) && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk)) { |
else if ((unit.ch == '{') && syntax.get(RESyntax.RE_INTERVALS) && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ (unit.bk || quot))) { |
379 |
int newIndex = getMinMax(pattern,index,minMax,syntax); |
int newIndex = getMinMax(pattern,index,minMax,syntax); |
380 |
if (newIndex > index) { |
if (newIndex > index) { |
381 |
if (minMax.first > minMax.second) |
if (minMax.first > minMax.second) |
400 |
// LIST OPERATOR: |
// LIST OPERATOR: |
401 |
// [...] | [^...] |
// [...] | [^...] |
402 |
|
|
403 |
else if ((unit.ch == '[') && !unit.bk) { |
else if ((unit.ch == '[') && !(unit.bk || quot)) { |
404 |
Vector options = new Vector(); |
Vector options = new Vector(); |
405 |
boolean negative = false; |
boolean negative = false; |
406 |
char lastChar = 0; |
char lastChar = 0; |
502 |
// SUBEXPRESSIONS |
// SUBEXPRESSIONS |
503 |
// (...) | \(...\) depending on RE_NO_BK_PARENS |
// (...) | \(...\) depending on RE_NO_BK_PARENS |
504 |
|
|
505 |
else if ((unit.ch == '(') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) { |
else if ((unit.ch == '(') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) { |
506 |
boolean pure = false; |
boolean pure = false; |
507 |
boolean comment = false; |
boolean comment = false; |
508 |
boolean lookAhead = false; |
boolean lookAhead = false; |
549 |
int nextIndex = index; |
int nextIndex = index; |
550 |
int nested = 0; |
int nested = 0; |
551 |
|
|
552 |
while ( ((nextIndex = getCharUnit(pattern,endIndex,unit)) > 0) |
while ( ((nextIndex = getCharUnit(pattern,endIndex,unit,false)) > 0) |
553 |
&& !(nested == 0 && (unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) ) |
&& !(nested == 0 && (unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) ) |
554 |
if ((endIndex = nextIndex) >= pLength) |
if ((endIndex = nextIndex) >= pLength) |
555 |
throw new REException(getLocalizedMessage("subexpr.no.end"),REException.REG_ESUBREG,nextIndex); |
throw new REException(getLocalizedMessage("subexpr.no.end"),REException.REG_ESUBREG,nextIndex); |
556 |
else if (unit.ch == '(' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) |
else if (unit.ch == '(' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) |
557 |
nested++; |
nested++; |
558 |
else if (unit.ch == ')' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk)) |
else if (unit.ch == ')' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) |
559 |
nested--; |
nested--; |
560 |
|
|
561 |
// endIndex is now position at a ')','\)' |
// endIndex is now position at a ')','\)' |
584 |
// UNMATCHED RIGHT PAREN |
// UNMATCHED RIGHT PAREN |
585 |
// ) or \) throw exception if |
// ) or \) throw exception if |
586 |
// !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) |
// !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) |
587 |
else if (!syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) && ((unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ unit.bk))) { |
else if (!syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) && ((unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))) { |
588 |
throw new REException(getLocalizedMessage("unmatched.paren"),REException.REG_EPAREN,index); |
throw new REException(getLocalizedMessage("unmatched.paren"),REException.REG_EPAREN,index); |
589 |
} |
} |
590 |
|
|
591 |
// START OF LINE OPERATOR |
// START OF LINE OPERATOR |
592 |
// ^ |
// ^ |
593 |
|
|
594 |
else if ((unit.ch == '^') && !unit.bk) { |
else if ((unit.ch == '^') && !(unit.bk || quot)) { |
595 |
addToken(currentToken); |
addToken(currentToken); |
596 |
currentToken = null; |
currentToken = null; |
597 |
addToken(new RETokenStart(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); |
addToken(new RETokenStart(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); |
600 |
// END OF LINE OPERATOR |
// END OF LINE OPERATOR |
601 |
// $ |
// $ |
602 |
|
|
603 |
else if ((unit.ch == '$') && !unit.bk) { |
else if ((unit.ch == '$') && !(unit.bk || quot)) { |
604 |
addToken(currentToken); |
addToken(currentToken); |
605 |
currentToken = null; |
currentToken = null; |
606 |
addToken(new RETokenEnd(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); |
addToken(new RETokenEnd(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null)); |
609 |
// MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null) |
// MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null) |
610 |
// . |
// . |
611 |
|
|
612 |
else if ((unit.ch == '.') && !unit.bk) { |
else if ((unit.ch == '.') && !(unit.bk || quot)) { |
613 |
addToken(currentToken); |
addToken(currentToken); |
614 |
currentToken = new RETokenAny(subIndex,syntax.get(RESyntax.RE_DOT_NEWLINE) || ((cflags & REG_DOT_NEWLINE) > 0),syntax.get(RESyntax.RE_DOT_NOT_NULL)); |
currentToken = new RETokenAny(subIndex,syntax.get(RESyntax.RE_DOT_NEWLINE) || ((cflags & REG_DOT_NEWLINE) > 0),syntax.get(RESyntax.RE_DOT_NOT_NULL)); |
615 |
} |
} |
617 |
// ZERO-OR-MORE REPEAT OPERATOR |
// ZERO-OR-MORE REPEAT OPERATOR |
618 |
// * |
// * |
619 |
|
|
620 |
else if ((unit.ch == '*') && !unit.bk) { |
else if ((unit.ch == '*') && !(unit.bk || quot)) { |
621 |
if (currentToken == null) |
if (currentToken == null) |
622 |
throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
623 |
if (currentToken instanceof RETokenRepeated) |
if (currentToken instanceof RETokenRepeated) |
633 |
// + | \+ depending on RE_BK_PLUS_QM |
// + | \+ depending on RE_BK_PLUS_QM |
634 |
// not available if RE_LIMITED_OPS is set |
// not available if RE_LIMITED_OPS is set |
635 |
|
|
636 |
else if ((unit.ch == '+') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ unit.bk)) { |
else if ((unit.ch == '+') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) { |
637 |
if (currentToken == null) |
if (currentToken == null) |
638 |
throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
639 |
if (currentToken instanceof RETokenRepeated) |
if (currentToken instanceof RETokenRepeated) |
650 |
// not available if RE_LIMITED_OPS is set |
// not available if RE_LIMITED_OPS is set |
651 |
// stingy matching if RE_STINGY_OPS is set and it follows a quantifier |
// stingy matching if RE_STINGY_OPS is set and it follows a quantifier |
652 |
|
|
653 |
else if ((unit.ch == '?') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ unit.bk)) { |
else if ((unit.ch == '?') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) { |
654 |
if (currentToken == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
if (currentToken == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index); |
655 |
|
|
656 |
// Check for stingy matching on RETokenRepeated |
// Check for stingy matching on RETokenRepeated |
817 |
|
|
818 |
} |
} |
819 |
|
|
820 |
private static int getCharUnit(char[] input, int index, CharUnit unit) throws REException { |
private static int getCharUnit(char[] input, int index, CharUnit unit, boolean quot) throws REException { |
821 |
unit.ch = input[index++]; |
unit.ch = input[index++]; |
822 |
if (unit.bk = (unit.ch == '\\')) |
if (unit.bk = (unit.ch == '\\' && (!quot || index >= input.length || input[index] == 'E'))) |
823 |
if (index < input.length) |
if (index < input.length) |
824 |
unit.ch = input[index++]; |
unit.ch = input[index++]; |
825 |
else throw new REException(getLocalizedMessage("ends.with.backslash"),REException.REG_ESCAPE,index); |
else throw new REException(getLocalizedMessage("ends.with.backslash"),REException.REG_ESCAPE,index); |
1293 |
|
|
1294 |
// Read string of digits |
// Read string of digits |
1295 |
do { |
do { |
1296 |
index = getCharUnit(input,index,unit); |
index = getCharUnit(input,index,unit,false); |
1297 |
if (Character.isDigit(unit.ch)) |
if (Character.isDigit(unit.ch)) |
1298 |
buf.append(unit.ch); |
buf.append(unit.ch); |
1299 |
} while ((index != input.length) && Character.isDigit(unit.ch)); |
} while ((index != input.length) && Character.isDigit(unit.ch)); |
1318 |
else if ((unit.ch == ',') && !unit.bk) { |
else if ((unit.ch == ',') && !unit.bk) { |
1319 |
buf = new StringBuffer(); |
buf = new StringBuffer(); |
1320 |
// Read string of digits |
// Read string of digits |
1321 |
while (((index = getCharUnit(input,index,unit)) != input.length) && Character.isDigit(unit.ch)) |
while (((index = getCharUnit(input,index,unit,false)) != input.length) && Character.isDigit(unit.ch)) |
1322 |
buf.append(unit.ch); |
buf.append(unit.ch); |
1323 |
|
|
1324 |
if (!((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk))) |
if (!((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk))) |