From 90eb9c443ba5cd826f856b269cbf5ae1756f69b1 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 27 Jan 2011 20:01:38 +0300 Subject: [PATCH] Recovery for expressions. Bug with return inside if fixed --- grammar/src/expressions.grm | 2 + .../lang/parsing/JetExpressionParsing.java | 65 +++++++++++++++++-- idea/testData/psi/Expressions_ERR.jet | 9 +++ idea/testData/psi/Expressions_ERR.txt | 58 +++++++++++++++++ idea/testData/psi/When_ERR.txt | 5 +- 5 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 idea/testData/psi/Expressions_ERR.jet create mode 100644 idea/testData/psi/Expressions_ERR.txt diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index 5ce838a40c7..a82cd991db2 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -76,6 +76,7 @@ postfixUnaryExpression : memberAccess postfixUnaryOperation* ; +// !!! When you add here, remember to update the FIRST set in the parser atomicExpression : "(" expression ")" // see tupleLiteral : literalConstant @@ -92,6 +93,7 @@ atomicExpression : jump : loop : SimpleName + : FieldName : "namespace" // for the root namespace ; diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 2e023b4f980..00c3f690cab 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -29,6 +29,57 @@ public class JetExpressionParsing extends AbstractJetParsing { COLON ); + private static final TokenSet EXPRESSION_FIRST = TokenSet.orSet(TokenSet.create( + // Prefix + MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, LBRACKET, + // Atomic + + LPAR, // parenthesized + + // literal constant + TRUE_KEYWORD, FALSE_KEYWORD, + STRING_LITERAL, RAW_STRING_LITERAL, + INTEGER_LITERAL, LONG_LITERAL, CHARACTER_LITERAL, FLOAT_LITERAL, + NULL_KEYWORD, + + LBRACE, // functionLiteral + + LPAR, // tuple + + THIS_KEYWORD, // this + + IF_KEYWORD, // if + WHEN_KEYWORD, // when + TRY_KEYWORD, // try + TYPEOF_KEYWORD, // typeof + NEW_KEYWORD, // new + OBJECT_KEYWORD, // object + + // declaration + LBRACKET, // attribute + FUN_KEYWORD, + VAL_KEYWORD, VAR_KEYWORD, + EXTENSION_KEYWORD, + CLASS_KEYWORD, + TYPE_KEYWORD, + + // jump + THROW_KEYWORD, + RETURN_KEYWORD, + CONTINUE_KEYWORD, + BREAK_KEYWORD, + + // loop + FOR_KEYWORD, + WHILE_KEYWORD, + DO_KEYWORD, + + IDENTIFIER, // SimpleName + FIELD_IDENTIFIER, // Field reference + + NAMESPACE_KEYWORD // for absolute qualified names + ), MODIFIER_KEYWORDS); + private final JetParsing myJetParsing; public JetExpressionParsing(SemanticWhitespaceAwarePsiBuilder builder, JetParsing jetParsing) { @@ -141,8 +192,7 @@ public class JetExpressionParsing extends AbstractJetParsing { * ; */ public void parseExpression() { - // TODO: better recovery for expressions - if (atSet(RPAR, RBRACE, RBRACKET, GT)) { + if (!atSet(EXPRESSION_FIRST)) { error("Expecting an expression"); return; } @@ -906,7 +956,12 @@ public class JetExpressionParsing extends AbstractJetParsing { public void parseExpressions() { while (at(SEMICOLON)) advance(); // SEMICOLON while (!eof() && !at(RBRACE)) { - parseExpression(); + if (!atSet(EXPRESSION_FIRST)) { + errorAndAdvance("Expecting an expression"); + } + if (atSet(EXPRESSION_FIRST)) { + parseExpression(); + } if (at(SEMICOLON)) { while (at(SEMICOLON)) advance(); // SEMICOLON } else if (at(RBRACE)) { @@ -993,6 +1048,8 @@ public class JetExpressionParsing extends AbstractJetParsing { * for * : "for" "(" attributes valOrVar? SimpleName (":" type)? "in" expression ")" expression * ; + * + * TODO: empty loop body (at the end of the block)? */ private void parseFor() { assert _at(FOR_KEYWORD); @@ -1162,7 +1219,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // RETURN_KEYWORD - if (!at(EOL_OR_SEMICOLON)) parseExpression(); + if (atSet(EXPRESSION_FIRST) && !at(EOL_OR_SEMICOLON)) parseExpression(); returnExpression.done(RETURN); } diff --git a/idea/testData/psi/Expressions_ERR.jet b/idea/testData/psi/Expressions_ERR.jet new file mode 100644 index 00000000000..580458f3ded --- /dev/null +++ b/idea/testData/psi/Expressions_ERR.jet @@ -0,0 +1,9 @@ +val f = if (true) return else { + dfsd + );;;);;;~;;; + srgsdfg + + ~ + + ] +} diff --git a/idea/testData/psi/Expressions_ERR.txt b/idea/testData/psi/Expressions_ERR.txt new file mode 100644 index 00000000000..c585b07d936 --- /dev/null +++ b/idea/testData/psi/Expressions_ERR.txt @@ -0,0 +1,58 @@ +JetFile: Expressions_ERR.jet + NAMESPACE + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('f') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + IF + PsiElement(if)('if') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + BOOLEAN_CONSTANT + PsiElement(true)('true') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + THEN + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + PsiElement(else)('else') + PsiWhiteSpace(' ') + ELSE + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('dfsd') + PsiWhiteSpace('\n ') + PsiErrorElement:Expecting an expression + PsiElement(RPAR)(')') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiErrorElement:Expecting an expression + PsiElement(RPAR)(')') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiErrorElement:Expecting an expression + PsiElement(BAD_CHARACTER)('~') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiElement(SEMICOLON)(';') + PsiWhiteSpace('\n ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('srgsdfg') + PsiWhiteSpace('\n\n ') + PsiErrorElement:Expecting an expression + PsiElement(BAD_CHARACTER)('~') + PsiWhiteSpace('\n\n ') + PsiErrorElement:Expecting an expression + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/idea/testData/psi/When_ERR.txt b/idea/testData/psi/When_ERR.txt index ce43a2cdb12..34b37ef5fc3 100644 --- a/idea/testData/psi/When_ERR.txt +++ b/idea/testData/psi/When_ERR.txt @@ -152,9 +152,10 @@ JetFile: When_ERR.jet PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiWhiteSpace(' ') PsiErrorElement:Expecting an expression - PsiElement(SEMICOLON)(';') + + PsiWhiteSpace(' ') + PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION