diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java index 6990b6adadde..5306672eafca 100644 --- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java +++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java @@ -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; } diff --git a/python/testData/psi/ExtendedSlices.txt b/python/testData/psi/ExtendedSlices.txt index 5c6cfe870022..258ec818e1f6 100644 --- a/python/testData/psi/ExtendedSlices.txt +++ b/python/testData/psi/ExtendedSlices.txt @@ -58,7 +58,7 @@ PyFile:ExtendedSlices.py PsiWhiteSpace('\n') PyAssignmentStatement PySliceExpression - PyTargetExpression: d + PyReferenceExpression: d PsiElement(Py:IDENTIFIER)('d') PsiElement(Py:LBRACKET)('[') PySliceItem diff --git a/python/testData/psi/RangeAsLHS.py b/python/testData/psi/RangeAsLHS.py new file mode 100644 index 000000000000..16c0728c65dd --- /dev/null +++ b/python/testData/psi/RangeAsLHS.py @@ -0,0 +1,2 @@ +foo = [] +foo[:] = [] diff --git a/python/testData/psi/RangeAsLHS.txt b/python/testData/psi/RangeAsLHS.txt new file mode 100644 index 000000000000..996885266bae --- /dev/null +++ b/python/testData/psi/RangeAsLHS.txt @@ -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 + + PsiElement(Py:COLON)(':') + PyEmptyExpression + + PsiElement(Py:RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyListLiteralExpression + PsiElement(Py:LBRACKET)('[') + PsiElement(Py:RBRACKET)(']') \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java index 0ebe1453e7c3..10bf410b7bff 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -314,6 +314,10 @@ public class PythonParsingTest extends ParsingTestCase { doTest(); } + public void testRangeAsLHS() { // PY-6468 + doTest(); + } + public void doTest() { doTest(LanguageLevel.PYTHON25); }