From 09bd5b323a8e435ebe24a3aee812ae1c19225278 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 26 Feb 2014 16:26:12 +0400 Subject: [PATCH] Fixed error recovery after empty blocks with no indent --- .../python/parsing/StatementParsing.java | 11 ++--- .../psi/EmptyBlockInFunctionBeforeFunction.py | 6 +++ .../EmptyBlockInFunctionBeforeFunction.txt | 41 +++++++++++++++++++ .../jetbrains/python/PythonParsingTest.java | 4 ++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 python/testData/psi/EmptyBlockInFunctionBeforeFunction.py create mode 100644 python/testData/psi/EmptyBlockInFunctionBeforeFunction.txt diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java index 655fadccf52c..b23899a929f2 100644 --- a/python/src/com/jetbrains/python/parsing/StatementParsing.java +++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java @@ -809,10 +809,8 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { myBuilder.advanceLexer(); final PsiBuilder.Marker marker = myBuilder.mark(); - if (myBuilder.getTokenType() != PyTokenTypes.INDENT) { - myBuilder.error("Indent expected"); - } - else { + final boolean indentFound = myBuilder.getTokenType() == PyTokenTypes.INDENT; + if (indentFound) { myBuilder.advanceLexer(); if (myBuilder.eof()) { myBuilder.error("Indented block expected"); @@ -823,13 +821,16 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { } } } + else { + myBuilder.error("Indent expected"); + } marker.done(PyElementTypes.STATEMENT_LIST); marker.setCustomEdgeTokenBinders(LeadingCommentsBinder.INSTANCE, FollowingCommentBinder.INSTANCE); if (endMarker != null) { endMarker.done(elType); } - if (!myBuilder.eof()) { + if (indentFound && !myBuilder.eof()) { checkMatches(PyTokenTypes.DEDENT, "Dedent expected"); } // NOTE: the following line advances the PsiBuilder lexer and thus diff --git a/python/testData/psi/EmptyBlockInFunctionBeforeFunction.py b/python/testData/psi/EmptyBlockInFunctionBeforeFunction.py new file mode 100644 index 000000000000..5248b7d54dab --- /dev/null +++ b/python/testData/psi/EmptyBlockInFunctionBeforeFunction.py @@ -0,0 +1,6 @@ +def foo(xs): + for x in xs: + + +def bar(): + pass diff --git a/python/testData/psi/EmptyBlockInFunctionBeforeFunction.txt b/python/testData/psi/EmptyBlockInFunctionBeforeFunction.txt new file mode 100644 index 000000000000..4ee3e5c162af --- /dev/null +++ b/python/testData/psi/EmptyBlockInFunctionBeforeFunction.txt @@ -0,0 +1,41 @@ +PyFile:EmptyBlockInFunctionBeforeFunction.py + PyFunction('foo') + PsiElement(Py:DEF_KEYWORD)('def') + PsiWhiteSpace(' ') + PsiElement(Py:IDENTIFIER)('foo') + PyParameterList + PsiElement(Py:LPAR)('(') + PyNamedParameter('xs') + PsiElement(Py:IDENTIFIER)('xs') + PsiElement(Py:RPAR)(')') + PsiElement(Py:COLON)(':') + PsiWhiteSpace('\n ') + PyStatementList + PyForStatement + PyForPart + PsiElement(Py:FOR_KEYWORD)('for') + PsiWhiteSpace(' ') + PyTargetExpression: x + PsiElement(Py:IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(Py:IN_KEYWORD)('in') + PsiWhiteSpace(' ') + PyReferenceExpression: xs + PsiElement(Py:IDENTIFIER)('xs') + PsiElement(Py:COLON)(':') + PyStatementList + PsiErrorElement:Indent expected + + PsiWhiteSpace('\n\n\n') + PyFunction('bar') + PsiElement(Py:DEF_KEYWORD)('def') + PsiWhiteSpace(' ') + PsiElement(Py:IDENTIFIER)('bar') + PyParameterList + PsiElement(Py:LPAR)('(') + PsiElement(Py:RPAR)(')') + PsiElement(Py:COLON)(':') + PsiWhiteSpace('\n ') + PyStatementList + PyPassStatement + PsiElement(Py:PASS_KEYWORD)('pass') \ 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 f50257cfe0f1..3c7819fd715f 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -447,6 +447,10 @@ public class PythonParsingTest extends ParsingTestCase { doTest(LanguageLevel.PYTHON33); } + public void testEmptyBlockInFunctionBeforeFunction() { + doTest(); + } + public void doTest(LanguageLevel languageLevel) { LanguageLevel prev = myLanguageLevel; myLanguageLevel = languageLevel;