From dd477bf1adca9ab9d7f18f9d6247ce6bc5a6cfde Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Mon, 12 Dec 2011 11:46:17 +0400 Subject: [PATCH] regexes in reference expressions --- .../expressions/arguments/ArgumentList.java | 32 ++++++------ .../arithmetic/PathExpression.java | 11 ++-- ...DollarSlashRegexConstructorExpression.java | 50 +++++++------------ .../primary/PrimaryExpression.java | 11 ++-- .../primary/RegexConstructorExpression.java | 42 +++++++--------- .../path/GrPropertySelectionImpl.java | 4 +- .../lang/parser/ExpressionsParsingTest.groovy | 3 ++ .../groovy/expressions/path/regexp.test | 44 ++++++++++++++++ .../groovy/expressions/regex/regex10.test | 2 +- .../groovy/expressions/regex/regex22.test | 24 +++++++++ .../groovy/expressions/regex/regex23.test | 24 +++++++++ .../groovy/expressions/regex/regex8.test | 2 +- .../groovy/expressions/regex/regex9.test | 2 +- 13 files changed, 164 insertions(+), 87 deletions(-) create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/path/regexp.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/regex/regex22.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/regex/regex23.test diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java index ffe41c5501ad..222564b51b1d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arguments/ArgumentList.java @@ -115,11 +115,12 @@ public class ArgumentList implements GroovyElementTypes { marker.done(ARGUMENT_LABEL); return true; } - else if (ParserUtils.lookAhead(builder, mIDENT, mCOLON) || - TokenSets.KEYWORDS.contains(builder.getTokenType()) || - mSTRING_LITERAL.equals(builder.getTokenType()) || - mGSTRING_LITERAL.equals(builder.getTokenType()) || - mREGEX_LITERAL.equals(builder.getTokenType())) { + + final IElementType type = builder.getTokenType(); + if (ParserUtils.lookAhead(builder, mIDENT, mCOLON) || + TokenSets.KEYWORDS.contains(type) || + mSTRING_LITERAL.equals(type) || + mGSTRING_LITERAL.equals(type)) { builder.advanceLexer(); if (mCOLON.equals(builder.getTokenType())) { marker.done(ARGUMENT_LABEL); @@ -130,12 +131,14 @@ public class ArgumentList implements GroovyElementTypes { return false; } } - else if (mGSTRING_BEGIN.equals(builder.getTokenType()) || - mREGEX_BEGIN.equals(builder.getTokenType()) || - TokenSets.NUMBERS.contains(builder.getTokenType()) || - mLBRACK.equals(builder.getTokenType()) || - mLPAREN.equals(builder.getTokenType()) || - mLCURLY.equals(builder.getTokenType())) { + + if (mGSTRING_BEGIN.equals(type) || + mREGEX_BEGIN.equals(type) || + mDOLLAR_SLASH_REGEX_BEGIN.equals(type) || + TokenSets.NUMBERS.contains(type) || + mLBRACK.equals(type) || + mLPAREN.equals(type) || + mLCURLY.equals(type)) { PrimaryExpression.parsePrimaryExpression(builder, parser); if (mCOLON.equals(builder.getTokenType())) { marker.done(ARGUMENT_LABEL); @@ -146,11 +149,8 @@ public class ArgumentList implements GroovyElementTypes { return false; } } - else { - marker.drop(); - return false; - } + marker.drop(); + return false; } - } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java index 4125cb347519..45500d00a401 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PathExpression.java @@ -26,6 +26,7 @@ import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arguments.ArgumentList; +import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.DollarSlashRegexConstructorExpression; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.PrimaryExpression; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.RegexConstructorExpression; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.StringConstructorExpression; @@ -227,17 +228,15 @@ public class PathExpression implements GroovyElementTypes { } final IElementType tokenType = builder.getTokenType(); - if (mREGEX_LITERAL.equals(tokenType)) { - ParserUtils.eatElement(builder, REGEX); - return PATH_PROPERTY_REFERENCE; - } if (mGSTRING_BEGIN.equals(tokenType)) { StringConstructorExpression.parse(builder, parser); return PATH_PROPERTY_REFERENCE; } if (mREGEX_BEGIN.equals(tokenType)) { - RegexConstructorExpression.parse(builder, parser); - return PATH_PROPERTY_REFERENCE; + return RegexConstructorExpression.parse(builder, parser) ? PATH_PROPERTY_REFERENCE : REFERENCE_EXPRESSION; + } + if (mDOLLAR_SLASH_REGEX_BEGIN.equals(tokenType)) { + return DollarSlashRegexConstructorExpression.parse(builder, parser) ? PATH_PROPERTY_REFERENCE : REFERENCE_EXPRESSION; } if (mLCURLY.equals(tokenType)) { OpenOrClosableBlock.parseOpenBlock(builder, parser); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/DollarSlashRegexConstructorExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/DollarSlashRegexConstructorExpression.java index d719090cca4e..3a745d324708 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/DollarSlashRegexConstructorExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/DollarSlashRegexConstructorExpression.java @@ -16,52 +16,40 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary; import com.intellij.lang.PsiBuilder; +import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.plugins.groovy.GroovyBundle; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.PathExpression; import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_BEGIN; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_END; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mIDENT; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLCURLY; -import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.GSTRING_INJECTION; +import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.REGEX; /** * @author Max Medvedev */ public class DollarSlashRegexConstructorExpression { - public static GroovyElementType parse(PsiBuilder builder, GroovyParser parser) { + private static final Logger LOG = Logger.getInstance(DollarSlashRegexConstructorExpression.class); - PsiBuilder.Marker sMarker = builder.mark(); - if (ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_BEGIN)) { + public static boolean parse(PsiBuilder builder, GroovyParser parser) { + PsiBuilder.Marker marker = builder.mark(); + final boolean result = ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_BEGIN); + LOG.assertTrue(result); + + boolean inj = false; + ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_CONTENT); + while (parseInjection(builder, parser)) { + inj = true; ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_CONTENT); - if (!parseInjection(builder, parser)) { - if (!ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_END)) { - builder.error(GroovyBundle.message("dollar.slash.end.expected")); - } - sMarker.done(REGEX); - return REGEX; - } - else { - while (ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_CONTENT)) { - if (!parseInjection(builder, parser)) break; - } - if (!ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_END)) { - builder.error(GroovyBundle.message("dollar.slash.end.expected")); - } - sMarker.done(REGEX); - return REGEX; - } } - else { - sMarker.drop(); - return WRONGWAY; + + if (!ParserUtils.getToken(builder, mDOLLAR_SLASH_REGEX_END)) { + builder.error(GroovyBundle.message("dollar.slash.end.expected")); } + marker.done(REGEX); + return inj; } /** diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java index bec77d88e5e2..eb04353f7a2f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/PrimaryExpression.java @@ -69,10 +69,12 @@ public class PrimaryExpression implements GroovyElementTypes { return StringConstructorExpression.parse(builder, parser); } if (mREGEX_BEGIN == tokenType) { - return RegexConstructorExpression.parse(builder, parser); + RegexConstructorExpression.parse(builder, parser); + return REGEX; } if (mDOLLAR_SLASH_REGEX_BEGIN == tokenType) { - return DollarSlashRegexConstructorExpression.parse(builder, parser); + DollarSlashRegexConstructorExpression.parse(builder, parser); + return REGEX; } if (mLBRACK == tokenType) { return ListOrMapConstructorExpression.parse(builder, parser); @@ -83,10 +85,7 @@ public class PrimaryExpression implements GroovyElementTypes { if (mLCURLY == tokenType) { return OpenOrClosableBlock.parseClosableBlock(builder, parser); } - if (tokenType == mSTRING_LITERAL || - tokenType == mGSTRING_LITERAL || - tokenType == mREGEX_LITERAL || - tokenType == mDOLLAR_SLASH_REGEX_LITERAL) { + if (tokenType == mSTRING_LITERAL || tokenType == mGSTRING_LITERAL) { return ParserUtils.eatElement(builder, literalsAsRefExprs ? REFERENCE_EXPRESSION : LITERAL); } if (TokenSets.CONSTANTS.contains(tokenType)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/RegexConstructorExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/RegexConstructorExpression.java index d453fa433af0..b74b218412a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/RegexConstructorExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/primary/RegexConstructorExpression.java @@ -17,8 +17,8 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary; import com.intellij.lang.PsiBuilder; +import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.plugins.groovy.GroovyBundle; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock; @@ -29,34 +29,28 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; * @author ilyas */ public class RegexConstructorExpression implements GroovyElementTypes { + private static final Logger LOG = Logger.getInstance(RegexConstructorExpression.class); - public static GroovyElementType parse(PsiBuilder builder, GroovyParser parser) { + /** + * @return true if there are any injections + */ + public static boolean parse(PsiBuilder builder, GroovyParser parser) { + PsiBuilder.Marker marker = builder.mark(); + final boolean result = ParserUtils.getToken(builder, mREGEX_BEGIN); + LOG.assertTrue(result); - PsiBuilder.Marker sMarker = builder.mark(); - if (ParserUtils.getToken(builder, mREGEX_BEGIN)) { + boolean inj = false; + ParserUtils.getToken(builder, mREGEX_CONTENT); + while (parseInjection(builder, parser)) { + inj = true; ParserUtils.getToken(builder, mREGEX_CONTENT); - if (!parseInjection(builder, parser)) { - if (!ParserUtils.getToken(builder, mREGEX_END)) { - builder.error(GroovyBundle.message("regex.end.expected")); - } - sMarker.done(REGEX); - return REGEX; - } - else { - while (ParserUtils.getToken(builder, mREGEX_CONTENT)) { - if (!parseInjection(builder, parser)) break; - } - if (!ParserUtils.getToken(builder, mREGEX_END)) { - builder.error(GroovyBundle.message("regex.end.expected")); - } - sMarker.done(REGEX); - return REGEX; - } } - else { - sMarker.drop(); - return WRONGWAY; + + if (!ParserUtils.getToken(builder, mREGEX_END)) { + builder.error(GroovyBundle.message("regex.end.expected")); } + marker.done(REGEX); + return inj; } /** diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrPropertySelectionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrPropertySelectionImpl.java index 0cc928b8e0d5..0e35dbef859f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrPropertySelectionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrPropertySelectionImpl.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path; import com.intellij.lang.ASTNode; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; @@ -30,6 +31,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrRefer * @author ilyas */ public class GrPropertySelectionImpl extends GrReferenceExpressionImpl implements GrPropertySelection { + private static final Logger LOG = Logger.getInstance(GrPropertySelectionImpl.class); public GrPropertySelectionImpl(@NotNull ASTNode node) { super(node); @@ -70,7 +72,7 @@ public class GrPropertySelectionImpl extends GrReferenceExpressionImpl implement @Override public PsiElement getReferenceNameElement() { final PsiElement last = getLastChild(); - assert last != null; + LOG.assertTrue(last!=null); return last; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 7a3d0255e208..978360b13604 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -133,6 +133,7 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase { public void testpath$path8() throws Throwable { doTest(); } public void testpath$path9() throws Throwable { doTest(); } public void testpath$path10() throws Throwable {doTest(); } + public void testpath$regexp() {doTest()} public void testpath$typeVsExpr() {doTest();} public void testreferences$ref1() throws Throwable { doTest(); } public void testreferences$ref2() throws Throwable { doTest(); } @@ -159,6 +160,8 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase { public void testregex$regex2() throws Throwable { doTest(); } public void testregex$regex20() throws Throwable { doTest(); } public void testregex$regex21() throws Throwable { doTest(); } + public void testregex$regex22() throws Throwable { doTest(); } + public void testregex$regex23() throws Throwable { doTest(); } public void testregex$regex3() throws Throwable { doTest(); } public void testregex$regex33() throws Throwable { doTest(); } public void testregex$regex4() throws Throwable { doTest(); } diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/path/regexp.test b/plugins/groovy/testdata/parsing/groovy/expressions/path/regexp.test new file mode 100644 index 000000000000..330bf7ac6e3b --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/path/regexp.test @@ -0,0 +1,44 @@ +a.$/dfg/$./fg/."sfg"./${a}/.$/df$g/$ +----- +Groovy script + Property selection + Property selection + Reference expression + Reference expression + Reference expression + Reference expression + PsiElement(identifier)('a') + PsiElement(.)('.') + Compound regular expression + PsiElement($/ regex begin)('$/') + PsiElement($/ regex content)('dfg') + PsiElement($/ regex end)('/$') + PsiElement(.)('.') + Compound regular expression + PsiElement(regex begin)('/') + PsiElement(regex content)('fg') + PsiElement(regex end)('/') + PsiElement(.)('.') + PsiElement(Gstring)('"sfg"') + PsiElement(.)('.') + Compound regular expression + PsiElement(regex begin)('/') + GString injection + PsiElement($)('$') + Closable block + PsiElement({)('{') + Parameter list + + Reference expression + PsiElement(identifier)('a') + PsiElement(})('}') + PsiElement(regex end)('/') + PsiElement(.)('.') + Compound regular expression + PsiElement($/ regex begin)('$/') + PsiElement($/ regex content)('df') + GString injection + PsiElement($)('$') + Reference expression + PsiElement(identifier)('g') + PsiElement($/ regex end)('/$') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex10.test b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex10.test index f0989133fb9d..d7802962bb1d 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex10.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex10.test @@ -36,7 +36,7 @@ Groovy script Parameter list Method call - Property selection + Reference expression Reference expression PsiElement(identifier)('frg') PsiElement(.)('.') diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex22.test b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex22.test new file mode 100644 index 000000000000..f13ddd70ad61 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex22.test @@ -0,0 +1,24 @@ +/${1}${2}/ +----- +Groovy script + Compound regular expression + PsiElement(regex begin)('/') + GString injection + PsiElement($)('$') + Closable block + PsiElement({)('{') + Parameter list + + Literal + PsiElement(Integer)('1') + PsiElement(})('}') + GString injection + PsiElement($)('$') + Closable block + PsiElement({)('{') + Parameter list + + Literal + PsiElement(Integer)('2') + PsiElement(})('}') + PsiElement(regex end)('/') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex23.test b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex23.test new file mode 100644 index 000000000000..00e27cd6ae22 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex23.test @@ -0,0 +1,24 @@ +$/${1}${2}/$ +----- +Groovy script + Compound regular expression + PsiElement($/ regex begin)('$/') + GString injection + PsiElement($)('$') + Closable block + PsiElement({)('{') + Parameter list + + Literal + PsiElement(Integer)('1') + PsiElement(})('}') + GString injection + PsiElement($)('$') + Closable block + PsiElement({)('{') + Parameter list + + Literal + PsiElement(Integer)('2') + PsiElement(})('}') + PsiElement($/ regex end)('/$') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex8.test b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex8.test index 2f289315bb04..601e09b3cd4c 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex8.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex8.test @@ -52,7 +52,7 @@ Groovy script Parameter list Method call - Property selection + Reference expression Reference expression PsiElement(identifier)('frg') PsiElement(.)('.') diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex9.test b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex9.test index 8a222ba86109..14231157069a 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex9.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/regex/regex9.test @@ -53,7 +53,7 @@ Groovy script Parameter list Method call - Property selection + Reference expression Reference expression PsiElement(identifier)('frg') PsiElement(.)('.')