diff --git a/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java b/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java index fe23abdd1979..651fc47a6006 100644 --- a/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java +++ b/RegExpSupport/gen/org/intellij/lang/regexp/_RegExLexer.java @@ -1,3 +1,19 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /* The following code was generated by JFlex 1.7.0-SNAPSHOT tweaked for IntelliJ platform */ /* It's an automatically generated code. Do not modify it. */ @@ -288,56 +304,56 @@ class _RegExLexer implements FlexLexer { "\2\44\2\63\1\44\1\63\1\44\14\63\2\42\2\63"+ "\1\64\5\63\1\44\1\63\1\42\6\63\22\44\1\42"+ "\1\63\2\44\2\63\1\44\1\63\1\44\13\63\13\73"+ - "\1\44\10\73\22\44\2\73\2\44\2\73\1\44\1\73"+ - "\1\44\4\73\1\74\6\73\112\0\1\75\62\0\1\76"+ - "\4\0\1\77\53\0\1\100\1\101\1\102\4\103\1\100"+ - "\1\104\1\100\1\104\1\105\2\100\1\104\5\103\2\106"+ - "\3\107\3\110\1\111\2\112\2\113\1\105\1\114\1\105"+ - "\1\115\1\116\1\117\1\120\1\121\1\122\2\100\1\123"+ - "\1\124\1\105\1\100\1\124\1\100\1\124\2\100\1\124"+ - "\4\100\43\0\1\125\27\0\2\42\12\0\1\42\30\0"+ - "\1\42\24\0\2\44\10\0\3\44\6\0\23\44\1\0"+ - "\2\44\2\0\1\44\1\0\1\44\24\0\1\126\4\0"+ - "\1\77\44\0\1\127\6\0\1\100\1\101\1\102\4\103"+ - "\1\100\1\104\1\130\1\104\1\105\2\100\1\104\5\103"+ - "\2\106\3\107\3\110\1\111\2\112\2\113\1\105\1\114"+ - "\1\105\1\115\1\116\1\117\1\120\1\121\1\122\2\100"+ - "\1\123\1\124\1\105\1\100\1\124\1\100\1\124\2\100"+ - "\1\124\4\100\64\0\1\131\20\0\1\65\10\0\22\65"+ - "\2\0\2\65\2\0\1\65\1\0\1\65\26\0\1\66"+ - "\10\0\22\66\2\0\2\66\2\0\1\66\1\0\1\66"+ - "\24\0\1\132\64\0\1\133\33\0\1\134\11\0\1\135"+ - "\1\136\7\0\1\137\2\0\1\137\1\140\1\141\1\142"+ - "\11\0\1\143\61\0\2\101\43\0\1\101\25\0\1\144"+ - "\43\0\1\144\23\0\72\145\1\0\2\146\3\0\1\147"+ - "\16\0\2\146\4\0\3\146\3\0\1\146\1\0\1\146"+ - "\2\0\1\146\24\0\2\150\22\0\2\150\4\0\3\150"+ - "\3\0\1\150\1\0\1\150\2\0\1\150\24\0\1\101"+ - "\1\151\43\0\1\151\75\0\1\152\1\153\70\0\1\154"+ - "\1\155\70\0\1\156\14\0\1\157\71\0\1\160\1\161"+ - "\1\0\5\162\1\0\64\162\2\0\1\163\43\0\1\163"+ - "\24\0\2\164\22\0\2\164\4\0\3\164\3\0\1\164"+ - "\1\0\1\164\2\0\1\164\24\0\2\165\4\0\1\166"+ - "\15\0\2\165\4\0\3\165\3\0\1\165\1\0\1\165"+ - "\2\0\1\165\24\0\2\167\22\0\2\167\4\0\3\167"+ - "\3\0\1\167\1\0\1\167\2\0\1\167\24\0\1\101"+ - "\1\170\43\0\1\170\23\0\5\162\1\171\64\162\2\0"+ - "\1\172\43\0\1\172\24\0\2\173\4\0\1\164\15\0"+ - "\2\173\4\0\3\173\3\0\1\173\1\0\1\173\2\0"+ - "\1\173\24\0\2\174\22\0\2\174\4\0\3\174\3\0"+ - "\1\174\1\0\1\174\2\0\1\174\24\0\2\175\4\0"+ - "\1\164\15\0\2\175\4\0\3\175\3\0\1\175\1\0"+ - "\1\175\2\0\1\175\24\0\2\176\22\0\2\176\4\0"+ - "\3\176\3\0\1\176\1\0\1\176\2\0\1\176\24\0"+ - "\2\177\4\0\1\164\15\0\2\177\4\0\3\177\3\0"+ - "\1\177\1\0\1\177\2\0\1\177\24\0\2\200\4\0"+ - "\1\164\15\0\2\200\4\0\3\200\3\0\1\200\1\0"+ - "\1\200\2\0\1\200\24\0\2\201\4\0\1\164\15\0"+ - "\2\201\4\0\3\201\3\0\1\201\1\0\1\201\2\0"+ - "\1\201\24\0\2\202\4\0\1\164\15\0\2\202\4\0"+ - "\3\202\3\0\1\202\1\0\1\202\2\0\1\202\24\0"+ - "\2\202\4\0\1\166\15\0\2\202\4\0\3\202\3\0"+ - "\1\202\1\0\1\202\2\0\1\202\23\0"; + "\1\44\2\73\1\26\5\73\22\44\2\73\2\44\2\73"+ + "\1\44\1\73\1\44\4\73\1\74\6\73\112\0\1\75"+ + "\62\0\1\76\4\0\1\77\53\0\1\100\1\101\1\102"+ + "\4\103\1\100\1\104\1\100\1\104\1\105\2\100\1\104"+ + "\5\103\2\106\3\107\3\110\1\111\2\112\2\113\1\105"+ + "\1\114\1\105\1\115\1\116\1\117\1\120\1\121\1\122"+ + "\2\100\1\123\1\124\1\105\1\100\1\124\1\100\1\124"+ + "\2\100\1\124\4\100\43\0\1\125\27\0\2\42\12\0"+ + "\1\42\30\0\1\42\24\0\2\44\10\0\3\44\6\0"+ + "\23\44\1\0\2\44\2\0\1\44\1\0\1\44\24\0"+ + "\1\126\4\0\1\77\44\0\1\127\6\0\1\100\1\101"+ + "\1\102\4\103\1\100\1\104\1\130\1\104\1\105\2\100"+ + "\1\104\5\103\2\106\3\107\3\110\1\111\2\112\2\113"+ + "\1\105\1\114\1\105\1\115\1\116\1\117\1\120\1\121"+ + "\1\122\2\100\1\123\1\124\1\105\1\100\1\124\1\100"+ + "\1\124\2\100\1\124\4\100\64\0\1\131\20\0\1\65"+ + "\10\0\22\65\2\0\2\65\2\0\1\65\1\0\1\65"+ + "\26\0\1\66\10\0\22\66\2\0\2\66\2\0\1\66"+ + "\1\0\1\66\24\0\1\132\64\0\1\133\33\0\1\134"+ + "\11\0\1\135\1\136\7\0\1\137\2\0\1\137\1\140"+ + "\1\141\1\142\11\0\1\143\61\0\2\101\43\0\1\101"+ + "\25\0\1\144\43\0\1\144\23\0\72\145\1\0\2\146"+ + "\3\0\1\147\16\0\2\146\4\0\3\146\3\0\1\146"+ + "\1\0\1\146\2\0\1\146\24\0\2\150\22\0\2\150"+ + "\4\0\3\150\3\0\1\150\1\0\1\150\2\0\1\150"+ + "\24\0\1\101\1\151\43\0\1\151\75\0\1\152\1\153"+ + "\70\0\1\154\1\155\70\0\1\156\14\0\1\157\71\0"+ + "\1\160\1\161\1\0\5\162\1\0\64\162\2\0\1\163"+ + "\43\0\1\163\24\0\2\164\22\0\2\164\4\0\3\164"+ + "\3\0\1\164\1\0\1\164\2\0\1\164\24\0\2\165"+ + "\4\0\1\166\15\0\2\165\4\0\3\165\3\0\1\165"+ + "\1\0\1\165\2\0\1\165\24\0\2\167\22\0\2\167"+ + "\4\0\3\167\3\0\1\167\1\0\1\167\2\0\1\167"+ + "\24\0\1\101\1\170\43\0\1\170\23\0\5\162\1\171"+ + "\64\162\2\0\1\172\43\0\1\172\24\0\2\173\4\0"+ + "\1\164\15\0\2\173\4\0\3\173\3\0\1\173\1\0"+ + "\1\173\2\0\1\173\24\0\2\174\22\0\2\174\4\0"+ + "\3\174\3\0\1\174\1\0\1\174\2\0\1\174\24\0"+ + "\2\175\4\0\1\164\15\0\2\175\4\0\3\175\3\0"+ + "\1\175\1\0\1\175\2\0\1\175\24\0\2\176\22\0"+ + "\2\176\4\0\3\176\3\0\1\176\1\0\1\176\2\0"+ + "\1\176\24\0\2\177\4\0\1\164\15\0\2\177\4\0"+ + "\3\177\3\0\1\177\1\0\1\177\2\0\1\177\24\0"+ + "\2\200\4\0\1\164\15\0\2\200\4\0\3\200\3\0"+ + "\1\200\1\0\1\200\2\0\1\200\24\0\2\201\4\0"+ + "\1\164\15\0\2\201\4\0\3\201\3\0\1\201\1\0"+ + "\1\201\2\0\1\201\24\0\2\202\4\0\1\164\15\0"+ + "\2\202\4\0\3\202\3\0\1\202\1\0\1\202\2\0"+ + "\1\202\24\0\2\202\4\0\1\166\15\0\2\202\4\0"+ + "\3\202\3\0\1\202\1\0\1\202\2\0\1\202\23\0"; private static int [] zzUnpackTrans() { int [] result = new int[3248]; diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java index 6883923b57fb..7b9461a10829 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,13 +28,13 @@ import com.intellij.psi.PsiElement; import com.intellij.util.PlatformIcons; import com.intellij.util.ProcessingContext; import com.intellij.util.ui.EmptyIcon; -import org.intellij.lang.regexp.psi.RegExpClass; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import static com.intellij.patterns.PlatformPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.or; /** * @author vnikolaenko @@ -52,7 +52,9 @@ public final class RegExpCompletionContributor extends CompletionContributor { final ElementPattern propertyNamePattern = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); - final ElementPattern bracketExpressionPattern = psiElement().afterLeaf(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN)); + final ElementPattern bracketExpressionPattern = psiElement().afterLeaf( + or(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN), + psiElement(RegExpTT.CARET).afterLeaf(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN)))); extend(CompletionType.BASIC, bracketExpressionPattern, new BracketExpressionCompletionProvider()); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java index 2543360abdb0..938d788b5c56 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParser.java @@ -277,6 +277,9 @@ public class RegExpParser implements PsiParser { private static void parseBracketExpression(PsiBuilder builder) { final PsiBuilder.Marker marker = builder.mark(); builder.advanceLexer(); + if (builder.getTokenType() == RegExpTT.CARET) { + builder.advanceLexer(); + } checkMatches(builder, RegExpTT.NAME, "POSIX character class name expected"); checkMatches(builder, RegExpTT.BRACKET_EXPRESSION_END, "Unclosed POSIX bracket expression"); marker.done(RegExpElementTypes.POSIX_BRACKET_EXPRESSION); diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java index 1abb0324ff6a..1e7238b5a783 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpParserDefinition.java @@ -20,7 +20,9 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.ParserDefinition; import com.intellij.lang.PsiParser; import com.intellij.lexer.Lexer; +import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -28,23 +30,34 @@ import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.tree.TokenSet; +import com.intellij.util.ObjectUtils; import org.intellij.lang.regexp.psi.impl.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.util.EnumSet; public class RegExpParserDefinition implements ParserDefinition { private static final TokenSet COMMENT_TOKENS = TokenSet.create(RegExpTT.COMMENT); + public static final EnumSet DEFAULT_CAPABILITIES = EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES, + RegExpCapability.ALLOW_HORIZONTAL_WHITESPACE_CLASS, + RegExpCapability.UNICODE_CATEGORY_SHORTHAND); + private static EnumSet ourTestingCapabilities = DEFAULT_CAPABILITIES; + @TestOnly + public static void setTestingCapabilities(@Nullable EnumSet capabilities, @NotNull Disposable parentDisposable) { + ourTestingCapabilities = capabilities; + Disposer.register(parentDisposable, () -> ourTestingCapabilities = null); + } + @NotNull public Lexer createLexer(Project project) { - return new RegExpLexer(EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES, - RegExpCapability.ALLOW_HORIZONTAL_WHITESPACE_CLASS, - RegExpCapability.UNICODE_CATEGORY_SHORTHAND)); + return new RegExpLexer(ObjectUtils.notNull(ourTestingCapabilities, DEFAULT_CAPABILITIES)); } public PsiParser createParser(Project project) { - return new RegExpParser(); + return new RegExpParser(ObjectUtils.notNull(ourTestingCapabilities, DEFAULT_CAPABILITIES)); } public IFileElementType getFileNodeType() { diff --git a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex index cc7cefa3e5ed..0ffe05388060 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex +++ b/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex @@ -284,6 +284,7 @@ HEX_CHAR=[0-9a-fA-F] } { + "^" { return RegExpTT.CARET; } {NAME} { return RegExpTT.NAME; } ":" {RBRACKET} { yybegin(CLASS2); return RegExpTT.BRACKET_EXPRESSION_END; } {ANY} { return RegExpTT.BAD_CHARACTER; } diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java index 5a55abaca62c..f9da6ee242e2 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.util.ArrayUtil; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; /** * Created by IntelliJ IDEA. @@ -40,6 +41,26 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { return Character.toUpperCase(testName.charAt(0)) + testName.substring(1) + "Expected" + ".regexp"; } + public void testPosixBracketExpression() { + EnumSet capabilities = RegExpParserDefinition.DEFAULT_CAPABILITIES.clone(); + capabilities.add(RegExpCapability.POSIX_BRACKET_EXPRESSIONS); + RegExpParserDefinition.setTestingCapabilities(capabilities, getTestRootDisposable()); + + myFixture.configureByText(RegExpFileType.INSTANCE, "[[:alp"); + myFixture.completeBasic(); + myFixture.checkResult("[[:alpha:]"); + } + + public void testNegatePosixBracketExpression() { + EnumSet capabilities = RegExpParserDefinition.DEFAULT_CAPABILITIES.clone(); + capabilities.add(RegExpCapability.POSIX_BRACKET_EXPRESSIONS); + RegExpParserDefinition.setTestingCapabilities(capabilities, getTestRootDisposable()); + + myFixture.configureByText(RegExpFileType.INSTANCE, "[[:^alp"); + myFixture.completeBasic(); + myFixture.checkResult("[[:^alpha:]"); + } + public void testBackSlashVariants() throws Throwable { doBackSlashVariantsTest(); } diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpLexerTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpLexerTest.java index 0c687b36bf7f..2647914b8da2 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpLexerTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpLexerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,16 @@ public class RegExpLexerTest extends LexerTestCase { "CLASS_END (']')", lexer); } + public void testNegatedPosixBracketExpression() { + final RegExpLexer lexer = new RegExpLexer(EnumSet.of(RegExpCapability.POSIX_BRACKET_EXPRESSIONS)); + doTest("[[:^xdigit:]]", "CLASS_BEGIN ('[')\n" + + "BRACKET_EXPRESSION_BEGIN ('[:')\n" + + "CARET ('^')\n" + + "NAME ('xdigit')\n" + + "BRACKET_EXPRESSION_END (':]')\n" + + "CLASS_END (']')", lexer); + } + @Override protected Lexer createLexer() { return null; diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java index 6c6430ac7149..bb7e231ef762 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParsingTest.java @@ -231,6 +231,7 @@ public class RegExpParsingTest extends ParsingTestCase { public void testNamedchars8() throws IOException { doCodeTest("\\p{Digit}+"); } public void testNamedchars9() throws IOException { doCodeTest("[:xdigit:]+"); } public void testNamedchars10() throws IOException { doCodeTest("\\p{unknown}+"); } + public void testNamedchars11() throws IOException { doCodeTest("[:^xdigit:]+"); } public void testBackrefs1() throws IOException { doCodeTest("(ac*)c*d[ac]*\\1"); } public void testBackrefs2() throws IOException { doCodeTest("(.)=\\1"); } diff --git a/RegExpSupport/testData/psi/Namedchars11.txt b/RegExpSupport/testData/psi/Namedchars11.txt new file mode 100644 index 000000000000..9113b2347475 --- /dev/null +++ b/RegExpSupport/testData/psi/Namedchars11.txt @@ -0,0 +1,28 @@ +REGEXP_FILE + RegExpPatternImpl: <[:^xdigit:]+> + RegExpBranchImpl: <[:^xdigit:]+> + RegExpClosureImpl: <[:^xdigit:]+> + RegExpClassImpl: <[:^xdigit:]> + PsiElement(CLASS_BEGIN)('[') + RegExpUnionImpl: <:^xdigit:> + RegExpCharImpl: <:> + PsiElement(CHARACTER)(':') + RegExpCharImpl: <^> + PsiElement(CARET)('^') + RegExpCharImpl: + PsiElement(CHARACTER)('x') + RegExpCharImpl: + PsiElement(CHARACTER)('d') + RegExpCharImpl: + PsiElement(CHARACTER)('i') + RegExpCharImpl: + PsiElement(CHARACTER)('g') + RegExpCharImpl: + PsiElement(CHARACTER)('i') + RegExpCharImpl: + PsiElement(CHARACTER)('t') + RegExpCharImpl: <:> + PsiElement(CHARACTER)(':') + PsiElement(CLASS_END)(']') + RegExpQuantifierImpl: <+> + PsiElement(PLUS)('+') \ No newline at end of file