diff --git a/src/org/joni/Lexer.java b/src/org/joni/Lexer.java index 695e8332..a441e7fd 100644 --- a/src/org/joni/Lexer.java +++ b/src/org/joni/Lexer.java @@ -956,6 +956,11 @@ private void fetchTokenFor_charProperty() { unfetch(); } } + token.setPropSingleChar(false); + } else if (syntax.op2EscPCharCharProperty()) { + token.type = TokenType.CHAR_PROPERTY; + token.setPropNot(c == 'P'); + token.setPropSingleChar(true); } else { syntaxWarn(Warnings.INVALID_UNICODE_PROPERTY, (char)c); } @@ -1252,13 +1257,18 @@ private void possessiveCheck() { protected final int fetchCharPropertyToCType() { mark(); - while (left()) { - int last = p; + if (token.getPropSingleChar()) { fetch(); - if (c == '}') { - return enc.propertyNameToCType(bytes, _p, last); - } else if (c == '(' || c == ')' || c == '{' || c == '|') { - throw new CharacterPropertyException(ERR_INVALID_CHAR_PROPERTY_NAME, bytes, _p, last); + return enc.propertyNameToCType(bytes, _p, p); + } else { + while (left()) { + int last = p; + fetch(); + if (c == '}') { + return enc.propertyNameToCType(bytes, _p, last); + } else if (c == '(' || c == ')' || c == '{' || c == '|') { + throw new CharacterPropertyException(ERR_INVALID_CHAR_PROPERTY_NAME, bytes, _p, last); + } } } newInternalException(ERR_PARSER_BUG); diff --git a/src/org/joni/Syntax.java b/src/org/joni/Syntax.java index 318fcc66..5bf6af74 100644 --- a/src/org/joni/Syntax.java +++ b/src/org/joni/Syntax.java @@ -286,6 +286,10 @@ public boolean op2QMarkLParenCondition() { return isOp2(OP2_QMARK_LPAREN_CONDITION); } + public boolean op2EscPCharCharProperty() { + return isOp2(OP2_ESC_P_BRACE_CHAR_PROPERTY); + } + /** * BEHAVIOR * @@ -542,7 +546,8 @@ public boolean warnReduntantNestedRepeat() { OP2_PLUS_POSSESSIVE_INTERVAL | OP2_CCLASS_SET_OP | OP2_QMARK_LT_NAMED_GROUP | OP2_ESC_K_NAMED_BACKREF | OP2_ESC_V_VTAB | OP2_ESC_U_HEX4 | - OP2_ESC_P_BRACE_CHAR_PROPERTY ), + OP2_ESC_P_BRACE_CHAR_PROPERTY | + OP2_ESC_P_CHAR_CHAR_PROPERTY), ( GNU_REGEX_BV | DIFFERENT_LEN_ALT_LOOK_BEHIND ), diff --git a/src/org/joni/Token.java b/src/org/joni/Token.java index 321ad91d..06d08f54 100644 --- a/src/org/joni/Token.java +++ b/src/org/joni/Token.java @@ -170,4 +170,11 @@ boolean getPropNot() { void setPropNot(boolean not) { INT2 = not ? 1 : 0; } + + boolean getPropSingleChar() { + return INT3 != 0; + } + void setPropSingleChar(boolean singleChar) { + INT3 = singleChar ? 1 : 0; + } } diff --git a/src/org/joni/constants/SyntaxProperties.java b/src/org/joni/constants/SyntaxProperties.java index d1e2cd39..44a0fea3 100644 --- a/src/org/joni/constants/SyntaxProperties.java +++ b/src/org/joni/constants/SyntaxProperties.java @@ -75,6 +75,7 @@ public interface SyntaxProperties { final int OP2_ESC_H_XDIGIT = (1<<19); /* \h, \H */ final int OP2_INEFFECTIVE_ESCAPE = (1<<20); /* \ */ final int OP2_OPTION_ECMASCRIPT = (1<<21); /* EcmaScript quirks */ + final int OP2_ESC_P_CHAR_CHAR_PROPERTY = (1<<22); /* \pX, \PX */ final int OP2_QMARK_LPAREN_CONDITION = (1<<29); /* (?(cond)yes...|no...) */ diff --git a/test/org/joni/test/TestJava.java b/test/org/joni/test/TestJava.java index 7837852e..e65cc77a 100644 --- a/test/org/joni/test/TestJava.java +++ b/test/org/joni/test/TestJava.java @@ -47,6 +47,12 @@ public void test() throws InterruptedException { x2s("[\\u00e0-\\u00e5]", "\u00c2", 0, 2, Option.IGNORECASE); x2s("[\\u00e2]", "\u00c2", 0, 2, Option.IGNORECASE); x2s("\\u00e2", "\u00c2", 0, 2, Option.IGNORECASE); + + // test \pL, one character char class without curly braces + x2s("\\pL", "A", 0, 1); + ns("\\PL", "A"); + ns("\\pL", "0"); + x2s("\\PL", "0", 0, 1); } public static void main(String[] args) throws Throwable {