Regexp: allow negate posix bracket expressions

This commit is contained in:
Alexander Zolotov
2016-08-04 01:24:40 +03:00
parent f1f8db870e
commit 878c7a09d7
9 changed files with 154 additions and 59 deletions
@@ -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];
@@ -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<PsiElement> propertyNamePattern = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern));
extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider());
final ElementPattern<PsiElement> bracketExpressionPattern = psiElement().afterLeaf(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN));
final ElementPattern<PsiElement> bracketExpressionPattern = psiElement().afterLeaf(
or(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN),
psiElement(RegExpTT.CARET).afterLeaf(psiElement(RegExpTT.BRACKET_EXPRESSION_BEGIN))));
extend(CompletionType.BASIC, bracketExpressionPattern, new BracketExpressionCompletionProvider());
}
@@ -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);
@@ -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<RegExpCapability> DEFAULT_CAPABILITIES = EnumSet.of(RegExpCapability.NESTED_CHARACTER_CLASSES,
RegExpCapability.ALLOW_HORIZONTAL_WHITESPACE_CLASS,
RegExpCapability.UNICODE_CATEGORY_SHORTHAND);
private static EnumSet<RegExpCapability> ourTestingCapabilities = DEFAULT_CAPABILITIES;
@TestOnly
public static void setTestingCapabilities(@Nullable EnumSet<RegExpCapability> 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() {
@@ -284,6 +284,7 @@ HEX_CHAR=[0-9a-fA-F]
}
<BRACKET_EXPRESSION> {
"^" { return RegExpTT.CARET; }
{NAME} { return RegExpTT.NAME; }
":" {RBRACKET} { yybegin(CLASS2); return RegExpTT.BRACKET_EXPRESSION_END; }
{ANY} { return RegExpTT.BAD_CHARACTER; }
@@ -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<RegExpCapability> capabilities = RegExpParserDefinition.DEFAULT_CAPABILITIES.clone();
capabilities.add(RegExpCapability.POSIX_BRACKET_EXPRESSIONS);
RegExpParserDefinition.setTestingCapabilities(capabilities, getTestRootDisposable());
myFixture.configureByText(RegExpFileType.INSTANCE, "[[:alp<caret>");
myFixture.completeBasic();
myFixture.checkResult("[[:alpha:]<caret>");
}
public void testNegatePosixBracketExpression() {
EnumSet<RegExpCapability> capabilities = RegExpParserDefinition.DEFAULT_CAPABILITIES.clone();
capabilities.add(RegExpCapability.POSIX_BRACKET_EXPRESSIONS);
RegExpParserDefinition.setTestingCapabilities(capabilities, getTestRootDisposable());
myFixture.configureByText(RegExpFileType.INSTANCE, "[[:^alp<caret>");
myFixture.completeBasic();
myFixture.checkResult("[[:^alpha:]<caret>");
}
public void testBackSlashVariants() throws Throwable {
doBackSlashVariantsTest();
}
@@ -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;
@@ -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"); }
@@ -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: <x>
PsiElement(CHARACTER)('x')
RegExpCharImpl: <d>
PsiElement(CHARACTER)('d')
RegExpCharImpl: <i>
PsiElement(CHARACTER)('i')
RegExpCharImpl: <g>
PsiElement(CHARACTER)('g')
RegExpCharImpl: <i>
PsiElement(CHARACTER)('i')
RegExpCharImpl: <t>
PsiElement(CHARACTER)('t')
RegExpCharImpl: <:>
PsiElement(CHARACTER)(':')
PsiElement(CLASS_END)(']')
RegExpQuantifierImpl: <+>
PsiElement(PLUS)('+')