diff --git a/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java b/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java index fa996a7c9ea..c66d8c150cc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java @@ -80,7 +80,6 @@ public interface JetTokens { JetToken AS_SAFE = JetKeywordToken.keyword("AS_SAFE");//new JetToken("as?"); JetToken IDENTIFIER = new JetToken("IDENTIFIER"); - JetToken LABEL_IDENTIFIER = new JetToken("LABEL_IDENTIFIER"); JetToken FIELD_IDENTIFIER = new JetToken("FIELD_IDENTIFIER"); JetSingleValueToken LBRACKET = new JetSingleValueToken("LBRACKET", "["); @@ -127,6 +126,7 @@ public interface JetTokens { JetKeywordToken NOT_IN = JetKeywordToken.keyword("NOT_IN", "!in"); JetKeywordToken NOT_IS = JetKeywordToken.keyword("NOT_IS", "!is"); JetSingleValueToken HASH = new JetSingleValueToken("HASH", "#"); + JetSingleValueToken AT = new JetSingleValueToken("AT", "@"); JetSingleValueToken COMMA = new JetSingleValueToken("COMMA", ","); @@ -211,7 +211,7 @@ public interface JetTokens { COLON, RANGE, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS, - IDENTIFIER, LABEL_IDENTIFIER); + IDENTIFIER); TokenSet AUGMENTED_ASSIGNMENTS = TokenSet.create(PLUSEQ, MINUSEQ, MULTEQ, PERCEQ, DIVEQ); TokenSet ALL_ASSIGNMENTS = TokenSet.create(EQ, PLUSEQ, MINUSEQ, MULTEQ, PERCEQ, DIVEQ); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/lexer/Kotlin.flex b/compiler/frontend/src/org/jetbrains/kotlin/lexer/Kotlin.flex index f1620a7b4dc..8b3006afb5f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/lexer/Kotlin.flex +++ b/compiler/frontend/src/org/jetbrains/kotlin/lexer/Kotlin.flex @@ -84,7 +84,6 @@ PLAIN_IDENTIFIER={LETTER} {IDENTIFIER_PART}* ESCAPED_IDENTIFIER = `[^`\n]+` IDENTIFIER = {PLAIN_IDENTIFIER}|{ESCAPED_IDENTIFIER} FIELD_IDENTIFIER = \${IDENTIFIER} -LABEL_IDENTIFIER = \@{IDENTIFIER}? EOL_COMMENT="/""/"[^\n]* SHEBANG_COMMENT="#!"[^\n]* @@ -273,7 +272,6 @@ LONG_TEMPLATE_ENTRY_START=\$\{ {FIELD_IDENTIFIER} { return JetTokens.FIELD_IDENTIFIER; } {IDENTIFIER} { return JetTokens.IDENTIFIER; } -{LABEL_IDENTIFIER} { return JetTokens.LABEL_IDENTIFIER; } \!in{IDENTIFIER_PART} { yypushback(3); return JetTokens.EXCL; } \!is{IDENTIFIER_PART} { yypushback(3); return JetTokens.EXCL; } @@ -325,6 +323,7 @@ LONG_TEMPLATE_ENTRY_START=\$\{ "=" { return JetTokens.EQ ; } "," { return JetTokens.COMMA ; } "#" { return JetTokens.HASH ; } +"@" { return JetTokens.AT ; } // error fallback . { return TokenType.BAD_CHARACTER; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java index 84796575a5b..52b3dfdeb72 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetExpressionParsing.java @@ -71,7 +71,7 @@ public class JetExpressionParsing extends AbstractJetParsing { // Prefix MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, EXCLEXCL, // Joining complex tokens makes it necessary to put EXCLEXCL here - LBRACKET, LABEL_IDENTIFIER, + LBRACKET, // Atomic COLONCOLON, // callable reference @@ -112,7 +112,8 @@ public class JetExpressionParsing extends AbstractJetParsing { IDENTIFIER, // SimpleName FIELD_IDENTIFIER, // Field reference - PACKAGE_KEYWORD // for absolute qualified names + PACKAGE_KEYWORD, // for absolute qualified names + AT // Just for better recovery and maybe for annotations ); private static final TokenSet STATEMENT_FIRST = TokenSet.orSet( @@ -143,7 +144,7 @@ public class JetExpressionParsing extends AbstractJetParsing { POSTFIX(PLUSPLUS, MINUSMINUS, EXCLEXCL, DOT, SAFE_ACCESS), // typeArguments? valueArguments : typeArguments : arrayAccess - PREFIX(MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, LABEL_IDENTIFIER) { // annotations + PREFIX(MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL) { // annotations @Override public void parseHigherPrecedence(JetExpressionParsing parser) { @@ -328,9 +329,8 @@ public class JetExpressionParsing extends AbstractJetParsing { * label prefixExpression */ private void parseLabeledExpression() { - assert _at(LABEL_IDENTIFIER); PsiBuilder.Marker expression = mark(); - parseLabel(); + parseLabelDefinition(); parsePrefixExpression(); expression.done(LABELED_EXPRESSION); } @@ -351,7 +351,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } else { myBuilder.disableJoiningComplexTokens(); - if (at(LABEL_IDENTIFIER)) { + if (isAtLabelDefinitionOrMissingIdentifier()) { myBuilder.restoreJoiningComplexTokensState(); parseLabeledExpression(); } @@ -532,10 +532,10 @@ public class JetExpressionParsing extends AbstractJetParsing { */ protected boolean parseCallWithClosure() { boolean success = false; - while ((at(LBRACE) || at(LABEL_IDENTIFIER) && lookahead(1) == LBRACE)) { + + while (at(LBRACE) || isAtLabelDefinitionBeforeLBrace()) { PsiBuilder.Marker argument = mark(); if (!at(LBRACE)) { - assert _at(LABEL_IDENTIFIER); parseLabeledExpression(); } else { @@ -548,6 +548,19 @@ public class JetExpressionParsing extends AbstractJetParsing { return success; } + private boolean isAtLabelDefinitionBeforeLBrace() { + if (at(IDENTIFIER)) { + if (myBuilder.rawLookup(1) != AT) return false; + return lookahead(2) == LBRACE; + } + + return at(AT) && lookahead(1) == LBRACE; + } + + private boolean isAtLabelDefinitionOrMissingIdentifier() { + return (at(IDENTIFIER) && myBuilder.rawLookup(1) == AT) || at(AT); + } + /* * atomicExpression * : tupleLiteral // or parenthesized element @@ -982,7 +995,8 @@ public class JetExpressionParsing extends AbstractJetParsing { if (declType != null) { // we do not attach preceding comments (non-doc) to local variables because they are likely commenting a few statements below - closeDeclarationWithCommentBinders(decl, declType, declType != JetNodeTypes.PROPERTY && declType != JetNodeTypes.MULTI_VARIABLE_DECLARATION); + closeDeclarationWithCommentBinders(decl, declType, + declType != JetNodeTypes.PROPERTY && declType != JetNodeTypes.MULTI_VARIABLE_DECLARATION); return true; } else { @@ -1450,10 +1464,10 @@ public class JetExpressionParsing extends AbstractJetParsing { if (at(LBRACE)) { parseFunctionLiteral(true); } - else if (at(LABEL_IDENTIFIER) && lookahead(1) == LBRACE ) { + else if (isAtLabelDefinitionBeforeLBrace()) { PsiBuilder.Marker mark = mark(); - parseLabel(); + parseLabelDefinition(); parseFunctionLiteral(true); @@ -1609,7 +1623,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // BREAK_KEYWORD or CONTINUE_KEYWORD - parseLabelOnTheSameLine(); + parseLabelReferenceWithNoWhitespace(); marker.done(type); } @@ -1624,7 +1638,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // RETURN_KEYWORD - parseLabelOnTheSameLine(); + parseLabelReferenceWithNoWhitespace(); if (atSet(EXPRESSION_FIRST) && !at(EOL_OR_SEMICOLON)) parseExpression(); @@ -1634,28 +1648,55 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * label? */ - private void parseLabelOnTheSameLine() { - if (!eol() && at(LABEL_IDENTIFIER)) { - parseLabel(); + private void parseLabelReferenceWithNoWhitespace() { + if (at(AT) && !WHITE_SPACE_OR_COMMENT_BIT_SET.contains(myBuilder.rawLookup(-1))) { + parseLabelReference(); } } /* - * label + * IDENTIFIER "@" */ - private void parseLabel() { - assert _at(LABEL_IDENTIFIER); - - String labelText = myBuilder.getTokenText(); - if ("@".equals(labelText)) { - errorAndAdvance("Label must be named"); + private void parseLabelDefinition() { + if (at(AT)) { + // recovery for empty label identifier + errorAndAdvance("Label must be named"); // AT return; } + PsiBuilder.Marker labelWrap = mark(); + PsiBuilder.Marker mark = mark(); + + assert _at(IDENTIFIER) && myBuilder.rawLookup(1) == AT : "Callers must check that current token is IDENTIFIER followed with '@'"; + + advance(); // IDENTIFIER + advance(); // AT + + mark.done(LABEL); + + labelWrap.done(LABEL_QUALIFIER); + } + + /* + * "@" IDENTIFIER + */ + private void parseLabelReference() { + assert _at(AT); + PsiBuilder.Marker labelWrap = mark(); PsiBuilder.Marker mark = mark(); - advance(); // LABEL_IDENTIFIER + + if (myBuilder.rawLookup(1) != IDENTIFIER) { + errorAndAdvance("Label must be named"); // AT + labelWrap.drop(); + mark.drop(); + return; + } + + advance(); // AT + advance(); // IDENTIFIER + mark.done(LABEL); labelWrap.done(LABEL_QUALIFIER); @@ -1753,7 +1794,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // THIS_KEYWORD thisReference.done(REFERENCE_EXPRESSION); - parseLabelOnTheSameLine(); + parseLabelReferenceWithNoWhitespace(); mark.done(THIS_EXPRESSION); } @@ -1787,7 +1828,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } myBuilder.restoreNewlinesState(); } - parseLabelOnTheSameLine(); + parseLabelReferenceWithNoWhitespace(); mark.done(SUPER_EXPRESSION); } diff --git a/compiler/testData/psi/ControlStructures.kt b/compiler/testData/psi/ControlStructures.kt index 1e8156b680c..04b92762853 100644 --- a/compiler/testData/psi/ControlStructures.kt +++ b/compiler/testData/psi/ControlStructures.kt @@ -3,9 +3,9 @@ fun a( a : foo = throw Foo(), a : foo = return 10, a : foo = break, - a : foo = break @la, + a : foo = break@la, a : foo = continue, - a : foo = continue @la, + a : foo = continue@la, a : foo = if (10) foo else bar, a : foo = if (10) foo ) { @@ -13,11 +13,11 @@ fun a( return 10 break - @la - break @la + la@ + break@la continue - @la - continue @la + la@ + continue@la if (foo) if (foo) bar diff --git a/compiler/testData/psi/ControlStructures.txt b/compiler/testData/psi/ControlStructures.txt index 4c8e671566f..4aa36a363fc 100644 --- a/compiler/testData/psi/ControlStructures.txt +++ b/compiler/testData/psi/ControlStructures.txt @@ -80,10 +80,10 @@ JetFile: ControlStructures.kt PsiWhiteSpace(' ') BREAK PsiElement(break)('break') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiElement(COMMA)(',') PsiWhiteSpace('\n ') VALUE_PARAMETER @@ -116,10 +116,10 @@ JetFile: ControlStructures.kt PsiWhiteSpace(' ') CONTINUE PsiElement(continue)('continue') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiElement(COMMA)(',') PsiWhiteSpace('\n ') VALUE_PARAMETER @@ -202,14 +202,15 @@ JetFile: ControlStructures.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(IDENTIFIER)('la') + PsiElement(AT)('@') PsiWhiteSpace('\n ') BREAK PsiElement(break)('break') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiWhiteSpace('\n ') CONTINUE PsiElement(continue)('continue') @@ -217,14 +218,15 @@ JetFile: ControlStructures.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(IDENTIFIER)('la') + PsiElement(AT)('@') PsiWhiteSpace('\n ') CONTINUE PsiElement(continue)('continue') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiWhiteSpace('\n ') IF PsiElement(if)('if') diff --git a/compiler/testData/psi/Labels.kt b/compiler/testData/psi/Labels.kt index c2dc2ca6980..3416def34dd 100644 --- a/compiler/testData/psi/Labels.kt +++ b/compiler/testData/psi/Labels.kt @@ -1,7 +1,7 @@ fun foo() { return return 1 - return (@a 1) + return (a@ 1) return@ return@ 1 @@ -10,8 +10,8 @@ fun foo() { return@a return@a 1 - return@a (@a 1) - return@a @a 1 + return@a (a@ 1) + return@a a@ 1 return@@ return@@ 1 @@ -24,7 +24,7 @@ fun foo() { continue@ continue@a - a.filter @f{ + a.filter f@{ if (1) return return@f true } diff --git a/compiler/testData/psi/Labels.txt b/compiler/testData/psi/Labels.txt index 5b1aa09fa00..a4d4077f69b 100644 --- a/compiler/testData/psi/Labels.txt +++ b/compiler/testData/psi/Labels.txt @@ -29,7 +29,8 @@ JetFile: Labels.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(IDENTIFIER)('a') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -38,12 +39,12 @@ JetFile: Labels.kt RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -51,13 +52,13 @@ JetFile: Labels.kt RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') PARENTHESIZED PsiElement(LPAR)('(') LABELED_EXPRESSION PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -66,11 +67,11 @@ JetFile: Labels.kt RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') LABELED_EXPRESSION PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -79,13 +80,15 @@ JetFile: Labels.kt PsiElement(return)('return') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -94,14 +97,16 @@ JetFile: Labels.kt PsiElement(return)('return') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace(' ') PARENTHESIZED PsiElement(LPAR)('(') LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(IDENTIFIER)('a') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -111,12 +116,14 @@ JetFile: Labels.kt PsiElement(return)('return') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace(' ') LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(IDENTIFIER)('a') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -124,18 +131,18 @@ JetFile: Labels.kt RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') LABELED_EXPRESSION PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') LABELED_EXPRESSION PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') INTEGER_CONSTANT PsiElement(INTEGER_LITERAL)('1') @@ -146,13 +153,14 @@ JetFile: Labels.kt BREAK PsiElement(break)('break') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') BREAK PsiElement(break)('break') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace('\n\n ') CONTINUE PsiElement(continue)('continue') @@ -160,13 +168,14 @@ JetFile: Labels.kt CONTINUE PsiElement(continue)('continue') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') CONTINUE PsiElement(continue)('continue') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace('\n\n ') DOT_QUALIFIED_EXPRESSION REFERENCE_EXPRESSION @@ -180,7 +189,8 @@ JetFile: Labels.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@f') + PsiElement(IDENTIFIER)('f') + PsiElement(AT)('@') FUNCTION_LITERAL_EXPRESSION FUNCTION_LITERAL PsiElement(LBRACE)('{') @@ -203,7 +213,8 @@ JetFile: Labels.kt PsiElement(return)('return') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@f') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('f') PsiWhiteSpace(' ') BOOLEAN_CONSTANT PsiElement(true)('true') @@ -221,7 +232,7 @@ JetFile: Labels.kt FUNCTION_LITERAL_ARGUMENT LABELED_EXPRESSION PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') FUNCTION_LITERAL_EXPRESSION FUNCTION_LITERAL PsiElement(LBRACE)('{') @@ -243,7 +254,7 @@ JetFile: Labels.kt RETURN PsiElement(return)('return') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace(' ') BOOLEAN_CONSTANT PsiElement(true)('true') @@ -258,14 +269,15 @@ JetFile: Labels.kt REFERENCE_EXPRESSION PsiElement(this)('this') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') THIS_EXPRESSION REFERENCE_EXPRESSION PsiElement(this)('this') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace('\n\n ') SUPER_EXPRESSION REFERENCE_EXPRESSION @@ -287,7 +299,7 @@ JetFile: Labels.kt PsiElement(IDENTIFIER)('A') PsiElement(GT)('>') PsiErrorElement:Label must be named - PsiElement(LABEL_IDENTIFIER)('@') + PsiElement(AT)('@') PsiWhiteSpace('\n ') SUPER_EXPRESSION REFERENCE_EXPRESSION @@ -300,6 +312,7 @@ JetFile: Labels.kt PsiElement(GT)('>') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@a') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('a') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/SimpleExpressions.kt b/compiler/testData/psi/SimpleExpressions.kt index e581ab7004c..741edf5dc54 100644 --- a/compiler/testData/psi/SimpleExpressions.kt +++ b/compiler/testData/psi/SimpleExpressions.kt @@ -25,9 +25,9 @@ fun a( a : foo = throw Foo(), a : foo = return 10, a : foo = break, - a : foo = break @la, + a : foo = break@la, a : foo = continue, - a : foo = continue @la, + a : foo = continue@la, a : foo = 10, a : foo = 10, a : foo = 10, @@ -38,9 +38,9 @@ fun a( return 10 break - @la - break @la + la@ + break@la continue - @la - continue @la + la@ + continue@la } diff --git a/compiler/testData/psi/SimpleExpressions.txt b/compiler/testData/psi/SimpleExpressions.txt index 0b852d13bb1..bae4610a897 100644 --- a/compiler/testData/psi/SimpleExpressions.txt +++ b/compiler/testData/psi/SimpleExpressions.txt @@ -552,10 +552,10 @@ JetFile: SimpleExpressions.kt PsiWhiteSpace(' ') BREAK PsiElement(break)('break') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiElement(COMMA)(',') PsiWhiteSpace('\n ') VALUE_PARAMETER @@ -588,10 +588,10 @@ JetFile: SimpleExpressions.kt PsiWhiteSpace(' ') CONTINUE PsiElement(continue)('continue') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiElement(COMMA)(',') PsiWhiteSpace('\n ') VALUE_PARAMETER @@ -700,14 +700,15 @@ JetFile: SimpleExpressions.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(IDENTIFIER)('la') + PsiElement(AT)('@') PsiWhiteSpace('\n ') BREAK PsiElement(break)('break') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiWhiteSpace('\n ') CONTINUE PsiElement(continue)('continue') @@ -715,13 +716,14 @@ JetFile: SimpleExpressions.kt LABELED_EXPRESSION LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(IDENTIFIER)('la') + PsiElement(AT)('@') PsiWhiteSpace('\n ') CONTINUE PsiElement(continue)('continue') - PsiWhiteSpace(' ') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@la') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('la') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/Super.txt b/compiler/testData/psi/Super.txt index 7f1a6066b3c..d68d377ddce 100644 --- a/compiler/testData/psi/Super.txt +++ b/compiler/testData/psi/Super.txt @@ -76,7 +76,8 @@ JetFile: Super.kt PsiElement(GT)('>') LABEL_QUALIFIER LABEL - PsiElement(LABEL_IDENTIFIER)('@label') + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('label') PsiElement(DOT)('.') CALL_EXPRESSION REFERENCE_EXPRESSION diff --git a/compiler/testData/psi/newLabels/basic.kt b/compiler/testData/psi/newLabels/basic.kt new file mode 100644 index 00000000000..7b8c765c4ca --- /dev/null +++ b/compiler/testData/psi/newLabels/basic.kt @@ -0,0 +1,25 @@ +fun foo() { + x1.filter b@ { + return 1 + } + c@ { + return 2 + } + + loop1@ for (i in 1..100) { + return 4 + } + + loop2@ for (i in 1..100) { + return@loop2 4 + return@loop2 5 + } + + label1@ val x = 1 + + 1 + label3@ 3 + 4 + + l1@ foo bar l2@ baz // binary expression + + return (a@ 1) +} \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/basic.txt b/compiler/testData/psi/newLabels/basic.txt new file mode 100644 index 00000000000..3bb90f439bf --- /dev/null +++ b/compiler/testData/psi/newLabels/basic.txt @@ -0,0 +1,229 @@ +JetFile: basic.kt + PACKAGE_DIRECTIVE + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x1') + PsiElement(DOT)('.') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('filter') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_ARGUMENT + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('b') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL_ARGUMENT + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('c') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('loop1') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FOR + PsiElement(for)('for') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(in)('in') + PsiWhiteSpace(' ') + LOOP_RANGE + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + OPERATION_REFERENCE + PsiElement(RANGE)('..') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('100') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BODY + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('loop2') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FOR + PsiElement(for)('for') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(in)('in') + PsiWhiteSpace(' ') + LOOP_RANGE + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + OPERATION_REFERENCE + PsiElement(RANGE)('..') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('100') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BODY + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + LABEL_QUALIFIER + LABEL + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + LABEL_QUALIFIER + LABEL + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('5') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('label1') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n ') + BINARY_EXPRESSION + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('label3') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n\n ') + BINARY_EXPRESSION + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('l1') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('l2') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('baz') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// binary expression') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + PARENTHESIZED + PsiElement(LPAR)('(') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('a') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/oldSyntaxExpressions.kt b/compiler/testData/psi/newLabels/oldSyntaxExpressions.kt new file mode 100644 index 00000000000..81ffaaa8e6c --- /dev/null +++ b/compiler/testData/psi/newLabels/oldSyntaxExpressions.kt @@ -0,0 +1,11 @@ +fun foo() { + @loop1 for (i in 1..100) { } + + x2.filter @f { + return 2 + } + + return (@f 3) + + val x = 1 +} \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/oldSyntaxExpressions.txt b/compiler/testData/psi/newLabels/oldSyntaxExpressions.txt new file mode 100644 index 00000000000..9a5c9510208 --- /dev/null +++ b/compiler/testData/psi/newLabels/oldSyntaxExpressions.txt @@ -0,0 +1,99 @@ +JetFile: oldSyntaxExpressions.kt + PACKAGE_DIRECTIVE + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('loop1') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + + PsiWhiteSpace(' ') + FOR + PsiElement(for)('for') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(in)('in') + PsiWhiteSpace(' ') + LOOP_RANGE + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + OPERATION_REFERENCE + PsiElement(RANGE)('..') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('100') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BODY + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x2') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('filter') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('f') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + PARENTHESIZED + PsiElement(LPAR)('(') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + PsiErrorElement:Expecting ')' + + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('3') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/recovery.kt b/compiler/testData/psi/newLabels/recovery.kt new file mode 100644 index 00000000000..b4ed4d99bf0 --- /dev/null +++ b/compiler/testData/psi/newLabels/recovery.kt @@ -0,0 +1,32 @@ +fun foo() { + + x2.filter c @ { // should be no space after c + return 2 + } + + x3.filter @ { // no label identifier + return 3 + } + + loop2 @ for (i in 1..100) { // should be no space after loop2 + return@ loop2 5 + return @ loop2 7 + return + @loop2 4 + } + + @ while (1) { + return 123 + } + + label2 @ fun foo() {} // should be no space after label2 + + 1 + label3@ 3 + 4 + + l1 @ foo bar l2 @ baz // binary expression with extra spaces + foo l3 @ bar baz // binary expression with `@ bar` parsed as wrong label + + foo@ bar baz // binary expression labeled `bar` and return as second arg + + return @ 1 +} diff --git a/compiler/testData/psi/newLabels/recovery.txt b/compiler/testData/psi/newLabels/recovery.txt new file mode 100644 index 00000000000..7c69e391da7 --- /dev/null +++ b/compiler/testData/psi/newLabels/recovery.txt @@ -0,0 +1,268 @@ +JetFile: recovery.kt + PACKAGE_DIRECTIVE + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n ') + BINARY_EXPRESSION + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x2') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('filter') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('c') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// should be no space after c') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x3') + PsiElement(DOT)('.') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('filter') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_ARGUMENT + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// no label identifier') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiWhiteSpace(' ') + PsiElement(for)('for') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('i') + PsiWhiteSpace(' ') + PsiElement(in)('in') + PsiWhiteSpace(' ') + PsiElement(INTEGER_LITERAL)('1') + PsiElement(RANGE)('..') + PsiElement(INTEGER_LITERAL)('100') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// should be no space after loop2') + PsiWhiteSpace('\n ') + BLOCK + RETURN + PsiElement(return)('return') + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('5') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('7') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace('\n ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('loop2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + WHILE + PsiElement(while)('while') + PsiWhiteSpace(' ') + PsiElement(LPAR)('(') + CONDITION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BODY + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('123') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('label2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiWhiteSpace(' ') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BLOCK + + PsiElement(RBRACE)('}') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// should be no space after label2') + PsiWhiteSpace('\n\n ') + BINARY_EXPRESSION + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('label3') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n\n ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('l1') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('l2') + PsiWhiteSpace(' ') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('baz') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// binary expression with extra spaces') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + BINARY_EXPRESSION + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('l3') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('baz') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// binary expression with `@ bar` parsed as wrong label') + PsiWhiteSpace('\n\n ') + LABELED_EXPRESSION + LABEL_QUALIFIER + LABEL + PsiElement(IDENTIFIER)('foo') + PsiElement(AT)('@') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('bar') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(IDENTIFIER)('baz') + PsiWhiteSpace(' ') + PsiComment(EOL_COMMENT)('// binary expression labeled `bar` and return as second arg') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/spaceBeforeLabelReference.kt b/compiler/testData/psi/newLabels/spaceBeforeLabelReference.kt new file mode 100644 index 00000000000..223ca65bda5 --- /dev/null +++ b/compiler/testData/psi/newLabels/spaceBeforeLabelReference.kt @@ -0,0 +1,30 @@ +fun foo() { + break @l1 + + val x = 1 + + return @l2 1 + + val x = 2 + + return @l3 + + val x = 3 + + continue @l4 5 + + val x = 6 + + break/**/@l5 + + val x = 7 + + return /**/@l6 + + val x = 8 + + return// +@l7 4 + + val x = 9 +} \ No newline at end of file diff --git a/compiler/testData/psi/newLabels/spaceBeforeLabelReference.txt b/compiler/testData/psi/newLabels/spaceBeforeLabelReference.txt new file mode 100644 index 00000000000..dba7c3cc185 --- /dev/null +++ b/compiler/testData/psi/newLabels/spaceBeforeLabelReference.txt @@ -0,0 +1,152 @@ +JetFile: spaceBeforeLabelReference.kt + PACKAGE_DIRECTIVE + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BREAK + PsiElement(break)('break') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('l1') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('l2') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('l3') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace('\n\n ') + CONTINUE + PsiElement(continue)('continue') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('l4') + PsiWhiteSpace(' ') + PsiElement(INTEGER_LITERAL)('5') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('6') + PsiWhiteSpace('\n\n ') + BREAK + PsiElement(break)('break') + PsiComment(BLOCK_COMMENT)('/**/') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(AT)('@') + PsiElement(IDENTIFIER)('l5') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('7') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiWhiteSpace(' ') + PsiComment(BLOCK_COMMENT)('/**/') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('l6') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('8') + PsiWhiteSpace('\n\n ') + RETURN + PsiElement(return)('return') + PsiComment(EOL_COMMENT)('//') + PsiWhiteSpace('\n') + LABELED_EXPRESSION + PsiErrorElement:Label must be named + PsiElement(AT)('@') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('l7') + PsiWhiteSpace(' ') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(INTEGER_LITERAL)('4') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('9') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java index 05ffb9008e7..71835506927 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java @@ -1201,6 +1201,39 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { } } + @TestMetadata("compiler/testData/psi/newLabels") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NewLabels extends AbstractJetParsingTest { + public void testAllFilesPresentInNewLabels() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/newLabels"), Pattern.compile("^(.*)\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/newLabels/basic.kt"); + doParsingTest(fileName); + } + + @TestMetadata("oldSyntaxExpressions.kt") + public void testOldSyntaxExpressions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/newLabels/oldSyntaxExpressions.kt"); + doParsingTest(fileName); + } + + @TestMetadata("recovery.kt") + public void testRecovery() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/newLabels/recovery.kt"); + doParsingTest(fileName); + } + + @TestMetadata("spaceBeforeLabelReference.kt") + public void testSpaceBeforeLabelReference() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/newLabels/spaceBeforeLabelReference.kt"); + doParsingTest(fileName); + } + } + @TestMetadata("compiler/testData/psi/packages") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index 5cd70d74f52..de6d4c01dbe 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -8,7 +8,7 @@ | Precedence | Title | Symbols | |------------|-------|---------| | Highest | Postfix | `++`, `--`, `.`, `?.`, `?` | -| | Prefix | `-`, `+`, `++`, `--`, `!`, [`@label`](#LabelName), `@`, `@@` | +| | Prefix | `-`, `+`, `++`, `--`, `!`, [`labelDefinition@`](#IDENTIFIER)`@` | | | Type RHS | `:`, `as`, `as?` | | | Multiplicative | `*`, `/`, `%` | | | Additive | `+`, `-` | @@ -112,8 +112,8 @@ atomicExpression : "(" expression ")" : literalConstant : functionLiteral - : "this" label? - : "super" ("<" type ">")? label? + : "this" labelReference? + : "super" ("<" type ">")? labelReference? : if : when : try @@ -125,10 +125,12 @@ atomicExpression : "package" // for the root package ; -label - : "@" - : "@@" - : LabelName +labelReference + : "@" LabelName + ; + +labelDefinition + : LabelName "@" ; literalConstant @@ -212,7 +214,7 @@ prefixUnaryOperation : "++" : "--" : "!" // No ~ : annotations // mandatory - : label + : labelDefinition ; postfixUnaryOperation @@ -223,8 +225,8 @@ postfixUnaryOperation ; callSuffix - : typeArguments? valueArguments (label? functionLiteral) - : typeArguments (label? functionLiteral) + : typeArguments? valueArguments (labelDefinition? functionLiteral) + : typeArguments (labelDefinition? functionLiteral) ; memberAccessOperation @@ -241,9 +243,9 @@ valueArguments jump : "throw" expression - : "return" label? expression? - : "continue" label? - : "break" label? + : "return" labelReference? expression? + : "continue" labelReference? + : "break" labelReference? // yield ? ;