Mon, 21 Jan 2013 11:16:28 -0800
Merge
1 /*
2 * Copyright (c) 2011, 2013, 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 */
24 /*
25 * @test
26 * @bug 7115050 8003280 8005852
27 * @summary Add lambda tests
28 * Add parser support for lambda expressions
29 * @library ../lib
30 * @build JavacTestingAbstractThreadedTest
31 * @run main LambdaParserTest
32 */
34 import java.net.URI;
35 import java.util.Arrays;
36 import javax.tools.Diagnostic;
37 import javax.tools.JavaFileObject;
38 import javax.tools.SimpleJavaFileObject;
39 import com.sun.source.util.JavacTask;
41 public class LambdaParserTest
42 extends JavacTestingAbstractThreadedTest
43 implements Runnable {
45 enum LambdaKind {
46 NILARY_EXPR("()->x"),
47 NILARY_STMT("()->{ return x; }"),
48 ONEARY_SHORT_EXPR("#PN->x"),
49 ONEARY_SHORT_STMT("#PN->{ return x; }"),
50 ONEARY_EXPR("(#M1 #T1 #PN)->x"),
51 ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"),
52 TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"),
53 TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }");
55 String lambdaTemplate;
57 LambdaKind(String lambdaTemplate) {
58 this.lambdaTemplate = lambdaTemplate;
59 }
61 String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
62 ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) {
63 return lambdaTemplate.replaceAll("#M1", mk1.modifier)
64 .replaceAll("#M2", mk2.modifier)
65 .replaceAll("#T1", pk1.parameterType)
66 .replaceAll("#T2", pk2.parameterType)
67 .replaceAll("#PN", pn.nameStr);
68 }
70 int arity() {
71 switch (this) {
72 case NILARY_EXPR:
73 case NILARY_STMT: return 0;
74 case ONEARY_SHORT_EXPR:
75 case ONEARY_SHORT_STMT:
76 case ONEARY_EXPR:
77 case ONEARY_STMT: return 1;
78 case TWOARY_EXPR:
79 case TWOARY_STMT: return 2;
80 default: throw new AssertionError("Invalid lambda kind " + this);
81 }
82 }
84 boolean isShort() {
85 return this == ONEARY_SHORT_EXPR ||
86 this == ONEARY_SHORT_STMT;
87 }
88 }
90 enum LambdaParameterName {
91 IDENT("x"),
92 UNDERSCORE("_");
94 String nameStr;
96 LambdaParameterName(String nameStr) {
97 this.nameStr = nameStr;
98 }
99 }
101 enum LambdaParameterKind {
102 IMPLICIT(""),
103 EXPLIICT_SIMPLE("A"),
104 EXPLIICT_SIMPLE_ARR1("A[]"),
105 EXPLIICT_SIMPLE_ARR2("A[][]"),
106 EXPLICIT_VARARGS("A..."),
107 EXPLICIT_GENERIC1("A<X>"),
108 EXPLICIT_GENERIC2("A<? extends X, ? super Y>"),
109 EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>..."),
110 EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]"),
111 EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]");
113 String parameterType;
115 LambdaParameterKind(String parameterType) {
116 this.parameterType = parameterType;
117 }
119 boolean explicit() {
120 return this != IMPLICIT;
121 }
123 boolean isVarargs() {
124 return this == EXPLICIT_VARARGS ||
125 this == EXPLICIT_GENERIC2_VARARGS;
126 }
127 }
129 enum ModifierKind {
130 NONE(""),
131 FINAL("final"),
132 PUBLIC("public");
134 String modifier;
136 ModifierKind(String modifier) {
137 this.modifier = modifier;
138 }
140 boolean compatibleWith(LambdaParameterKind pk) {
141 switch (this) {
142 case PUBLIC: return false;
143 case FINAL: return pk != LambdaParameterKind.IMPLICIT;
144 case NONE: return true;
145 default: throw new AssertionError("Invalid modifier kind " + this);
146 }
147 }
148 }
150 enum ExprKind {
151 NONE("#L#S"),
152 SINGLE_PAREN1("(#L#S)"),
153 SINGLE_PAREN2("(#L)#S"),
154 DOUBLE_PAREN1("((#L#S))"),
155 DOUBLE_PAREN2("((#L)#S)"),
156 DOUBLE_PAREN3("((#L))#S");
158 String expressionTemplate;
160 ExprKind(String expressionTemplate) {
161 this.expressionTemplate = expressionTemplate;
162 }
164 String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
165 ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) {
166 return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn))
167 .replaceAll("#S", sk.subExpression);
168 }
169 }
171 enum SubExprKind {
172 NONE(""),
173 SELECT_FIELD(".f"),
174 SELECT_METHOD(".f()"),
175 SELECT_NEW(".new Foo()"),
176 POSTINC("++"),
177 POSTDEC("--");
179 String subExpression;
181 SubExprKind(String subExpression) {
182 this.subExpression = subExpression;
183 }
184 }
186 public static void main(String... args) throws Exception {
187 for (LambdaKind lk : LambdaKind.values()) {
188 for (LambdaParameterName pn : LambdaParameterName.values()) {
189 for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
190 if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT)
191 continue;
192 for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
193 if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT)
194 continue;
195 for (ModifierKind mk1 : ModifierKind.values()) {
196 if (mk1 != ModifierKind.NONE && lk.isShort())
197 continue;
198 if (lk.arity() < 1 && mk1 != ModifierKind.NONE)
199 continue;
200 for (ModifierKind mk2 : ModifierKind.values()) {
201 if (lk.arity() < 2 && mk2 != ModifierKind.NONE)
202 continue;
203 for (SubExprKind sk : SubExprKind.values()) {
204 for (ExprKind ek : ExprKind.values()) {
205 pool.execute(
206 new LambdaParserTest(pk1, pk2, mk1,
207 mk2, lk, sk, ek, pn));
208 }
209 }
210 }
211 }
212 }
213 }
214 }
215 }
217 checkAfterExec();
218 }
220 LambdaParameterKind pk1;
221 LambdaParameterKind pk2;
222 ModifierKind mk1;
223 ModifierKind mk2;
224 LambdaKind lk;
225 LambdaParameterName pn;
226 SubExprKind sk;
227 ExprKind ek;
228 JavaSource source;
229 DiagnosticChecker diagChecker;
231 LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2,
232 ModifierKind mk1, ModifierKind mk2, LambdaKind lk,
233 SubExprKind sk, ExprKind ek, LambdaParameterName pn) {
234 this.pk1 = pk1;
235 this.pk2 = pk2;
236 this.mk1 = mk1;
237 this.mk2 = mk2;
238 this.lk = lk;
239 this.pn = pn;
240 this.sk = sk;
241 this.ek = ek;
242 this.source = new JavaSource();
243 this.diagChecker = new DiagnosticChecker();
244 }
246 class JavaSource extends SimpleJavaFileObject {
248 String template = "class Test {\n" +
249 " SAM s = #E;\n" +
250 "}";
252 String source;
254 public JavaSource() {
255 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
256 source = template.replaceAll("#E",
257 ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk));
258 }
260 @Override
261 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
262 return source;
263 }
264 }
266 public void run() {
267 JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
268 null, null, Arrays.asList(source));
269 try {
270 ct.parse();
271 } catch (Throwable ex) {
272 processException(ex);
273 return;
274 }
275 check();
276 }
278 void check() {
279 checkCount.incrementAndGet();
281 boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
282 (lk.arity() > 1 && !mk2.compatibleWith(pk2));
284 if (lk.arity() == 2 &&
285 (pk1.explicit() != pk2.explicit() ||
286 pk1.isVarargs())) {
287 errorExpected = true;
288 }
290 errorExpected |= pn == LambdaParameterName.UNDERSCORE &&
291 lk.arity() > 0;
293 if (errorExpected != diagChecker.errorFound) {
294 throw new Error("invalid diagnostics for source:\n" +
295 source.getCharContent(true) +
296 "\nFound error: " + diagChecker.errorFound +
297 "\nExpected error: " + errorExpected);
298 }
299 }
301 static class DiagnosticChecker
302 implements javax.tools.DiagnosticListener<JavaFileObject> {
304 boolean errorFound;
306 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
307 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
308 errorFound = true;
309 }
310 }
311 }
313 }