a reference in a slice expression in the LHS of an assignment is always a reference expression, not a target expression (PY-6468)

This commit is contained in:
Dmitry Jemerov
2012-05-04 18:32:18 +02:00
parent c63b907727
commit 95350dbe11
5 changed files with 52 additions and 18 deletions
@@ -288,12 +288,12 @@ public class ExpressionParsing extends Parsing {
public boolean parseMemberExpression(boolean isTargetExpression) {
// in sequence a.b.... .c all members but last are always references, and the last may be target.
boolean recast_first_identifier = false;
boolean recast_qualifier = false;
boolean recastFirstIdentifier = false;
boolean recastQualifier = false;
do {
boolean first_identifier_is_target = isTargetExpression && ! recast_first_identifier;
boolean firstIdentifierIsTarget = isTargetExpression && ! recastFirstIdentifier;
PsiBuilder.Marker expr = myBuilder.mark();
if (!parsePrimaryExpression(first_identifier_is_target)) {
if (!parsePrimaryExpression(firstIdentifierIsTarget)) {
expr.drop();
return false;
}
@@ -301,15 +301,14 @@ public class ExpressionParsing extends Parsing {
while (true) {
final IElementType tokenType = myBuilder.getTokenType();
if (tokenType == PyTokenTypes.DOT) {
if (first_identifier_is_target) {
recast_first_identifier = true;
if (firstIdentifierIsTarget) {
recastFirstIdentifier = true;
expr.rollbackTo();
break;
}
else recast_first_identifier = false;
myBuilder.advanceLexer();
checkMatches(PyTokenTypes.IDENTIFIER, message("PARSE.expected.name"));
if (isTargetExpression && ! recast_qualifier && !atAnyOfTokens(PyTokenTypes.DOT, PyTokenTypes.LPAR, PyTokenTypes.LBRACKET)) {
if (isTargetExpression && ! recastQualifier && !atAnyOfTokens(PyTokenTypes.DOT, PyTokenTypes.LPAR, PyTokenTypes.LBRACKET)) {
expr.done(PyElementTypes.TARGET_EXPRESSION);
}
else {
@@ -354,25 +353,25 @@ public class ExpressionParsing extends Parsing {
sliceItemStart.drop();
checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
expr.done(PyElementTypes.SUBSCRIPTION_EXPRESSION);
if (isTargetExpression && ! recast_qualifier) {
recast_first_identifier = true; // subscription is always a reference
recast_qualifier = true; // recast non-first qualifiers too
expr.rollbackTo();
break;
}
}
}
if (isTargetExpression && ! recastQualifier) {
recastFirstIdentifier = true; // subscription is always a reference
recastQualifier = true; // recast non-first qualifiers too
expr.rollbackTo();
break;
}
expr = expr.precede();
}
else {
expr.drop();
break;
}
recast_first_identifier = false; // it is true only after a break; normal flow always unsets it.
// recast_qualifier is untouched, it remembers whether qualifiers were already recast
recastFirstIdentifier = false; // it is true only after a break; normal flow always unsets it.
// recastQualifier is untouched, it remembers whether qualifiers were already recast
}
}
while (recast_first_identifier);
while (recastFirstIdentifier);
return true;
}
+1 -1
View File
@@ -58,7 +58,7 @@ PyFile:ExtendedSlices.py
PsiWhiteSpace('\n')
PyAssignmentStatement
PySliceExpression
PyTargetExpression: d
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
PySliceItem
+2
View File
@@ -0,0 +1,2 @@
foo = []
foo[:] = []
+29
View File
@@ -0,0 +1,29 @@
PyFile:RangeAsLHS.py
PyAssignmentStatement
PyTargetExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiWhiteSpace(' ')
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyListLiteralExpression
PsiElement(Py:LBRACKET)('[')
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyAssignmentStatement
PySliceExpression
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:LBRACKET)('[')
PySliceItem
PyEmptyExpression
<empty list>
PsiElement(Py:COLON)(':')
PyEmptyExpression
<empty list>
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace(' ')
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyListLiteralExpression
PsiElement(Py:LBRACKET)('[')
PsiElement(Py:RBRACKET)(']')
@@ -314,6 +314,10 @@ public class PythonParsingTest extends ParsingTestCase {
doTest();
}
public void testRangeAsLHS() { // PY-6468
doTest();
}
public void doTest() {
doTest(LanguageLevel.PYTHON25);
}