From 09de9bef2085e9f5273f3d4d86774380b0df9991 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 28 Nov 2011 12:59:16 +0400 Subject: [PATCH] KT-337 Can't break a line before a dot --- .../lang/parsing/JetExpressionParsing.java | 11 ++++- .../jet/lang/parsing/JetParsing.java | 3 ++ ...SemanticWhitespaceAwarePsiBuilderImpl.java | 14 ++++++- .../quick/regressions/kt337.jet | 14 +++++++ .../testData/psi/NewLinesValidOperations.jet | 11 +++++ .../testData/psi/NewLinesValidOperations.txt | 41 +++++++++++++++++++ 6 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet create mode 100644 compiler/testData/psi/NewLinesValidOperations.jet create mode 100644 compiler/testData/psi/NewLinesValidOperations.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index aa9843843da..aa32e6dd1f1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -178,7 +178,10 @@ public class JetExpressionParsing extends AbstractJetParsing { } } + public static final TokenSet ALLOW_NEWLINE_OPERATIONS = TokenSet.create(DOT, SAFE_ACCESS); + public static final TokenSet ALL_OPERATIONS; + static { Set operations = new HashSet(); Precedence[] values = Precedence.values(); @@ -272,7 +275,7 @@ public class JetExpressionParsing extends AbstractJetParsing { precedence.parseHigherPrecedence(this); - while (!myBuilder.newlineBeforeCurrentToken() && atSet(precedence.getOperations())) { + while (!breakedWithNewLine() && atSet(precedence.getOperations())) { IElementType operation = tt(); parseOperationReference(); @@ -328,7 +331,7 @@ public class JetExpressionParsing extends AbstractJetParsing { PsiBuilder.Marker expression = mark(); parseAtomicExpression(); while (true) { - if (myBuilder.newlineBeforeCurrentToken()) { + if (breakedWithNewLine()) { break; } else if (at(LBRACKET)) { @@ -1704,4 +1707,8 @@ public class JetExpressionParsing extends AbstractJetParsing { protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { return myJetParsing.create(builder); } + + private boolean breakedWithNewLine() { + return !ALLOW_NEWLINE_OPERATIONS.contains(tt()) && myBuilder.newlineBeforeCurrentToken(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 9a97153ce8d..814752f7eaa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -124,9 +124,11 @@ public class JetParsing extends AbstractJetParsing { parseNamespaceName(); if (at(LBRACE)) { + // Because it's blocked namespace and it will be parsed as one of top level objects firstEntry.rollbackTo(); return; } + firstEntry.drop(); consumeIf(SEMICOLON); @@ -134,6 +136,7 @@ public class JetParsing extends AbstractJetParsing { firstEntry.rollbackTo(); } + // TODO: Duplicate with parsing imports in parseToplevelDeclarations while (at(IMPORT_KEYWORD)) { parseImportDirective(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java index e211deb85f4..2ac8b609e2c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java @@ -25,27 +25,37 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp @Override public boolean newlineBeforeCurrentToken() { + if (!newlinesEnabled.peek()) return false; + if (eof()) return true; - // TODO: maybe, memoize this somehow? + + // TODO: maybe, memorize this somehow? for (int i = 1; i <= getCurrentOffset(); i++) { IElementType previousToken = rawLookup(-i); + if (previousToken == JetTokens.BLOCK_COMMENT || previousToken == JetTokens.DOC_COMMENT || previousToken == JetTokens.EOL_COMMENT) { continue; } + if (previousToken != TokenType.WHITE_SPACE) { break; } + int previousTokenStart = rawTokenTypeStart(-i); int previousTokenEnd = rawTokenTypeStart(-i + 1); + assert previousTokenStart >= 0; assert previousTokenEnd < getOriginalText().length(); + for (int j = previousTokenStart; j < previousTokenEnd; j++) { - if (getOriginalText().charAt(j) == '\n') return true; + if (getOriginalText().charAt(j) == '\n') + return true; } } + return false; } diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet new file mode 100644 index 00000000000..7cac265e866 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet @@ -0,0 +1,14 @@ +//KT-337 Can't break a line before a dot + +class A() { + fun foo() {} +} + +fun test() { + val a = A() + + a + + .foo() // Should be a valid expression + +} diff --git a/compiler/testData/psi/NewLinesValidOperations.jet b/compiler/testData/psi/NewLinesValidOperations.jet new file mode 100644 index 00000000000..1a9483d7f62 --- /dev/null +++ b/compiler/testData/psi/NewLinesValidOperations.jet @@ -0,0 +1,11 @@ +fun test() { + val str = "" + + str + + .length + + str + + ?.length +} \ No newline at end of file diff --git a/compiler/testData/psi/NewLinesValidOperations.txt b/compiler/testData/psi/NewLinesValidOperations.txt new file mode 100644 index 00000000000..22e86010779 --- /dev/null +++ b/compiler/testData/psi/NewLinesValidOperations.txt @@ -0,0 +1,41 @@ +JetFile: NewLinesValidOperations.jet + NAMESPACE + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('test') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiWhiteSpace('\n\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace('\n\n ') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('length') + PsiWhiteSpace('\n\n ') + SAFE_ACCESS_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace('\n\n ') + PsiElement(SAFE_ACCESS)('?.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('length') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file