LambdaParserTest.java revision 3019:176472b94f2e
1/*
2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 7115050 8003280 8005852 8006694 8129962
27 * @summary Add lambda tests
28 *  Add parser support for lambda expressions
29 *  temporarily workaround combo tests are causing time out in several platforms
30 * @library /tools/javac/lib
31 * @modules jdk.compiler/com.sun.tools.javac.api
32 *          jdk.compiler/com.sun.tools.javac.code
33 *          jdk.compiler/com.sun.tools.javac.comp
34 *          jdk.compiler/com.sun.tools.javac.main
35 *          jdk.compiler/com.sun.tools.javac.tree
36 *          jdk.compiler/com.sun.tools.javac.util
37 * @build combo.ComboTestHelper
38
39 * @run main LambdaParserTest
40 */
41
42import java.io.IOException;
43
44import combo.ComboInstance;
45import combo.ComboParameter;
46import combo.ComboTask.Result;
47import combo.ComboTestHelper;
48
49public class LambdaParserTest extends ComboInstance<LambdaParserTest> {
50
51    enum LambdaKind implements ComboParameter {
52        NILARY_EXPR("()->x"),
53        NILARY_STMT("()->{ return x; }"),
54        ONEARY_SHORT_EXPR("#{NAME}->x"),
55        ONEARY_SHORT_STMT("#{NAME}->{ return x; }"),
56        ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"),
57        ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"),
58        TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"),
59        TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }");
60
61        String lambdaTemplate;
62
63        LambdaKind(String lambdaTemplate) {
64            this.lambdaTemplate = lambdaTemplate;
65        }
66
67        @Override
68        public String expand(String optParameter) {
69            return lambdaTemplate;
70        }
71
72        int arity() {
73            switch (this) {
74                case NILARY_EXPR:
75                case NILARY_STMT: return 0;
76                case ONEARY_SHORT_EXPR:
77                case ONEARY_SHORT_STMT:
78                case ONEARY_EXPR:
79                case ONEARY_STMT: return 1;
80                case TWOARY_EXPR:
81                case TWOARY_STMT: return 2;
82                default: throw new AssertionError("Invalid lambda kind " + this);
83            }
84        }
85
86        boolean isShort() {
87            return this == ONEARY_SHORT_EXPR ||
88                    this == ONEARY_SHORT_STMT;
89        }
90    }
91
92    enum LambdaParameterName implements ComboParameter {
93        IDENT("x"),
94        UNDERSCORE("_");
95
96        String nameStr;
97
98        LambdaParameterName(String nameStr) {
99            this.nameStr = nameStr;
100        }
101
102        @Override
103        public String expand(String optParameter) {
104            return nameStr;
105        }
106    }
107
108    enum LambdaParameterKind implements ComboParameter {
109        IMPLICIT(""),
110        EXPLIICT_SIMPLE("A"),
111        EXPLIICT_SIMPLE_ARR1("A[]"),
112        EXPLIICT_SIMPLE_ARR2("A[][]"),
113        EXPLICIT_VARARGS("A..."),
114        EXPLICIT_GENERIC1("A<X>"),
115        EXPLICIT_GENERIC2("A<? extends X, ? super Y>"),
116        EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>..."),
117        EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]"),
118        EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]");
119
120        String parameterType;
121
122        LambdaParameterKind(String parameterType) {
123            this.parameterType = parameterType;
124        }
125
126        boolean explicit() {
127            return this != IMPLICIT;
128        }
129
130        boolean isVarargs() {
131            return this == EXPLICIT_VARARGS ||
132                    this == EXPLICIT_GENERIC2_VARARGS;
133        }
134
135        @Override
136        public String expand(String optParameter) {
137            return parameterType;
138        }
139    }
140
141    enum ModifierKind implements ComboParameter {
142        NONE(""),
143        FINAL("final"),
144        PUBLIC("public");
145
146        String modifier;
147
148        ModifierKind(String modifier) {
149            this.modifier = modifier;
150        }
151
152        boolean compatibleWith(LambdaParameterKind pk) {
153            switch (this) {
154                case PUBLIC: return false;
155                case FINAL: return pk != LambdaParameterKind.IMPLICIT;
156                case NONE: return true;
157                default: throw new AssertionError("Invalid modifier kind " + this);
158            }
159        }
160
161        @Override
162        public String expand(String optParameter) {
163            return modifier;
164        }
165    }
166
167    enum ExprKind implements ComboParameter {
168        NONE("#{LAMBDA}#{SUBEXPR}"),
169        SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"),
170        SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"),
171        DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"),
172        DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"),
173        DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}");
174
175        String expressionTemplate;
176
177        ExprKind(String expressionTemplate) {
178            this.expressionTemplate = expressionTemplate;
179        }
180
181        @Override
182        public String expand(String optParameter) {
183            return expressionTemplate;
184        }
185    }
186
187    enum SubExprKind implements ComboParameter {
188        NONE(""),
189        SELECT_FIELD(".f"),
190        SELECT_METHOD(".f()"),
191        SELECT_NEW(".new Foo()"),
192        POSTINC("++"),
193        POSTDEC("--");
194
195        String subExpression;
196
197        SubExprKind(String subExpression) {
198            this.subExpression = subExpression;
199        }
200
201        @Override
202        public String expand(String optParameter) {
203            return subExpression;
204        }
205    }
206
207    public static void main(String... args) throws Exception {
208        new ComboTestHelper<LambdaParserTest>()
209                .withFilter(LambdaParserTest::redundantTestFilter)
210                .withFilter(LambdaParserTest::badImplicitFilter)
211                .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values())
212                .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values())
213                .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values())
214                .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values())
215                .withDimension("EXPR", ExprKind.values())
216                .withDimension("SUBEXPR", SubExprKind.values())
217                .run(LambdaParserTest::new);
218    }
219
220    LambdaParameterKind[] pks = new LambdaParameterKind[2];
221    ModifierKind[] mks = new ModifierKind[2];
222    LambdaKind lk;
223    LambdaParameterName pn;
224
225    boolean badImplicitFilter() {
226        return !(mks[0] != ModifierKind.NONE && lk.isShort());
227    }
228
229    boolean redundantTestFilter() {
230        for (int i = lk.arity(); i < mks.length ; i++) {
231            if (mks[i].ordinal() != 0) {
232                return false;
233            }
234        }
235        for (int i = lk.arity(); i < pks.length ; i++) {
236            if (pks[i].ordinal() != 0) {
237                return false;
238            }
239        }
240        return true;
241    }
242
243    String template = "class Test {\n" +
244                      "   SAM s = #{EXPR};\n" +
245                      "}";
246
247    @Override
248    public void doWork() throws IOException {
249        check(newCompilationTask()
250                .withSourceFromTemplate(template)
251                .parse());
252    }
253
254    void check(Result<?> res) {
255        boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) ||
256                (lk.arity() > 1 && !mks[1].compatibleWith(pks[1]));
257
258        if (lk.arity() == 2 &&
259                (pks[0].explicit() != pks[1].explicit() ||
260                pks[0].isVarargs())) {
261            errorExpected = true;
262        }
263
264        errorExpected |= pn == LambdaParameterName.UNDERSCORE &&
265                lk.arity() > 0;
266
267        if (errorExpected != res.hasErrors()) {
268            fail("invalid diagnostics for source:\n" +
269                res.compilationInfo() +
270                "\nFound error: " + res.hasErrors() +
271                "\nExpected error: " + errorExpected);
272        }
273    }
274}
275