From 6bad4830c34c6c8df6cabc384d90f4cd3900bf2a Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 21 Dec 2011 10:52:58 +0200 Subject: [PATCH] Graet Syntactic Shift : Syntax for function literals fixed --- .../lang/parsing/JetExpressionParsing.java | 235 +++++++++++++----- .../jet/lang/parsing/JetParsing.java | 13 +- .../jet/lang/resolve/TypeResolver.java | 4 +- compiler/testData/cfg/Basic.instructions | 16 +- compiler/testData/cfg/Basic.jet | 2 +- ...unctionTypes.kt => ShiftFunctionTypes.jet} | 0 .../greatSyntacticShift/functionLiterals.jet | 43 ++++ .../org/jetbrains/jet/JetTestCaseBuilder.java | 2 +- .../jet/checkers/JetDiagnosticsTest.java | 3 +- .../jet/codegen/PatternMatchingTest.java | 2 +- 10 files changed, 234 insertions(+), 86 deletions(-) rename compiler/testData/diagnostics/tests/{ShiftFunctionTypes.kt => ShiftFunctionTypes.jet} (100%) create mode 100644 compiler/testData/psi/greatSyntacticShift/functionLiterals.jet 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 f84ec2f38cd..0c55185fe81 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -1082,83 +1082,112 @@ public class JetExpressionParsing extends AbstractJetParsing { myBuilder.enableNewlines(); advance(); // LBRACE - int doubleArrowPos = matchTokenStreamPredicate(new FirstBefore(new At(ARROW), new At(RBRACE)) { - @Override - public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) { - return openBraces == 0; + boolean paramsFound = false; + + if (at(ARROW)) { + // { -> ...} + advance(); // ARROW + mark().done(VALUE_PARAMETER_LIST); + paramsFound = true; + } + else if (at(LPAR)) { + // Look for ARROW after matching RPAR + // {(a, b) -> ...} + + { + PsiBuilder.Marker rollbackMarker = mark(); + + parseFunctionLiteralParametersAndType(); + + paramsFound = rollbackOrDropAt(rollbackMarker, ARROW); } - }); - boolean doubleArrowPresent = doubleArrowPos >= 0; - if (doubleArrowPresent) { - boolean dontExpectParameters = false; - - int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtOffset(doubleArrowPos))); - if (lastDot >= 0) { // There is a receiver type - createTruncatedBuilder(lastDot).parseTypeRef(); - - expect(DOT, "Expecting '.'"); - - if (!at(LPAR)) { - int firstLParPos = matchTokenStreamPredicate(new FirstBefore(new At(LPAR), new AtOffset(doubleArrowPos))); - - if (firstLParPos >= 0) { - errorUntilOffset("Expecting '('", firstLParPos); - } else { - errorUntilOffset("To specify a receiver type, use the full notation: {ReceiverType.(parameters) [: ReturnType] => ...}", - doubleArrowPos); - dontExpectParameters = true; + if (!paramsFound) { + // If not found, try a typeRef DOT and then LPAR .. RPAR ARROW + // {((A) -> B).(x) -> ... } + PsiBuilder.Marker rollbackMarker = mark(); + int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtSet(ARROW, RPAR))); + if (lastDot >= 0) { + createTruncatedBuilder(lastDot).parseTypeRef(); + if (at(DOT)) { + advance(); // DOT + parseFunctionLiteralParametersAndType(); } } + paramsFound = rollbackOrDropAt(rollbackMarker, ARROW); } - - if (at(LPAR)) { - parseFunctionLiteralParameterList(); - - if (at(COLON)) { - advance(); // COLON - if (at(ARROW)) { - error("Expecting a type"); - } - else { - myJetParsing.parseTypeRef(); - } - } - } - else if (!dontExpectParameters) { - PsiBuilder.Marker parameterList = mark(); - - while (!eof()) { - PsiBuilder.Marker parameter = mark(); - - int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtOffset(doubleArrowPos))); - createTruncatedBuilder(parameterNamePos).parseModifierList(MODIFIER_LIST, false); - - expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(ARROW)); - - parameter.done(VALUE_PARAMETER); - - if (at(COLON)) { - errorUntilOffset("To specify a type of a parameter or a return type, use the full notation: {(parameter : Type) : ReturnType => ...}", doubleArrowPos); - } - else if (at(ARROW)) { - break; - } - else if (!at(COMMA)) { - errorUntilOffset("Expecting '=>' or ','", doubleArrowPos); - } - else { - advance(); // COMMA - } - } - - parameterList.done(VALUE_PARAMETER_LIST); - } - - expectNoAdvance(ARROW, "Expecting '=>'"); } else { + if (at(IDENTIFIER)) { + // Try to parse a simple name list followed by an ARROW + // {a -> ...} + // {a, b -> ...} + PsiBuilder.Marker rollbackMarker = mark(); + parseFunctionLiteralShorthandParameterList(); + parseOptionalFunctionLiteralType(); + paramsFound = rollbackOrDropAt(rollbackMarker, ARROW); + } + if (!paramsFound && atSet(JetParsing.TYPE_REF_FIRST)) { + // Try to parse a type DOT valueParameterList ARROW + // {A.(b) -> ...} + PsiBuilder.Marker rollbackMarker = mark(); + int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtSet(ARROW, RBRACE))); + if (lastDot >= 0) { // There is a receiver type + createTruncatedBuilder(lastDot).parseTypeRef(); + } + + if (at(DOT)) { + advance(); // DOT + parseFunctionLiteralParametersAndType(); + paramsFound = rollbackOrDropAt(rollbackMarker, ARROW); + } + else { + rollbackMarker.rollbackTo(); + } + } +// int doubleArrowPos = matchTokenStreamPredicate(new FirstBefore(new At(ARROW), new At(RBRACE)) { +// @Override +// public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) { +// return openBraces == 0; +// } +// }); +// +// boolean doubleArrowPresent = doubleArrowPos >= 0; +// if (doubleArrowPresent) { +// boolean dontExpectParameters = false; +// +// int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtOffset(doubleArrowPos))); +// if (lastDot >= 0) { // There is a receiver type +// createTruncatedBuilder(lastDot).parseTypeRef(); +// +// expect(DOT, "Expecting '.'"); +// +// if (!at(LPAR)) { +// int firstLParPos = matchTokenStreamPredicate(new FirstBefore(new At(LPAR), new AtOffset(doubleArrowPos))); +// +// if (firstLParPos >= 0) { +// errorUntilOffset("Expecting '('", firstLParPos); +// } else { +// errorUntilOffset("To specify a receiver type, use the full notation: {ReceiverType.(parameters) [: ReturnType] => ...}", +// doubleArrowPos); +// dontExpectParameters = true; +// } +// } +// +// } +// +// if (at(LPAR)) { +// parseFunctionLiteralParametersAndType(); +// } +// else if (!dontExpectParameters) { +// parseFunctionLiteralShorthandParameterList(); +// } +// +// expectNoAdvance(ARROW, "Expecting '=>'"); +// } + } + if (!paramsFound) { if (preferBlock) { literal.drop(); parseStatements(); @@ -1180,6 +1209,74 @@ public class JetExpressionParsing extends AbstractJetParsing { literalExpression.done(FUNCTION_LITERAL_EXPRESSION); } + private boolean rollbackOrDropAt(PsiBuilder.Marker rollbackMarker, IElementType dropAt) { + if (at(dropAt)) { + advance(); // dropAt + rollbackMarker.drop(); + return true; + } + rollbackMarker.rollbackTo(); + return false; + } + + /* + * SimpleName{,} + */ + private void parseFunctionLiteralShorthandParameterList() { + PsiBuilder.Marker parameterList = mark(); + + while (!eof()) { + PsiBuilder.Marker parameter = mark(); + +// int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtOffset(doubleArrowPos))); +// createTruncatedBuilder(parameterNamePos).parseModifierList(MODIFIER_LIST, false); + + expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(ARROW)); + + parameter.done(VALUE_PARAMETER); + + if (at(COLON)) { + PsiBuilder.Marker errorMarker = mark(); + advance(); // COLON + myJetParsing.parseTypeRef(); + errorMarker.error("To specify a type of a parameter or a return type, use the full notation: {(parameter : Type) : ReturnType => ...}"); + } + else if (at(ARROW)) { + break; + } + else if (at(COMMA)) { + advance(); // COMMA + } + else { + error("Expecting '->' or ','"); + break; + } + } + + parameterList.done(VALUE_PARAMETER_LIST); + } + + private void parseFunctionLiteralParametersAndType() { + parseFunctionLiteralParameterList(); + + parseOptionalFunctionLiteralType(); + } + + /* + * (":" type)? + */ + private void parseOptionalFunctionLiteralType() { + if (at(COLON)) { + advance(); // COLON + if (at(ARROW)) { + error("Expecting a type"); + } + else { + myJetParsing.parseTypeRef(); + } + } + } + /* * "(" (modifiers SimpleName (":" type)?){","} ")" */ 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 716a830cafc..fc890c3d2b8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -1354,7 +1354,13 @@ public class JetParsing extends AbstractJetParsing { typeRefMarker.done(TYPE_REFERENCE); advance(); // DOT - parseFunctionTypeContents().drop(); + + if (at(LPAR)) { + parseFunctionTypeContents().drop(); + } + else { + error("Expecting function type"); + } typeRefMarker = precede.precede(); precede.done(FUNCTION_TYPE); @@ -1519,8 +1525,9 @@ public class JetParsing extends AbstractJetParsing { } private PsiBuilder.Marker parseFunctionTypeContents() { - assert _at(LPAR) : tt(); -// +// assert _at(LPAR) : tt(); + if (!_at(LPAR)) + System.out.println(myBuilder.getTokenText()); PsiBuilder.Marker functionType = mark(); // advance(); // LPAR diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 8501f499d9f..35cd9d738a7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE; +import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED; import static org.jetbrains.jet.lang.diagnostics.Errors.WRONG_NUMBER_OF_TYPE_ARGUMENTS; import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; @@ -173,7 +174,8 @@ public class TypeResolver { @Override public void visitJetElement(JetElement element) { - throw new IllegalArgumentException("Unsupported type: " + element); + trace.report(UNSUPPORTED.on(element, "Self-types are not supported yet")); +// throw new IllegalArgumentException("Unsupported type: " + element); } }); } diff --git a/compiler/testData/cfg/Basic.instructions b/compiler/testData/cfg/Basic.instructions index 970f555349b..fb9dddf0e69 100644 --- a/compiler/testData/cfg/Basic.instructions +++ b/compiler/testData/cfg/Basic.instructions @@ -121,17 +121,17 @@ sink: NEXT:[] PREV:[] ===================== == flfun == -fun flfun(f : fun () : Any) : Unit {} +fun flfun(f : () -> Any) : Unit {} --------------------- l0: - NEXT:[v(f : fun () : Any)] PREV:[] - v(f : fun () : Any) NEXT:[w(f)] PREV:[] - w(f) NEXT:[read (Unit)] PREV:[v(f : fun () : Any)] - read (Unit) NEXT:[] PREV:[w(f)] + NEXT:[v(f : () -> Any)] PREV:[] + v(f : () -> Any) NEXT:[w(f)] PREV:[] + w(f) NEXT:[read (Unit)] PREV:[v(f : () -> Any)] + read (Unit) NEXT:[] PREV:[w(f)] l1: - NEXT:[] PREV:[read (Unit)] + NEXT:[] PREV:[read (Unit)] error: - NEXT:[] PREV:[] + NEXT:[] PREV:[] sink: - NEXT:[] PREV:[] + NEXT:[] PREV:[] ===================== diff --git a/compiler/testData/cfg/Basic.jet b/compiler/testData/cfg/Basic.jet index 870c40513a0..f71bf2fd807 100644 --- a/compiler/testData/cfg/Basic.jet +++ b/compiler/testData/cfg/Basic.jet @@ -20,4 +20,4 @@ fun foo(a : Boolean, b : Int) : Unit {} fun genfun() : Unit {} -fun flfun(f : fun () : Any) : Unit {} \ No newline at end of file +fun flfun(f : () -> Any) : Unit {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/ShiftFunctionTypes.kt b/compiler/testData/diagnostics/tests/ShiftFunctionTypes.jet similarity index 100% rename from compiler/testData/diagnostics/tests/ShiftFunctionTypes.kt rename to compiler/testData/diagnostics/tests/ShiftFunctionTypes.jet diff --git a/compiler/testData/psi/greatSyntacticShift/functionLiterals.jet b/compiler/testData/psi/greatSyntacticShift/functionLiterals.jet new file mode 100644 index 00000000000..345d07943ad --- /dev/null +++ b/compiler/testData/psi/greatSyntacticShift/functionLiterals.jet @@ -0,0 +1,43 @@ +class Foo +class Bar + +fun a(vararg a : Any) = a + +fun test() { +a(1 +, {} +, { -> 1} +, {1} +, {x} +, {-> 1} +, {x -> 1} +, {x, y -> 1} +, {(x, y) -> 1} +, {(x, y) : Int -> 1} +, {(x) -> 1} +, {(x) : Int -> 1} +, {(x)} +, {(x).(y)} +, {x.(y)} +, {Int.(x) -> 1} +, {A.B.(x) -> 1} +, {A.B.(x, y) -> 1} +, {Int.(x) : Int -> 1} +, {Int.(x, y) -> 1} +, {Int.(x, y) : Int -> 1} +, {(Int).(x, y) -> 1} +, {(Int).(x, y) : Int -> 1} +, {(Int).(x, y) : (Int) -> Int -> {1}} +, {Int? .(x, y) -> 1} +, {This.(x, y) -> 1} +, {#(A, B).(x, y) -> 1} +, {#(a, b).(y)} +, {#(a, b)} +, {Foo.x} +, {Foo.(x)} +, {Foo.(x) -> x} +, {Foo.Bar.Baz.(x) -> x} +, {Foo.(x) : Int -> x} +, {Foo.Bar.Baz.(x) : Int -> x} +) +} diff --git a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java index deee0732f1b..ca7256763fb 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java +++ b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java @@ -48,7 +48,7 @@ public abstract class JetTestCaseBuilder { } public static void appendTestsInDirectory(String baseDataDir, String dataPath, boolean recursive, final FilenameFilter filter, NamedTestFactory factory, TestSuite suite) { - final String extensionJet = ".jet.jet"; + final String extensionJet = ".jet"; final String extensionKt = ".kt"; final FilenameFilter extensionFilter = new FilenameFilter() { @Override diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java index 0660183d5ff..61116f1dfa9 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTest.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.JetTestCaseBuilder; import org.jetbrains.jet.lang.Configuration; -import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.psi.JetDeclaration; @@ -85,7 +84,7 @@ public class JetDiagnosticsTest extends JetLiteFixture { @Override public void runTest() throws Exception { - String testFileName = name + ".kt"; + String testFileName = name + ".jet"; String expectedText = loadFile(testFileName); diff --git a/compiler/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/compiler/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 3c47ffefd74..4643204921f 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -86,7 +86,7 @@ public class PatternMatchingTest extends CodegenTestCase { } public void testTuplePattern() throws Exception { - loadText("fun foo(x: (Any, Any)) = when(x) { is #(1,2) -> \"one,two\"; else -> \"something\" }"); + loadText("fun foo(x: #(Any, Any)) = when(x) { is #(1,2) -> \"one,two\"; else -> \"something\" }"); Method foo = generateFunction(); final Object result; try {