Updated star expression annotator to allow * unpacking in tuples and lists

This commit is contained in:
Andrey Vlasovskikh
2015-09-14 14:45:40 +03:00
parent 045532ee74
commit 57a4d381e3
5 changed files with 50 additions and 10 deletions
@@ -190,7 +190,7 @@ public class ExpressionParsing extends Parsing {
}
if (atToken(PyTokenTypes.EXP)) {
if (!parseStarExpression(false)) {
if (!parseDoubleStarExpression(false)) {
myBuilder.error("expression expected");
expr.done(PyElementTypes.DICT_LITERAL_EXPRESSION);
return;
@@ -248,7 +248,7 @@ public class ExpressionParsing extends Parsing {
while (myBuilder.getTokenType() != PyTokenTypes.RBRACE) {
checkMatches(PyTokenTypes.COMMA, message("PARSE.expected.comma"));
if (atToken(PyTokenTypes.EXP)) {
if (!parseStarExpression(false)) {
if (!parseDoubleStarExpression(false)) {
break;
}
}
@@ -789,8 +789,7 @@ public class ExpressionParsing extends Parsing {
}
private boolean parseStarExpression(boolean isTargetExpression) {
final IElementType tokenType = myBuilder.getTokenType();
if (tokenType == PyTokenTypes.MULT || tokenType == PyTokenTypes.EXP) {
if (atToken(PyTokenTypes.MULT)) {
PsiBuilder.Marker starExpr = myBuilder.mark();
nextToken();
if (!parseBitwiseORExpression(isTargetExpression)) {
@@ -798,7 +797,22 @@ public class ExpressionParsing extends Parsing {
starExpr.drop();
return false;
}
starExpr.done(tokenType == PyTokenTypes.MULT ? PyElementTypes.STAR_EXPRESSION : PyElementTypes.DOUBLE_STAR_EXPRESSION);
starExpr.done(PyElementTypes.STAR_EXPRESSION);
return true;
}
return parseBitwiseORExpression(isTargetExpression);
}
private boolean parseDoubleStarExpression(boolean isTargetExpression) {
if (atToken(PyTokenTypes.EXP)) {
PsiBuilder.Marker starExpr = myBuilder.mark();
nextToken();
if (!parseBitwiseORExpression(isTargetExpression)) {
myBuilder.error(message("PARSE.expected.expression"));
starExpr.drop();
return false;
}
starExpr.done(PyElementTypes.DOUBLE_STAR_EXPRESSION);
return true;
}
return parseBitwiseORExpression(isTargetExpression);
@@ -15,8 +15,9 @@
*/
package com.jetbrains.python.validation;
import com.jetbrains.python.psi.PyStarExpression;
import com.jetbrains.python.psi.PyTargetExpression;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
@@ -25,8 +26,20 @@ public class StarAnnotator extends PyAnnotator {
@Override
public void visitPyStarExpression(PyStarExpression node) {
super.visitPyStarExpression(node);
if (!(node.getExpression() instanceof PyTargetExpression)) {
getHolder().createErrorAnnotation(node, "can use starred expression only as assignment target");
if (!isAssignmentTarget(node) && !isStarUnpacking(node)) {
getHolder().createErrorAnnotation(node, "Can't use starred expression here");
}
}
private static boolean isStarUnpacking(@NotNull PyStarExpression node) {
PsiElement parent = node.getParent();
while (parent instanceof PyParenthesizedExpression) {
parent = parent.getParent();
}
return parent instanceof PyTupleExpression || parent instanceof PyListLiteralExpression;
}
private static boolean isAssignmentTarget(@NotNull PyStarExpression node) {
return node.getExpression() instanceof PyTargetExpression;
}
}
@@ -1 +1 @@
y = (<error descr="can use starred expression only as assignment target">*()</error> for _ in ())
y = (<error descr="Can't use starred expression here">*()</error> for _ in ())
@@ -0,0 +1,9 @@
1, *x
(1, *x)
[1, *x]
if <error descr="Can't use starred expression here">*x</error>:
pass
1 + (<error descr="Can't use starred expression here">*x</error>)
1 + (*x,)
@@ -241,6 +241,10 @@ public class PythonHighlightingTest extends PyTestCase {
doTest(LanguageLevel.PYTHON35, false, false);
}
public void testUnpackingStar() {
doTest(LanguageLevel.PYTHON35, false, false);
}
// ---
private void doTest(final LanguageLevel languageLevel, final boolean checkWarnings, final boolean checkInfos) {
PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel);