Parse collection literals as atomic expressions

This commit is contained in:
Mikhail Zarechenskiy
2017-03-17 12:40:47 +03:00
parent 3c7678092e
commit d3fd96ceed
10 changed files with 341 additions and 45 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -201,6 +201,8 @@ public interface KtNodeTypes {
KtNodeType WHEN_CONDITION_IS_PATTERN = new KtNodeType("WHEN_CONDITION_IS_PATTERN", KtWhenConditionIsPattern.class);
KtNodeType WHEN_CONDITION_EXPRESSION = new KtNodeType("WHEN_CONDITION_WITH_EXPRESSION", KtWhenConditionWithExpression.class);
KtNodeType COLLECTION_LITERAL_EXPRESSION = new KtNodeType("COLLECTION_LITERAL_EXPRESSION", KtCollectionLiteralExpression.class);
IElementType PACKAGE_DIRECTIVE = KtStubElementTypes.PACKAGE_DIRECTIVE;
IElementType SCRIPT = KtStubElementTypes.SCRIPT;
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -111,7 +111,9 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
IDENTIFIER, // SimpleName
AT // Just for better recovery and maybe for annotations
AT, // Just for better recovery and maybe for annotations
LBRACKET // Collection literal expression
);
private static final TokenSet STATEMENT_FIRST = TokenSet.orSet(
@@ -613,6 +615,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
* : functionLiteral
* : declaration
* : SimpleName
* : collectionLiteral
* ;
*/
private boolean parseAtomicExpression() {
@@ -621,6 +624,9 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
if (at(LPAR)) {
parseParenthesizedExpression();
}
else if (at(LBRACKET)) {
parseCollectionLiteralExpression();
}
else if (at(THIS_KEYWORD)) {
parseThisExpression();
}
@@ -987,28 +993,59 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
* ;
*/
private void parseArrayAccess() {
parseAsCollectionLiteralExpression(INDICES, false, "Expecting an index element");
}
/*
* collectionLiteral
* : "[" element{","}? "]"
* ;
*/
private void parseCollectionLiteralExpression() {
parseAsCollectionLiteralExpression(COLLECTION_LITERAL_EXPRESSION, true, "Expecting an element");
}
private void parseAsCollectionLiteralExpression(KtNodeType nodeType, boolean canBeEmpty, String missingElementErrorMessage) {
assert _at(LBRACKET);
PsiBuilder.Marker indices = mark();
PsiBuilder.Marker innerExpressions = mark();
myBuilder.disableNewlines();
advance(); // LBRACKET
while (true) {
if (at(COMMA)) errorAndAdvance("Expecting an index element");
if (at(RBRACKET)) {
error("Expecting an index element");
break;
if (!canBeEmpty && at(RBRACKET)) {
error(missingElementErrorMessage);
}
parseExpression();
if (!at(COMMA)) break;
advance(); // COMMA
else {
parseInnerExpressions(missingElementErrorMessage);
}
expect(RBRACKET, "Expecting ']'");
myBuilder.restoreNewlinesState();
indices.done(INDICES);
innerExpressions.done(nodeType);
}
private void parseInnerExpressions(String missingElementErrorMessage) {
boolean firstElement = true;
while (true) {
if (at(COMMA)) errorAndAdvance(missingElementErrorMessage);
if (at(RBRACKET)) {
if (firstElement) {
break;
}
else {
error(missingElementErrorMessage);
}
break;
}
parseExpression();
firstElement = false;
if (!at(COMMA)) break;
advance(); // COMMA
}
}
/*
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode
class KtCollectionLiteralExpression(node: ASTNode) : KtExpressionImpl(node)
+14
View File
@@ -0,0 +1,14 @@
fun test() {
[]
[1]
[1, 2]
[[]]
[[1]]
[1, []]
[[], 1]
[[], [1, []]]
[1,
2]
[1,
[2]]
}
+117
View File
@@ -0,0 +1,117 @@
JetFile: CollectionLiterals.kt
PACKAGE_DIRECTIVE
<empty list>
IMPORT_LIST
<empty list>
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('test')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('2')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace('\n ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('2')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('2')
PsiElement(RBRACKET)(']')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
+8
View File
@@ -0,0 +1,8 @@
fun test() {
[,]
[1, ]
[, 1]
[1, 2 3]
[1, 2 3, ]
[
}
+79
View File
@@ -0,0 +1,79 @@
JetFile: CollectionLiterals_ERR.kt
PACKAGE_DIRECTIVE
<empty list>
IMPORT_LIST
<empty list>
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('test')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiErrorElement:Expecting an element
PsiElement(COMMA)(',')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiErrorElement:Expecting an element
<empty list>
PsiWhiteSpace(' ')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiErrorElement:Expecting an element
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('2')
PsiErrorElement:Expecting ']'
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(INTEGER_LITERAL)('3')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('2')
PsiErrorElement:Expecting ']'
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(INTEGER_LITERAL)('3')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
PsiElement(RBRACKET)(']')
PsiWhiteSpace('\n ')
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
PsiErrorElement:Expecting an expression
<empty list>
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -35,24 +35,25 @@ JetFile: oldAnnotationsRecovery.kt
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
PsiErrorElement:Expecting an element
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('inline')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(RBRACKET)(']')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
<empty list>
PsiWhiteSpace(' ')
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('bar')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
LAMBDA_EXPRESSION
FUNCTION_LITERAL
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
BLOCK
RETURN
PsiElement(return)('return')
PsiWhiteSpace(' ')
@@ -61,7 +62,7 @@ JetFile: oldAnnotationsRecovery.kt
PsiWhiteSpace('\n ')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n ')
PsiErrorElement:Expecting an element
COLLECTION_LITERAL_EXPRESSION
PsiElement(LBRACKET)('[')
CALL_EXPRESSION
REFERENCE_EXPRESSION
@@ -75,9 +76,9 @@ JetFile: oldAnnotationsRecovery.kt
PsiElement(REGULAR_STRING_PART)('1')
PsiElement(CLOSING_QUOTE)('"')
PsiElement(RPAR)(')')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(RBRACKET)(']')
PsiWhiteSpace(' ')
PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(PLUS)('+')
PsiElement(INTEGER_LITERAL)('1')
@@ -122,6 +122,18 @@ public class ParsingTestGenerated extends AbstractParsingTest {
doParsingTest(fileName);
}
@TestMetadata("CollectionLiterals.kt")
public void testCollectionLiterals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/CollectionLiterals.kt");
doParsingTest(fileName);
}
@TestMetadata("CollectionLiterals_ERR.kt")
public void testCollectionLiterals_ERR() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/CollectionLiterals_ERR.kt");
doParsingTest(fileName);
}
@TestMetadata("CommentsBinding.kt")
public void testCommentsBinding() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/CommentsBinding.kt");
+5
View File
@@ -120,6 +120,7 @@ atomicExpression
: objectLiteral
: jump
: loop
: collectionLiteral
: SimpleName
;
@@ -275,3 +276,7 @@ arrayAccess
objectLiteral
: "object" (":" delegationSpecifier{","})? classBody
;
collectionLiteral
: "[" element{","}? "]"
;