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 13c3bc23c67..1d2166f6e60 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -343,7 +343,36 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * atomicExpression postfixUnaryOperation? + * callableReference + * : userType? "::" SimpleName + * ; + */ + private boolean parseCallableReferenceExpression() { + PsiBuilder.Marker expression = mark(); + + if (!at(COLONCOLON)) { + PsiBuilder.Marker typeReference = mark(); + myJetParsing.parseUserType(); + typeReference.done(TYPE_REFERENCE); + if (!at(COLONCOLON)) { + expression.rollbackTo(); + return false; + } + } + + advance(); // COLONCOLON + + parseSimpleNameExpression(); + expression.done(CALLABLE_REFERENCE_EXPRESSION); + + return true; + } + + /* + * postfixUnaryExpression + * : atomicExpression postfixUnaryOperation* + * : callableReference postfixUnaryOperation* + * ; * * postfixUnaryOperation * : "++" : "--" : "!!" @@ -354,10 +383,13 @@ public class JetExpressionParsing extends AbstractJetParsing { * ; */ private void parsePostfixExpression() { -// System.out.println("post at " + myBuilder.getTokenText()); - PsiBuilder.Marker expression = mark(); - parseAtomicExpression(); + + boolean callableReference = parseCallableReferenceExpression(); + if (!callableReference) { + parseAtomicExpression(); + } + while (true) { if (interruptedWithNewLine()) { break; @@ -366,7 +398,7 @@ public class JetExpressionParsing extends AbstractJetParsing { parseArrayAccess(); expression.done(ARRAY_ACCESS_EXPRESSION); } - else if (parseCallSuffix()) { + else if (!callableReference && parseCallSuffix()) { expression.done(CALL_EXPRESSION); } else if (at(DOT)) { @@ -383,13 +415,6 @@ public class JetExpressionParsing extends AbstractJetParsing { expression.done(SAFE_ACCESS_EXPRESSION); } -// else if (at(HASH)) { -// advance(); // HASH -// -// expect(IDENTIFIER, "Expecting property or function name"); -// -// expression.done(HASH_QUALIFIED_EXPRESSION); -// } else if (atSet(Precedence.POSTFIX.getOperations())) { parseOperationReference(); expression.done(POSTFIX_EXPRESSION); 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 23cbdf9da9f..526e41fae7a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -1452,7 +1452,7 @@ public class JetParsing extends AbstractJetParsing { * : ("namespace" ".")? simpleUserType{"."} * ; */ - private void parseUserType() { + void parseUserType() { PsiBuilder.Marker userType = mark(); if (at(PACKAGE_KEYWORD)) { diff --git a/compiler/testData/psi/DoubleColon.jet b/compiler/testData/psi/DoubleColon.jet new file mode 100644 index 00000000000..bf44a1c132d --- /dev/null +++ b/compiler/testData/psi/DoubleColon.jet @@ -0,0 +1,42 @@ +fun ok() { + A::a + A::a + 1 + Map::size + + ::a + + a.b::c + a::b.c + a.b::c.d + + a::c + a::c.d + a.b::d + a.b::d.e + a.b::e + a.b::e.d + a.b>::g.h + + a.b.c.e.g::h + + a::b() + (a::b)() + a.(b::c)() + a.b::c() +} + +fun err0() { + a::b.c::d +} + +fun err1() { + A:: +} + +fun err2() { + A::a::b +} + +fun err3() { + :: +} diff --git a/compiler/testData/psi/DoubleColon.txt b/compiler/testData/psi/DoubleColon.txt new file mode 100644 index 00000000000..f4b20260a2d --- /dev/null +++ b/compiler/testData/psi/DoubleColon.txt @@ -0,0 +1,492 @@ +JetFile: DoubleColon.jet + NAMESPACE_HEADER + + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('ok') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Map') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('String') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('size') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('e') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('e') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('e') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('e') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + PsiElement(GT)('>') + PsiElement(GT)('>') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('g') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('h') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + USER_TYPE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('d') + PsiElement(GT)('>') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('e') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + PsiElement(GT)('>') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('g') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('h') + PsiWhiteSpace('\n\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PARENTHESIZED + PsiElement(LPAR)('(') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(RPAR)(')') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + CALL_EXPRESSION + PARENTHESIZED + PsiElement(LPAR)('(') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiElement(RPAR)(')') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('err0') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + DOT_QUALIFIED_EXPRESSION + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('c') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(COLONCOLON)('::') + PsiElement(IDENTIFIER)('d') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('err1') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(COLONCOLON)('::') + PsiWhiteSpace('\n') + REFERENCE_EXPRESSION + PsiErrorElement:Expecting an identifier + + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('err2') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(COLONCOLON)('::') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('a') + PsiErrorElement:Unexpected tokens (use ';' to separate expressions on the same line) + PsiElement(COLONCOLON)('::') + PsiElement(IDENTIFIER)('b') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('err3') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALLABLE_REFERENCE_EXPRESSION + PsiElement(COLONCOLON)('::') + PsiWhiteSpace('\n') + REFERENCE_EXPRESSION + PsiErrorElement:Expecting an identifier + + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index dbb3a9e7279..727a93e6edd 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -99,6 +99,12 @@ prefixUnaryExpression postfixUnaryExpression : atomicExpression postfixUnaryOperation* + : callableReference postfixUnaryOperation* + ; + +// TODO: callSuffix is forbidden after callableReference, since parentheses will be used to provide parameter types +callableReference + : userType? "::" SimpleName ; // !!! When you add here, remember to update the FIRST set in the parser