comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java @ 7291:a748e4d44694

Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process
author Christian Humer <christian.humer@gmail.com>
date Fri, 21 Dec 2012 10:44:31 -0800
parents
children 5e3d1a68664e
comparison
equal deleted inserted replaced
7290:a81db08fe930 7291:a748e4d44694
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.codegen.processor.typesystem;
24
25 import static com.oracle.truffle.codegen.processor.Utils.*;
26 import static javax.lang.model.element.Modifier.*;
27
28 import java.util.*;
29
30 import javax.lang.model.element.*;
31 import javax.lang.model.type.*;
32
33 import com.oracle.truffle.codegen.processor.*;
34 import com.oracle.truffle.codegen.processor.ast.*;
35 import com.oracle.truffle.codegen.processor.template.*;
36
37 public class TypeSystemCodeGenerator extends CompilationUnitFactory<TypeSystemData> {
38
39 public TypeSystemCodeGenerator(ProcessorContext context) {
40 super(context);
41 }
42
43 public static String isTypeMethodName(TypeData type) {
44 return "is" + Utils.getSimpleName(type.getBoxedType());
45 }
46
47 public static String asTypeMethodName(TypeData type) {
48 return "as" + Utils.getSimpleName(type.getBoxedType());
49 }
50
51 public static String expectTypeMethodName(TypeData type) {
52 return "expect" + Utils.getSimpleName(type.getBoxedType());
53 }
54
55 /**
56 * Finds the generated singleton field for a TypeSytemData instance. TypeSystemCodeGenerator must be applied to the
57 * TypeSystemData model before use.
58 */
59 public static VariableElement findSingleton(ProcessorContext context, TypeSystemData typeSystem) {
60 TypeMirror type = context.findGeneratedClassBySimpleName(TypeClassFactory.typeName(typeSystem), typeSystem);
61 return Utils.findDeclaredField(type, TypeClassFactory.singletonName(typeSystem.getTemplateType().asType()));
62 }
63
64 @Override
65 protected void createChildren(TypeSystemData m) {
66 add(new TypeClassFactory(context), m);
67 }
68
69 protected static class TypeClassFactory extends ClassElementFactory<TypeSystemData> {
70
71 private static final String LOCAL_VALUE = "value";
72
73 public TypeClassFactory(ProcessorContext context) {
74 super(context);
75 }
76
77 @Override
78 public CodeTypeElement create(TypeSystemData typeSystem) {
79 String name = typeName(typeSystem);
80 CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC), name, typeSystem.getTemplateType().asType(), false);
81
82 clazz.getImplements().add(getContext().getTruffleTypes().getTypeConversion());
83
84 clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz));
85 CodeVariableElement singleton = createSingleton(clazz);
86 clazz.add(singleton);
87
88 clazz.add(createGetTopType(typeSystem));
89 clazz.add(createConvertTo(typeSystem, singleton));
90
91 for (TypeData type : typeSystem.getTypes()) {
92 if (!type.isGeneric()) {
93 CodeExecutableElement isType = createIsTypeMethod(type);
94 if (isType != null) {
95 clazz.add(isType);
96 }
97 CodeExecutableElement asType = createAsTypeMethod(type);
98 if (asType != null) {
99 clazz.add(asType);
100 }
101
102 for (TypeData sourceType : collectExpectSourceTypes(type)) {
103 CodeExecutableElement expect = createExpectTypeMethod(type, sourceType);
104 if (expect != null) {
105 clazz.add(expect);
106 }
107 }
108 }
109 }
110
111 clazz.getEnclosedElements().addAll(typeSystem.getExtensionElements());
112
113 return clazz;
114 }
115
116 private static List<TypeData> collectExpectSourceTypes(TypeData type) {
117 Set<TypeData> sourceTypes = new HashSet<>();
118 sourceTypes.add(type.getTypeSystem().getGenericTypeData());
119 for (TypeCastData cast : type.getTypeCasts()) {
120 sourceTypes.add(cast.getSourceType());
121 }
122 for (TypeCheckData cast : type.getTypeChecks()) {
123 sourceTypes.add(cast.getCheckedType());
124 }
125 return new ArrayList<>(sourceTypes);
126 }
127
128
129 private CodeExecutableElement createConvertTo(TypeSystemData typeSystem, CodeVariableElement singleton) {
130 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Object.class), "convertTo");
131 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "targetType"));
132 method.addParameter(new CodeVariableElement(getContext().getType(Object.class), "value"));
133
134 CodeTreeBuilder builder = method.createBuilder();
135
136 boolean first = true;
137 for (TypeData type : typeSystem.getTypes()) {
138 if (first) {
139 builder.startIf();
140 first = false;
141 } else {
142 builder.startElseIf();
143 }
144 builder.string("targetType").string(" == ").typeLiteral(type.getBoxedType());
145 builder.end(); // if
146 builder.startBlock();
147
148 builder.startReturn();
149
150 if (typeEquals(type.getBoxedType(), getContext().getType(Object.class))) {
151 builder.string("value");
152 } else {
153 builder.string(singleton.getName()).string(".").startCall(asTypeMethodName(type)).string("value").end();
154 }
155
156 builder.end(); // return
157
158 builder.end(); // block
159 }
160
161 builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
162
163 return method;
164 }
165
166 private CodeExecutableElement createGetTopType(TypeSystemData typeSystem) {
167 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Class.class), "getTopType");
168
169 CodeTreeBuilder builder = method.createBuilder();
170 builder.startReturn();
171 if (typeSystem.getTypes().length > 0) {
172 builder.typeLiteral(typeSystem.getTypes()[0].getBoxedType());
173 } else {
174 builder.null_();
175 }
176 builder.end(); // return
177
178 return method;
179 }
180
181 private static String typeName(TypeSystemData typeSystem) {
182 String name = getSimpleName(typeSystem.getTemplateType());
183 return name + "Gen";
184 }
185
186 private static String singletonName(TypeMirror type) {
187 return createConstantName(getSimpleName(type));
188 }
189
190 private CodeVariableElement createSingleton(CodeTypeElement clazz) {
191 CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(getModel().getTemplateType().asType()));
192 field.createInitBuilder().startNew(clazz.asType()).end();
193 return field;
194 }
195
196 private CodeExecutableElement createIsTypeMethod(TypeData type) {
197 if (!type.getTypeChecks().isEmpty()) {
198 return null;
199 }
200
201 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class),
202 TypeSystemCodeGenerator.isTypeMethodName(type));
203 method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE));
204
205 CodeTreeBuilder body = method.createBuilder();
206 body.startReturn().instanceOf(LOCAL_VALUE, type.getBoxedType()).end();
207
208 return method;
209 }
210
211 private CodeExecutableElement createAsTypeMethod(TypeData type) {
212 if (!type.getTypeCasts().isEmpty()) {
213 return null;
214 }
215
216 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(),
217 TypeSystemCodeGenerator.asTypeMethodName(type));
218 method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE));
219
220 CodeTreeBuilder body = method.createBuilder();
221 body.startReturn().cast(type.getPrimitiveType(), body.create().string(LOCAL_VALUE).getTree()).end();
222
223 return method;
224 }
225
226 private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) {
227 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType));
228 method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE));
229 method.addThrownType(getContext().getTruffleTypes().getUnexpectedValueException());
230
231 CodeTreeBuilder body = method.createBuilder();
232 body.startIf().startCall(null, TypeSystemCodeGenerator.isTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end().startBlock();
233 body.startReturn().startCall(null, TypeSystemCodeGenerator.asTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end();
234 body.end(); // if-block
235 body.startThrow().startNew(getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end();
236
237 return method;
238 }
239 }
240 }