test/tools/javac/lambda/LambdaParserTest.java

changeset 1144
9448fe783fd2
child 1169
116f68a5e677
equal deleted inserted replaced
1143:ec59a2ce9114 1144:9448fe783fd2
1 /*
2 * Copyright (c) 2011, 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
27 * @summary Add parser support for lambda expressions
28 */
29
30 import com.sun.source.util.JavacTask;
31 import java.net.URI;
32 import java.util.Arrays;
33 import javax.tools.Diagnostic;
34 import javax.tools.JavaCompiler;
35 import javax.tools.JavaFileObject;
36 import javax.tools.SimpleJavaFileObject;
37 import javax.tools.StandardJavaFileManager;
38 import javax.tools.ToolProvider;
39
40 public class LambdaParserTest {
41
42 static int checkCount = 0;
43
44 enum LambdaKind {
45 NILARY_EXPR("()->x"),
46 NILARY_STMT("()->{ return x; }"),
47 ONEARY_SHORT_EXPR("x->x"),
48 ONEARY_SHORT_STMT("x->{ return x; }"),
49 ONEARY_EXPR("(#M1 #T1 x)->x"),
50 ONEARY_STMT("(#M1 #T1 x)->{ return x; }"),
51 TWOARY_EXPR("(#M1 #T1 x, #M2 #T2 y)->x"),
52 TWOARY_STMT("(#M1 #T1 x, #M2 #T2 y)->{ return x; }");
53
54 String lambdaTemplate;
55
56 LambdaKind(String lambdaTemplate) {
57 this.lambdaTemplate = lambdaTemplate;
58 }
59
60 String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
61 ModifierKind mk1, ModifierKind mk2) {
62 return lambdaTemplate.replaceAll("#M1", mk1.modifier)
63 .replaceAll("#M2", mk2.modifier)
64 .replaceAll("#T1", pk1.parameterType)
65 .replaceAll("#T2", pk2.parameterType);
66 }
67
68 int arity() {
69 switch (this) {
70 case NILARY_EXPR:
71 case NILARY_STMT: return 0;
72 case ONEARY_SHORT_EXPR:
73 case ONEARY_SHORT_STMT:
74 case ONEARY_EXPR:
75 case ONEARY_STMT: return 1;
76 case TWOARY_EXPR:
77 case TWOARY_STMT: return 2;
78 default: throw new AssertionError("Invalid lambda kind " + this);
79 }
80 }
81
82 boolean isShort() {
83 return this == ONEARY_SHORT_EXPR ||
84 this == ONEARY_SHORT_STMT;
85 }
86 }
87
88 enum LambdaParameterKind {
89 IMPLICIT(""),
90 EXPLIICT_SIMPLE("A"),
91 EXPLICIT_VARARGS("A..."),
92 EXPLICIT_GENERIC1("A<X>"),
93 EXPLICIT_GENERIC3("A<? extends X, ? super Y>");
94
95 String parameterType;
96
97 LambdaParameterKind(String parameterType) {
98 this.parameterType = parameterType;
99 }
100
101 boolean explicit() {
102 return this != IMPLICIT;
103 }
104 }
105
106 enum ModifierKind {
107 NONE(""),
108 FINAL("final"),
109 PUBLIC("public");
110
111 String modifier;
112
113 ModifierKind(String modifier) {
114 this.modifier = modifier;
115 }
116
117 boolean compatibleWith(LambdaParameterKind pk) {
118 switch (this) {
119 case PUBLIC: return false;
120 case FINAL: return pk != LambdaParameterKind.IMPLICIT;
121 case NONE: return true;
122 default: throw new AssertionError("Invalid modifier kind " + this);
123 }
124 }
125 }
126
127 enum ExprKind {
128 NONE("#L#S"),
129 SINGLE_PAREN1("(#L#S)"),
130 SINGLE_PAREN2("(#L)#S"),
131 DOUBLE_PAREN1("((#L#S))"),
132 DOUBLE_PAREN2("((#L)#S)"),
133 DOUBLE_PAREN3("((#L))#S");
134
135 String expressionTemplate;
136
137 ExprKind(String expressionTemplate) {
138 this.expressionTemplate = expressionTemplate;
139 }
140
141 String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
142 ModifierKind mk1, ModifierKind mk2, LambdaKind lk, SubExprKind sk) {
143 return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2))
144 .replaceAll("#S", sk.subExpression);
145 }
146 }
147
148 enum SubExprKind {
149 NONE(""),
150 SELECT_FIELD(".f"),
151 SELECT_METHOD(".f()"),
152 SELECT_NEW(".new Foo()"),
153 POSTINC("++"),
154 POSTDEC("--");
155
156 String subExpression;
157
158 SubExprKind(String subExpression) {
159 this.subExpression = subExpression;
160 }
161 }
162
163 public static void main(String... args) throws Exception {
164
165 //create default shared JavaCompiler - reused across multiple compilations
166 JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
167 StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
168
169 for (LambdaKind lk : LambdaKind.values()) {
170 for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
171 if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT) continue;
172 for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
173 if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT) continue;
174 for (ModifierKind mk1 : ModifierKind.values()) {
175 if (mk1 != ModifierKind.NONE && lk.isShort()) continue;
176 if (lk.arity() < 1 && mk1 != ModifierKind.NONE) continue;
177 for (ModifierKind mk2 : ModifierKind.values()) {
178 if (lk.arity() < 2 && mk2 != ModifierKind.NONE) continue;
179 for (SubExprKind sk : SubExprKind.values()) {
180 for (ExprKind ek : ExprKind.values()) {
181 new LambdaParserTest(pk1, pk2, mk1, mk2, lk, sk, ek)
182 .run(comp, fm);
183 }
184 }
185 }
186 }
187 }
188 }
189 }
190 System.out.println("Total check executed: " + checkCount);
191 }
192
193 LambdaParameterKind pk1;
194 LambdaParameterKind pk2;
195 ModifierKind mk1;
196 ModifierKind mk2;
197 LambdaKind lk;
198 SubExprKind sk;
199 ExprKind ek;
200 JavaSource source;
201 DiagnosticChecker diagChecker;
202
203 LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2, ModifierKind mk1,
204 ModifierKind mk2, LambdaKind lk, SubExprKind sk, ExprKind ek) {
205 this.pk1 = pk1;
206 this.pk2 = pk2;
207 this.mk1 = mk1;
208 this.mk2 = mk2;
209 this.lk = lk;
210 this.sk = sk;
211 this.ek = ek;
212 this.source = new JavaSource();
213 this.diagChecker = new DiagnosticChecker();
214 }
215
216 class JavaSource extends SimpleJavaFileObject {
217
218 String template = "class Test {\n" +
219 " SAM s = #E;\n" +
220 "}";
221
222 String source;
223
224 public JavaSource() {
225 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
226 source = template.replaceAll("#E", ek.expressionString(pk1, pk2, mk1, mk2, lk, sk));
227 }
228
229 @Override
230 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
231 return source;
232 }
233 }
234
235 void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
236 JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
237 Arrays.asList("-XDallowLambda"), null, Arrays.asList(source));
238 try {
239 ct.parse();
240 } catch (Throwable ex) {
241 throw new AssertionError("Error thron when parsing the following source:\n" + source.getCharContent(true));
242 }
243 check();
244 }
245
246 void check() {
247 checkCount++;
248
249 boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
250 (lk.arity() > 1 && !mk2.compatibleWith(pk2));
251
252 if (lk.arity() == 2 &&
253 (pk1.explicit() != pk2.explicit() ||
254 pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) {
255 errorExpected = true;
256 }
257
258 if (errorExpected != diagChecker.errorFound) {
259 throw new Error("invalid diagnostics for source:\n" +
260 source.getCharContent(true) +
261 "\nFound error: " + diagChecker.errorFound +
262 "\nExpected error: " + errorExpected);
263 }
264 }
265
266 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
267
268 boolean errorFound;
269
270 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
271 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
272 errorFound = true;
273 }
274 }
275 }
276 }

mercurial