From 08e1276e41a02b9aedde88cc7a15b23893abe086 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 30 Dec 2010 16:38:30 +0300 Subject: [PATCH] f(foo(x)) is parsed as a call(call(...)) --- grammar/src/expressions.grm | 4 +- .../lang/parsing/JetExpressionParsing.java | 29 +++++- .../jet/lang/parsing/JetParsing.java | 2 +- idea/testData/psi/Precedence.jet | 4 + idea/testData/psi/Precedence.txt | 88 +++++++++++++++++++ 5 files changed, 123 insertions(+), 4 deletions(-) diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index aa51044370b..a9effdbb696 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -58,7 +58,7 @@ elvisOperation // ATTENTION infixFunctionCall - : rangeExpression (SimpleName (typeParameters | rangeExpression))* + : rangeExpression (SimpleName (typeArguments | rangeExpression))* ; rangeExpression @@ -168,7 +168,7 @@ prefixUnaryOperation postfixUnaryOperation : "++" : "--" : typeArguments? valueArguments - : typeArguments + // : typeArguments // TODO: : arrayAccess ; diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 4cd5a1cc3d8..5231a6de9b8 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -14,6 +14,17 @@ import static org.jetbrains.jet.lexer.JetTokens.*; */ public class JetExpressionParsing extends AbstractJetParsing { private final JetParsing myJetParsing; + private static final TokenSet TYPE_ARGUMENT_LIST_STOPPERS = TokenSet.create( + INTEGER_LITERAL, LONG_LITERAL, FLOAT_LITERAL, CHARACTER_LITERAL, STRING_LITERAL, RAW_STRING_LITERAL, + NAMESPACE_KEYWORD, AS_KEYWORD, TYPE_KEYWORD, CLASS_KEYWORD, THIS_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, + FUN_KEYWORD, DECOMPOSER_KEYWORD, EXTENSION_KEYWORD, FOR_KEYWORD, NULL_KEYWORD, TYPEOF_KEYWORD, + NEW_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_KEYWORD, + CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD, TRY_KEYWORD, ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, + MATCH_KEYWORD, RBRACKET, RBRACE, RPAR, PLUSPLUS, MINUSMINUS, MUL, PLUS, MINUS, EXCL, DIV, PERC, LTEQ, + // TODO GTEQ, + EQEQEQ, ARROW, DOUBLE_ARROW, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS, QUEST, + SEMICOLON, RANGE, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS, HASH, EOL_OR_SEMICOLON + ); public JetExpressionParsing(SemanticWhitespaceAwarePsiBuilder builder, JetParsing jetParsing) { super(builder); @@ -29,7 +40,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } }, - POSTFIX(PLUSPLUS, MINUSMINUS), // valueArguments : arrayAccess + POSTFIX(PLUSPLUS, MINUSMINUS), // typeArguments? valueArguments : arrayAccess PREFIX(MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL) { // attributes @@ -173,6 +184,22 @@ public class JetExpressionParsing extends AbstractJetParsing { } else if (at(LPAR)) { parseValueArgumentList(); expression.done(CALL_EXPRESSION); + } else if (at(LT)) { + // TODO: be more clever: f(foo(c)) is not a function call + int gtPos = matchTokenStreamPredicate(new FirstBefore(new At(GT), new AtSet(TYPE_ARGUMENT_LIST_STOPPERS, false)) { + @Override + public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) { + return openAngleBrackets == 1 && openBrackets == 0 && openBraces == 0 && openParentheses == 0; + } + }); + if (gtPos >= 0) { + myJetParsing.parseTypeArgumentList(); +// if (at(LPAR)) parseValueArgumentList(); TODO : we can do this... + parseValueArgumentList(); + expression.done(CALL_EXPRESSION); + } else { + expression.drop(); + } } else { expression.drop(); } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 77eb34b705d..4483567250f 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -1215,7 +1215,7 @@ public class JetParsing extends AbstractJetParsing { /* * (optionalProjection type){","} */ - private void parseTypeArgumentList() { + public void parseTypeArgumentList() { if (!at(LT)) return; PsiBuilder.Marker list = mark(); diff --git a/idea/testData/psi/Precedence.jet b/idea/testData/psi/Precedence.jet index 50d46e09699..e62234233f2 100644 --- a/idea/testData/psi/Precedence.jet +++ b/idea/testData/psi/Precedence.jet @@ -1,4 +1,8 @@ fun foo() { + f(foo(x))) + f(foo(x)) + f((foo(x)) + f(foo') + TUPLE + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('x') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + CALL_EXPRESSION + PsiElement(IDENTIFIER)('foo') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('x') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + TUPLE + PsiElement(LPAR)('(') + BINARY_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(LT)('<') + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + TUPLE + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('x') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + BINARY_EXPRESSION + PsiElement(IDENTIFIER)('foo') + PsiElement(LT)('<') + PsiElement(IDENTIFIER)('a') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('b') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') BINARY_EXPRESSION PsiElement(IDENTIFIER)('a') PsiWhiteSpace(' ')