don't parse compound statements after semicolon at top level of file (PY-7660)

This commit is contained in:
Dmitry Jemerov
2012-12-13 22:03:07 +01:00
parent 2b9d27582e
commit 59d5c27308
6 changed files with 55 additions and 3 deletions
@@ -7,6 +7,7 @@ public class ParsingScope {
private boolean myFunction = false;
private boolean myClass = false;
private boolean mySuite = false;
private boolean myAfterSemicolon = false;
public ParsingScope withFunction(boolean flag) {
final ParsingScope result = copy();
@@ -38,6 +39,14 @@ public class ParsingScope {
return mySuite;
}
public boolean isAfterSemicolon() {
return myAfterSemicolon;
}
public void setAfterSemicolon(boolean value) {
myAfterSemicolon = value;
}
protected ParsingScope createInstance() {
return new ParsingScope();
}
@@ -30,10 +30,18 @@ public class PyParser implements PsiParser {
long start = System.currentTimeMillis();
final PsiBuilder.Marker rootMarker = builder.mark();
ParsingContext context = createParsingContext(builder, myLanguageLevel, myFutureFlag);
StatementParsing stmt_parser = context.getStatementParser();
builder.setTokenTypeRemapper(stmt_parser); // must be done before touching the caching lexer with eof() call.
StatementParsing statementParser = context.getStatementParser();
builder.setTokenTypeRemapper(statementParser); // must be done before touching the caching lexer with eof() call.
boolean lastAfterSemicolon = false;
while (!builder.eof()) {
stmt_parser.parseStatement(context.emptyParsingScope());
ParsingScope scope = context.emptyParsingScope();
if (lastAfterSemicolon) {
statementParser.parseSimpleStatement(scope);
}
else {
statementParser.parseStatement(scope);
}
lastAfterSemicolon = scope.isAfterSemicolon();
}
rootMarker.done(root);
ASTNode ast = builder.getTreeBuilt();
@@ -254,8 +254,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
else if (builder.getTokenType() == PyTokenTypes.SEMICOLON) {
if (!scope.isSuite()) {
builder.advanceLexer();
scope.setAfterSemicolon(true);
if (builder.getTokenType() == PyTokenTypes.STATEMENT_BREAK) {
builder.advanceLexer();
scope.setAfterSemicolon(false);
}
}
}
@@ -0,0 +1,2 @@
a = 0; if a:
pass
@@ -0,0 +1,28 @@
PyFile:CompoundStatementAfterSemicolon.py
PyAssignmentStatement
PyTargetExpression: a
PsiElement(Py:IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyNumericLiteralExpression
PsiElement(Py:INTEGER_LITERAL)('0')
PsiElement(Py:SEMICOLON)(';')
PsiWhiteSpace(' ')
PsiElement(Py:IF_KEYWORD)('if')
PsiErrorElement:Statement expected, found Py:IF_KEYWORD
<empty list>
PsiWhiteSpace(' ')
PyExpressionStatement
PyReferenceExpression: a
PsiElement(Py:IDENTIFIER)('a')
PsiErrorElement:End of statement expected
<empty list>
PsiElement(Py:COLON)(':')
PsiErrorElement:Statement expected, found Py:COLON
<empty list>
PsiWhiteSpace('\n ')
PsiErrorElement:Unexpected indent
<empty list>
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
@@ -352,6 +352,9 @@ public class PythonParsingTest extends ParsingTestCase {
doTest(LanguageLevel.PYTHON25);
}
public void testCompoundStatementAfterSemicolon() { // PY-7660
doTest();
}
public void doTest(LanguageLevel languageLevel) {
LanguageLevel prev = myLanguageLevel;