comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java @ 16759:23415229349b

Truffle-DSL: new package structure.
author Christian Humer <christian.humer@gmail.com>
date Mon, 11 Aug 2014 15:57:14 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java@bd28da642eea
children e6d15134ca86
comparison
equal deleted inserted replaced
16758:c5f8eeb3cbc8 16759:23415229349b
1 /*
2 * Copyright (c) 2012, 2012, 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 package com.oracle.truffle.dsl.processor.parser;
24
25 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
26
27 import java.lang.annotation.*;
28 import java.util.*;
29
30 import javax.lang.model.element.*;
31 import javax.lang.model.type.*;
32 import javax.lang.model.util.*;
33
34 import com.oracle.truffle.api.dsl.*;
35 import com.oracle.truffle.dsl.processor.generator.*;
36 import com.oracle.truffle.dsl.processor.java.*;
37 import com.oracle.truffle.dsl.processor.model.*;
38
39 public class TypeSystemParser extends AbstractParser<TypeSystemData> {
40
41 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class);
42
43 @Override
44 public Class<? extends Annotation> getAnnotationType() {
45 return TypeSystem.class;
46 }
47
48 @Override
49 protected TypeSystemData parse(Element element, AnnotationMirror mirror) {
50 TypeElement templateType = (TypeElement) element;
51 AnnotationMirror templateTypeAnnotation = mirror;
52 TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation);
53
54 // annotation type on class path!?
55 TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
56 if (annotationTypeElement == null) {
57 typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName());
58 }
59 if (templateType.getModifiers().contains(Modifier.PRIVATE)) {
60 typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName());
61 }
62
63 if (templateType.getModifiers().contains(Modifier.FINAL)) {
64 typeSystem.addError("The @%s must not be final.", getAnnotationType().getName());
65 }
66 if (typeSystem.hasErrors()) {
67 return typeSystem;
68 }
69
70 typeSystem.setTypes(parseTypes(typeSystem));
71 if (typeSystem.hasErrors()) {
72 return typeSystem;
73 }
74
75 TypeMirror genericType = context.getType(Object.class);
76 TypeData voidType = new TypeData(typeSystem, typeSystem.getTypes().size(), null, context.getType(void.class), context.getType(Void.class));
77
78 typeSystem.setGenericType(genericType);
79 typeSystem.setVoidType(voidType);
80
81 verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class);
82
83 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
84 List<ImplicitCastData> implicitCasts = new ImplicitCastParser(context, typeSystem).parse(elements);
85 List<TypeCastData> casts = new TypeCastParser(context, typeSystem).parse(elements);
86 List<TypeCheckData> checks = new TypeCheckParser(context, typeSystem).parse(elements);
87
88 if (casts == null || checks == null || implicitCasts == null) {
89 return typeSystem;
90 }
91
92 typeSystem.setImplicitCasts(implicitCasts);
93 typeSystem.setCasts(casts);
94 typeSystem.setChecks(checks);
95
96 if (typeSystem.hasErrors()) {
97 return typeSystem;
98 }
99
100 for (TypeCheckData check : checks) {
101 check.getCheckedType().addTypeCheck(check);
102 }
103
104 for (TypeCastData cast : casts) {
105 cast.getTargetType().addTypeCast(cast);
106 }
107
108 verifyGenericTypeChecksAndCasts(typeSystem);
109 verifyMethodSignatures(typeSystem);
110 verifyNamesUnique(typeSystem);
111
112 return typeSystem;
113 }
114
115 private void verifyExclusiveMethodAnnotation(Template template, Class<?>... annotationTypes) {
116 List<ExecutableElement> methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements());
117 for (ExecutableElement method : methods) {
118 List<AnnotationMirror> foundAnnotations = new ArrayList<>();
119 for (int i = 0; i < annotationTypes.length; i++) {
120 Class<?> annotationType = annotationTypes[i];
121 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(context.getEnvironment(), method, annotationType);
122 if (mirror != null) {
123 foundAnnotations.add(mirror);
124 }
125 }
126 if (foundAnnotations.size() > 1) {
127 List<String> annotationNames = new ArrayList<>();
128 for (AnnotationMirror mirror : foundAnnotations) {
129 annotationNames.add("@" + ElementUtils.getSimpleName(mirror.getAnnotationType()));
130 }
131
132 template.addError("Non exclusive usage of annotations %s.", annotationNames);
133 }
134 }
135 }
136
137 private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) {
138 for (TypeData type : typeSystem.getTypes()) {
139 if (!type.getTypeChecks().isEmpty()) {
140 boolean hasGeneric = false;
141 for (TypeCheckData typeCheck : type.getTypeChecks()) {
142 if (typeCheck.isGeneric()) {
143 hasGeneric = true;
144 break;
145 }
146 }
147 if (!hasGeneric) {
148 type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
149 TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), ElementUtils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(),
150 Object.class.getSimpleName());
151 }
152 }
153 if (!type.getTypeCasts().isEmpty()) {
154 boolean hasGeneric = false;
155 for (TypeCastData typeCast : type.getTypeCasts()) {
156 if (typeCast.isGeneric()) {
157 hasGeneric = true;
158 break;
159 }
160 }
161 if (!hasGeneric) {
162 type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
163 TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), ElementUtils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(),
164 Object.class.getSimpleName());
165 }
166 }
167 }
168 }
169
170 private List<TypeData> parseTypes(TypeSystemData typeSystem) {
171 List<TypeData> types = new ArrayList<>();
172 List<TypeMirror> typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
173 if (typeMirrors.isEmpty()) {
174 typeSystem.addError("At least one type must be defined.");
175 return types;
176 }
177
178 final AnnotationValue annotationValue = ElementUtils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value");
179 final TypeMirror objectType = context.getType(Object.class);
180
181 int index = 0;
182 for (TypeMirror primitiveType : typeMirrors) {
183 TypeMirror boxedType = ElementUtils.boxType(context, primitiveType);
184 TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitiveType, boxedType);
185
186 if (isPrimitiveWrapper(primitiveType)) {
187 typeData.addError("Types must not contain primitive wrapper types.");
188 }
189
190 if (ElementUtils.typeEquals(boxedType, objectType)) {
191 typeData.addError("Types must not contain the generic type java.lang.Object.");
192 }
193
194 types.add(typeData);
195 index++;
196 }
197
198 verifyTypeOrder(types);
199
200 types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType));
201
202 return types;
203 }
204
205 private static void verifyTypeOrder(List<TypeData> types) {
206 Map<String, List<String>> invalidTypes = new HashMap<>();
207
208 for (int i = types.size() - 1; i >= 0; i--) {
209 TypeData typeData = types.get(i);
210 TypeMirror type = typeData.getBoxedType();
211 if (invalidTypes.containsKey(ElementUtils.getQualifiedName(type))) {
212 typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)), ElementUtils.getQualifiedName(type));
213 }
214 List<String> nextInvalidTypes = ElementUtils.getQualifiedSuperTypeNames(ElementUtils.fromTypeMirror(type));
215 nextInvalidTypes.add(getQualifiedName(type));
216
217 for (String qualifiedName : nextInvalidTypes) {
218 List<String> inheritedTypes = invalidTypes.get(qualifiedName);
219 if (inheritedTypes == null) {
220 inheritedTypes = new ArrayList<>();
221 invalidTypes.put(qualifiedName, inheritedTypes);
222 }
223 inheritedTypes.add(ElementUtils.getQualifiedName(typeData.getBoxedType()));
224 }
225 }
226 }
227
228 private boolean isPrimitiveWrapper(TypeMirror type) {
229 Types types = context.getEnvironment().getTypeUtils();
230 for (TypeKind kind : TypeKind.values()) {
231 if (!kind.isPrimitive()) {
232 continue;
233 }
234 if (ElementUtils.typeEquals(type, types.boxedClass(types.getPrimitiveType(kind)).asType())) {
235 return true;
236 }
237 }
238 return false;
239 }
240
241 private void verifyMethodSignatures(TypeSystemData typeSystem) {
242 Set<String> generatedIsMethodNames = new HashSet<>();
243 Set<String> generatedAsMethodNames = new HashSet<>();
244 Set<String> generatedExpectMethodNames = new HashSet<>();
245
246 for (TypeData typeData : typeSystem.getTypes()) {
247 generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData));
248 generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData));
249 generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData));
250 }
251
252 List<ExecutableElement> methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements());
253 for (ExecutableElement method : methods) {
254 if (method.getModifiers().contains(Modifier.PRIVATE)) {
255 // will not conflict overridden methods
256 continue;
257 } else if (method.getParameters().size() != 1) {
258 continue;
259 }
260 String methodName = method.getSimpleName().toString();
261 if (generatedIsMethodNames.contains(methodName)) {
262 verifyIsMethod(typeSystem, method);
263 } else if (generatedAsMethodNames.contains(methodName)) {
264 verifyAsMethod(typeSystem, method);
265 } else if (generatedExpectMethodNames.contains(methodName)) {
266 verifyExpectMethod(typeSystem);
267 }
268 }
269 }
270
271 private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) {
272 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCheck.class);
273 if (mirror == null) {
274 typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
275 return false;
276 }
277 return true;
278 }
279
280 private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) {
281 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCast.class);
282 if (mirror == null) {
283 typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
284 return false;
285 }
286 return true;
287 }
288
289 private static boolean verifyExpectMethod(TypeSystemData typeSystem) {
290 typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually.");
291 return false;
292 }
293
294 private static void verifyNamesUnique(TypeSystemData typeSystem) {
295 List<TypeData> types = typeSystem.getTypes();
296 for (int i = 0; i < types.size(); i++) {
297 for (int j = i + 1; j < types.size(); j++) {
298 String name1 = ElementUtils.getSimpleName(types.get(i).getBoxedType());
299 String name2 = ElementUtils.getSimpleName(types.get(j).getBoxedType());
300 if (name1.equalsIgnoreCase(name2)) {
301 typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2);
302 }
303 }
304 }
305 }
306 }