From 621a51e856c5e6b435849ceb739dd6d92d1acefc Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 2 Jan 2011 16:30:18 +0300 Subject: [PATCH] Passing closures outside parentheses. !!! A hack for by clause --- grammar/src/class.grm | 2 +- .../jet/lang/parsing/AbstractJetParsing.java | 6 +- .../lang/parsing/JetExpressionParsing.java | 26 +- .../jetbrains/jet/lang/parsing/JetParser.java | 2 +- .../jet/lang/parsing/JetParsing.java | 35 ++- idea/testData/psi/FunctionCalls.jet | 30 ++ idea/testData/psi/FunctionCalls.txt | 262 ++++++++++++++++++ .../jetbrains/jet/parsing/JetParsingTest.java | 1 + 8 files changed, 351 insertions(+), 13 deletions(-) create mode 100644 idea/testData/psi/FunctionCalls.jet create mode 100644 idea/testData/psi/FunctionCalls.txt diff --git a/grammar/src/class.grm b/grammar/src/class.grm index 658ef24caa6..68cff07020f 100644 --- a/grammar/src/class.grm +++ b/grammar/src/class.grm @@ -34,7 +34,7 @@ delegationSpecifier ; explicitDelegation - : userType "by" expression // TODO: Syntax is questionable + : userType "by" expression // internal this expression no foo {bar} is allowed // TODO: Syntax is questionable ; typeParameter diff --git a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java index 6a9ac1dec9f..62bd31c7463 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/AbstractJetParsing.java @@ -12,7 +12,7 @@ import static org.jetbrains.jet.lexer.JetTokens.*; /** * @author abreslav */ -/*package*/ class AbstractJetParsing { +/*package*/ abstract class AbstractJetParsing { protected final SemanticWhitespaceAwarePsiBuilder myBuilder; public AbstractJetParsing(SemanticWhitespaceAwarePsiBuilder builder) { @@ -227,8 +227,10 @@ import static org.jetbrains.jet.lexer.JetTokens.*; return myBuilder.eolInLastWhitespace() || eof(); } + protected abstract JetParsing create(SemanticWhitespaceAwarePsiBuilder builder); + protected JetParsing createTruncatedBuilder(int eofPosition) { - return new JetParsing(new TruncatedSemanticWhitespaceAwarePsiBuilder(myBuilder, eofPosition)); + return create(new TruncatedSemanticWhitespaceAwarePsiBuilder(myBuilder, eofPosition)); } protected class AtOffset implements TokenStreamPredicate { diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 06a4d1642c8..6eb305071cc 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -67,7 +67,6 @@ public class JetExpressionParsing extends AbstractJetParsing { EQUALITY(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ), CONJUNCTION(ANDAND), DISJUNCTION(OROR), - // TODO: RHS MATCH(MATCH_KEYWORD) { @Override public void parseRightHandSide(JetExpressionParsing parsing) { @@ -185,10 +184,8 @@ public class JetExpressionParsing extends AbstractJetParsing { */ private void parsePostfixExpression() { // System.out.println("post at " + myBuilder.getTokenText()); - // TODO: call with a closure outside parentheses PsiBuilder.Marker expression = mark(); -// parseBinaryExpression(Precedence.MEMBER_ACCESS); parseAtomicExpression(); while (true) { if (myBuilder.eolInLastWhitespace()) { @@ -199,8 +196,11 @@ public class JetExpressionParsing extends AbstractJetParsing { } else if (atSet(Precedence.POSTFIX.getOperations())) { advance(); // operation expression.done(POSTFIX_EXPRESSION); + } else if (parseCallWithClosure()) { + expression.done(CALL_EXPRESSION); } else if (at(LPAR)) { parseValueArgumentList(); + parseCallWithClosure(); expression.done(CALL_EXPRESSION); } else if (at(LT)) { // TODO: be (even) more clever @@ -212,7 +212,8 @@ public class JetExpressionParsing extends AbstractJetParsing { }); if (gtPos >= 0) { myJetParsing.parseTypeArgumentList(); - if (at(LPAR)) parseValueArgumentList(); + if (!myBuilder.eolInLastWhitespace() && at(LPAR)) parseValueArgumentList(); + parseCallWithClosure(); expression.done(CALL_EXPRESSION); } else { break; @@ -243,6 +244,17 @@ public class JetExpressionParsing extends AbstractJetParsing { expression.drop(); } + /* + * expression functionLiteral? + */ + protected boolean parseCallWithClosure() { + if (!myBuilder.eolInLastWhitespace() && at(LBRACE)) { + parseFunctionLiteral(); + return true; + } + return false; + } + /* * atomicExpression * : tupleLiteral // or parenthesized expression @@ -384,7 +396,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * matchEntry - * : attributes "case" pattern ("if" "(" expression ")")? "=>" expression SEMI? // TODO: Consider other options than "=>" + * : attributes "case" pattern ("if" "(" expression ")")? "=>" expression SEMI? * ; */ private void parseMatchEntry() { @@ -1125,4 +1137,8 @@ public class JetExpressionParsing extends AbstractJetParsing { mark.done(type); } + @Override + protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { + return myJetParsing.create(builder); + } } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParser.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParser.java index f159894d94c..d5a8689c13f 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParser.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParser.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; public class JetParser implements PsiParser { @NotNull public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder) { - new JetParsing(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder)).parseFile(); + JetParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder)).parseFile(); return psiBuilder.getTreeBuilt(); } } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 0be69b16ac3..7670d42d5c6 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -40,11 +40,32 @@ public class JetParsing extends AbstractJetParsing { private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON); /*package*/ static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR); - private final JetExpressionParsing myExpressionParsing; + public static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) { + JetParsing jetParsing = new JetParsing(builder); + jetParsing.myExpressionParsing = new JetExpressionParsing(builder, jetParsing); + return jetParsing; + } - public JetParsing(SemanticWhitespaceAwarePsiBuilder builder) { + public static JetParsing createForByClause(final SemanticWhitespaceAwarePsiBuilder builder) { + JetParsing jetParsing = new JetParsing(builder); + jetParsing.myExpressionParsing = new JetExpressionParsing(builder, jetParsing) { + @Override + protected boolean parseCallWithClosure() { + return false; + } + + @Override + protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { + return createForByClause(builder); + } + }; + return jetParsing; + } + + private JetExpressionParsing myExpressionParsing; + + private JetParsing(SemanticWhitespaceAwarePsiBuilder builder) { super(builder); - this.myExpressionParsing = new JetExpressionParsing(builder, this); } /* @@ -979,7 +1000,8 @@ public class JetParsing extends AbstractJetParsing { if (at(BY_KEYWORD)) { advance(); // BY_KEYWORD - myExpressionParsing.parseExpression(); + // TODO: discuss: in nested expressions (including method bodies) one cannot use foo {bar} either, but this is required only for the top level + createForByClause(myBuilder).myExpressionParsing.parseExpression(); delegator.done(DELEGATOR_BY); } else if (at(LPAR)) { @@ -1422,6 +1444,11 @@ public class JetParsing extends AbstractJetParsing { parameter.done(VALUE_PARAMETER); } + @Override + protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { + return createForTopLevel(builder); + } + /*package*/ static class EnumDetector implements Consumer { private boolean myEnum = false; diff --git a/idea/testData/psi/FunctionCalls.jet b/idea/testData/psi/FunctionCalls.jet new file mode 100644 index 00000000000..42161ea63ae --- /dev/null +++ b/idea/testData/psi/FunctionCalls.jet @@ -0,0 +1,30 @@ +fun foo() { + f(a) + f(a) + f + (a) + f {s} + f + {s} + f { + s + } + f(a) { + s + } + f(a) + { + s + } + f(a) { + s + } + f(a) + { + s + } + f(foo) + f(foo(a)) + f(foo(a)) + f(foo(a)) +} \ No newline at end of file diff --git a/idea/testData/psi/FunctionCalls.txt b/idea/testData/psi/FunctionCalls.txt new file mode 100644 index 00000000000..9ea157a38d8 --- /dev/null +++ b/idea/testData/psi/FunctionCalls.txt @@ -0,0 +1,262 @@ +JetFile: FunctionCalls.jet + NAMESPACE + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + TYPE_PARAMETER_LIST + + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('foo') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('foo') + PsiElement(GT)('>') + PsiWhiteSpace('\n ') + TUPLE + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + PsiWhiteSpace(' ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BODY + PsiElement(IDENTIFIER)('s') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + PsiElement(IDENTIFIER)('f') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + BODY + PsiElement(IDENTIFIER)('s') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + PsiWhiteSpace(' ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + PsiElement(IDENTIFIER)('s') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + PsiElement(IDENTIFIER)('s') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + PsiElement(IDENTIFIER)('s') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('a') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + PsiElement(IDENTIFIER)('s') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + PsiElement(IDENTIFIER)('f') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_REFERENCE + USER_TYPE + PsiElement(IDENTIFIER)('a') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BODY + PsiElement(IDENTIFIER)('s') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + 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)('>') + 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)('a') + 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 + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + TUPLE + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('a') + 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 + TUPLE + PsiElement(LPAR)('(') + BINARY_EXPRESSION + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace(' ') + PsiElement(PLUS)('+') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(RPAR)(')') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_ARGUMENT + BINARY_EXPRESSION + PsiElement(IDENTIFIER)('b') + PsiElement(GT)('>') + TUPLE + PsiElement(LPAR)('(') + PsiElement(IDENTIFIER)('a') + PsiElement(RPAR)(')') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java index fd957c86683..fa3c5b17a71 100644 --- a/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java +++ b/idea/tests/org/jetbrains/jet/parsing/JetParsingTest.java @@ -42,6 +42,7 @@ public class JetParsingTest extends ParsingTestCase { public void testExtensions() throws Exception {doTest(true);} public void testExtensions_ERR() throws Exception {doTest(true);} public void testFileStart_ERR() throws Exception {doTest(true);} + public void testFunctionCalls() throws Exception {doTest(true);} public void testFunctionLiterals() throws Exception {doTest(true);} public void testFunctionLiterals_ERR() throws Exception {doTest(true);} public void testFunctions() throws Exception {doTest(true);}