KT-337 Can't break a line before a dot

This commit is contained in:
Nikolay Krasko
2011-11-28 12:59:16 +04:00
parent 5ad627fab9
commit 09de9bef20
6 changed files with 90 additions and 4 deletions
@@ -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; public static final TokenSet ALL_OPERATIONS;
static { static {
Set<IElementType> operations = new HashSet<IElementType>(); Set<IElementType> operations = new HashSet<IElementType>();
Precedence[] values = Precedence.values(); Precedence[] values = Precedence.values();
@@ -272,7 +275,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
precedence.parseHigherPrecedence(this); precedence.parseHigherPrecedence(this);
while (!myBuilder.newlineBeforeCurrentToken() && atSet(precedence.getOperations())) { while (!breakedWithNewLine() && atSet(precedence.getOperations())) {
IElementType operation = tt(); IElementType operation = tt();
parseOperationReference(); parseOperationReference();
@@ -328,7 +331,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
PsiBuilder.Marker expression = mark(); PsiBuilder.Marker expression = mark();
parseAtomicExpression(); parseAtomicExpression();
while (true) { while (true) {
if (myBuilder.newlineBeforeCurrentToken()) { if (breakedWithNewLine()) {
break; break;
} }
else if (at(LBRACKET)) { else if (at(LBRACKET)) {
@@ -1704,4 +1707,8 @@ public class JetExpressionParsing extends AbstractJetParsing {
protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) {
return myJetParsing.create(builder); return myJetParsing.create(builder);
} }
private boolean breakedWithNewLine() {
return !ALLOW_NEWLINE_OPERATIONS.contains(tt()) && myBuilder.newlineBeforeCurrentToken();
}
} }
@@ -124,9 +124,11 @@ public class JetParsing extends AbstractJetParsing {
parseNamespaceName(); parseNamespaceName();
if (at(LBRACE)) { if (at(LBRACE)) {
// Because it's blocked namespace and it will be parsed as one of top level objects
firstEntry.rollbackTo(); firstEntry.rollbackTo();
return; return;
} }
firstEntry.drop(); firstEntry.drop();
consumeIf(SEMICOLON); consumeIf(SEMICOLON);
@@ -134,6 +136,7 @@ public class JetParsing extends AbstractJetParsing {
firstEntry.rollbackTo(); firstEntry.rollbackTo();
} }
// TODO: Duplicate with parsing imports in parseToplevelDeclarations
while (at(IMPORT_KEYWORD)) { while (at(IMPORT_KEYWORD)) {
parseImportDirective(); parseImportDirective();
} }
@@ -25,27 +25,37 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp
@Override @Override
public boolean newlineBeforeCurrentToken() { public boolean newlineBeforeCurrentToken() {
if (!newlinesEnabled.peek()) return false; if (!newlinesEnabled.peek()) return false;
if (eof()) return true; if (eof()) return true;
// TODO: maybe, memoize this somehow?
// TODO: maybe, memorize this somehow?
for (int i = 1; i <= getCurrentOffset(); i++) { for (int i = 1; i <= getCurrentOffset(); i++) {
IElementType previousToken = rawLookup(-i); IElementType previousToken = rawLookup(-i);
if (previousToken == JetTokens.BLOCK_COMMENT if (previousToken == JetTokens.BLOCK_COMMENT
|| previousToken == JetTokens.DOC_COMMENT || previousToken == JetTokens.DOC_COMMENT
|| previousToken == JetTokens.EOL_COMMENT) { || previousToken == JetTokens.EOL_COMMENT) {
continue; continue;
} }
if (previousToken != TokenType.WHITE_SPACE) { if (previousToken != TokenType.WHITE_SPACE) {
break; break;
} }
int previousTokenStart = rawTokenTypeStart(-i); int previousTokenStart = rawTokenTypeStart(-i);
int previousTokenEnd = rawTokenTypeStart(-i + 1); int previousTokenEnd = rawTokenTypeStart(-i + 1);
assert previousTokenStart >= 0; assert previousTokenStart >= 0;
assert previousTokenEnd < getOriginalText().length(); assert previousTokenEnd < getOriginalText().length();
for (int j = previousTokenStart; j < previousTokenEnd; j++) { for (int j = previousTokenStart; j < previousTokenEnd; j++) {
if (getOriginalText().charAt(j) == '\n') return true; if (getOriginalText().charAt(j) == '\n')
return true;
} }
} }
return false; return false;
} }
@@ -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
}
@@ -0,0 +1,11 @@
fun test() {
val str = ""
str
.length
str
?.length
}
@@ -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)('}')