Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java @ 18752:1acaa69ff61b
Truffle-DSL: refactor generator classes
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 29 Dec 2014 23:38:16 +0100 |
parents | |
children | f6b8787dc113 |
comparison
equal
deleted
inserted
replaced
18751:e55e18c1f40d | 18752:1acaa69ff61b |
---|---|
1 /* | |
2 * Copyright (c) 2014, 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.generator; | |
24 | |
25 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; | |
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 import javax.lang.model.util.*; | |
33 | |
34 import com.oracle.truffle.api.dsl.*; | |
35 import com.oracle.truffle.dsl.processor.java.*; | |
36 import com.oracle.truffle.dsl.processor.java.model.*; | |
37 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror; | |
38 import com.oracle.truffle.dsl.processor.model.*; | |
39 | |
40 class NodeFactoryFactory extends AbstractClassElementFactory<NodeData> { | |
41 | |
42 static final String FACTORY_METHOD_NAME = "create0"; | |
43 | |
44 private final Map<NodeData, List<TypeElement>> childTypes; | |
45 private CodeTypeElement generatedNode; | |
46 | |
47 NodeFactoryFactory(Map<NodeData, List<TypeElement>> childElements) { | |
48 this.childTypes = childElements; | |
49 } | |
50 | |
51 private static String factoryClassName(NodeData node) { | |
52 return node.getNodeId() + "Factory"; | |
53 } | |
54 | |
55 @Override | |
56 protected CodeTypeElement create(NodeData node) { | |
57 Modifier visibility = ElementUtils.getVisibility(node.getTemplateType().getModifiers()); | |
58 | |
59 CodeTypeElement clazz = createClass(node, modifiers(), factoryClassName(node), null, false); | |
60 if (visibility != null) { | |
61 clazz.getModifiers().add(visibility); | |
62 } | |
63 clazz.getModifiers().add(Modifier.FINAL); | |
64 return clazz; | |
65 } | |
66 | |
67 @Override | |
68 protected void createChildren(NodeData node) { | |
69 CodeTypeElement clazz = getElement(); | |
70 | |
71 Modifier createVisibility = ElementUtils.getVisibility(clazz.getModifiers()); | |
72 | |
73 if (node.needsFactory()) { | |
74 NodeBaseFactory factory = new NodeBaseFactory(); | |
75 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); | |
76 generatedNode = factory.getElement(); | |
77 | |
78 createFactoryMethods(node, clazz, createVisibility); | |
79 | |
80 for (SpecializationData specialization : node.getSpecializations()) { | |
81 if (!specialization.isReachable() || specialization.isGeneric()) { | |
82 continue; | |
83 } | |
84 | |
85 if (specialization.isPolymorphic() && node.isPolymorphic(context)) { | |
86 PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(generatedNode); | |
87 add(polymorphicFactory, specialization); | |
88 continue; | |
89 } | |
90 | |
91 add(new SpecializedNodeFactory(generatedNode), specialization); | |
92 } | |
93 | |
94 TypeMirror nodeFactory = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getTruffleTypes().getNodeFactoryBase()), node.getNodeType()); | |
95 clazz.setSuperClass(nodeFactory); | |
96 clazz.add(createNodeFactoryConstructor(node)); | |
97 clazz.add(createCreateNodeMethod(node)); | |
98 clazz.add(createGetInstanceMethod(node, createVisibility)); | |
99 clazz.add(createInstanceConstant(node, clazz.asType())); | |
100 } | |
101 | |
102 for (NodeData childNode : childTypes.keySet()) { | |
103 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { | |
104 continue; | |
105 } | |
106 | |
107 for (TypeElement type : childTypes.get(childNode)) { | |
108 Set<Modifier> typeModifiers = ((CodeTypeElement) type).getModifiers(); | |
109 Modifier visibility = ElementUtils.getVisibility(type.getModifiers()); | |
110 typeModifiers.clear(); | |
111 if (visibility != null) { | |
112 typeModifiers.add(visibility); | |
113 } | |
114 | |
115 typeModifiers.add(Modifier.STATIC); | |
116 typeModifiers.add(Modifier.FINAL); | |
117 clazz.add(type); | |
118 } | |
119 } | |
120 | |
121 List<NodeData> children = node.getNodeDeclaringChildren(); | |
122 if (node.getDeclaringNode() == null && children.size() > 0) { | |
123 clazz.add(createGetFactories(node)); | |
124 } | |
125 | |
126 } | |
127 | |
128 private Element createNodeFactoryConstructor(NodeData node) { | |
129 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), null, factoryClassName(node)); | |
130 CodeTreeBuilder builder = method.createBuilder(); | |
131 builder.startStatement(); | |
132 builder.startCall("super"); | |
133 | |
134 // node type | |
135 builder.typeLiteral(node.getNodeType()); | |
136 | |
137 // execution signature | |
138 builder.startGroup(); | |
139 if (node.getChildExecutions().isEmpty()) { | |
140 builder.staticReference(context.getTruffleTypes().getDslMetadata(), NodeBaseFactory.EMPTY_CLASS_ARRAY); | |
141 } else { | |
142 builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); | |
143 for (NodeExecutionData execution : node.getChildExecutions()) { | |
144 builder.typeLiteral(execution.getNodeType()); | |
145 } | |
146 builder.end(); | |
147 } | |
148 builder.end(); | |
149 | |
150 // node signatures | |
151 builder.startGroup(); | |
152 builder.startNewArray(new ArrayCodeTypeMirror(new ArrayCodeTypeMirror(context.getType(Class.class))), null); | |
153 List<ExecutableElement> constructors = NodeBaseFactory.findUserConstructors(generatedNode.asType()); | |
154 for (ExecutableElement constructor : constructors) { | |
155 builder.startGroup(); | |
156 if (constructor.getParameters().isEmpty()) { | |
157 builder.staticReference(context.getTruffleTypes().getDslMetadata(), NodeBaseFactory.EMPTY_CLASS_ARRAY); | |
158 } else { | |
159 builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); | |
160 for (VariableElement var : constructor.getParameters()) { | |
161 builder.typeLiteral(var.asType()); | |
162 } | |
163 builder.end(); | |
164 } | |
165 builder.end(); | |
166 } | |
167 builder.end(); | |
168 builder.end(); | |
169 | |
170 builder.end().end().end(); | |
171 return method; | |
172 } | |
173 | |
174 private CodeExecutableElement createCreateNodeMethod(NodeData node) { | |
175 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); | |
176 CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); | |
177 method.setVarArgs(true); | |
178 method.addParameter(arguments); | |
179 | |
180 CodeTreeBuilder builder = method.createBuilder(); | |
181 List<ExecutableElement> signatures = NodeBaseFactory.findUserConstructors(generatedNode.asType()); | |
182 boolean ifStarted = false; | |
183 | |
184 for (ExecutableElement element : signatures) { | |
185 ifStarted = builder.startIf(ifStarted); | |
186 builder.string("arguments.length == " + element.getParameters().size()); | |
187 | |
188 int index = 0; | |
189 for (VariableElement param : element.getParameters()) { | |
190 if (ElementUtils.isObject(param.asType())) { | |
191 continue; | |
192 } | |
193 builder.string(" && "); | |
194 if (!param.asType().getKind().isPrimitive()) { | |
195 builder.string("(arguments[" + index + "] == null || "); | |
196 } | |
197 builder.string("arguments[" + index + "] instanceof "); | |
198 builder.type(ElementUtils.boxType(getContext(), param.asType())); | |
199 if (!param.asType().getKind().isPrimitive()) { | |
200 builder.string(")"); | |
201 } | |
202 index++; | |
203 } | |
204 builder.end(); | |
205 builder.startBlock(); | |
206 | |
207 builder.startReturn().startCall("create"); | |
208 index = 0; | |
209 for (VariableElement param : element.getParameters()) { | |
210 builder.startGroup(); | |
211 if (!ElementUtils.isObject(param.asType())) { | |
212 builder.string("(").type(param.asType()).string(") "); | |
213 } | |
214 builder.string("arguments[").string(String.valueOf(index)).string("]"); | |
215 builder.end(); | |
216 index++; | |
217 } | |
218 builder.end().end(); | |
219 | |
220 builder.end(); // block | |
221 } | |
222 | |
223 builder.startElseBlock(); | |
224 builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); | |
225 builder.doubleQuote("Invalid create signature."); | |
226 builder.end().end(); | |
227 builder.end(); // else block | |
228 return method; | |
229 } | |
230 | |
231 private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { | |
232 TypeElement nodeFactoryType = ElementUtils.fromTypeMirror(getContext().getType(NodeFactory.class)); | |
233 TypeMirror returnType = ElementUtils.getDeclaredType(nodeFactoryType, node.getNodeType()); | |
234 | |
235 CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance"); | |
236 if (visibility != null) { | |
237 method.getModifiers().add(visibility); | |
238 } | |
239 method.getModifiers().add(Modifier.STATIC); | |
240 | |
241 String varName = instanceVarName(node); | |
242 | |
243 CodeTreeBuilder builder = method.createBuilder(); | |
244 builder.startIf(); | |
245 builder.string(varName).string(" == null"); | |
246 builder.end().startBlock(); | |
247 | |
248 builder.startStatement(); | |
249 builder.string(varName); | |
250 builder.string(" = "); | |
251 builder.startNew(factoryClassName(node)).end(); | |
252 builder.end(); | |
253 | |
254 builder.end(); | |
255 builder.startReturn().string(varName).end(); | |
256 return method; | |
257 } | |
258 | |
259 private static String instanceVarName(NodeData node) { | |
260 if (node.getDeclaringNode() != null) { | |
261 return ElementUtils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; | |
262 } else { | |
263 return "instance"; | |
264 } | |
265 } | |
266 | |
267 private static CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { | |
268 String varName = instanceVarName(node); | |
269 CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); | |
270 var.getModifiers().add(Modifier.PRIVATE); | |
271 var.getModifiers().add(Modifier.STATIC); | |
272 return var; | |
273 } | |
274 | |
275 private ExecutableElement createGetFactories(NodeData node) { | |
276 List<NodeData> children = node.getNodeDeclaringChildren(); | |
277 if (node.needsFactory()) { | |
278 children.add(node); | |
279 } | |
280 | |
281 List<TypeMirror> nodeTypesList = new ArrayList<>(); | |
282 TypeMirror prev = null; | |
283 boolean allSame = true; | |
284 for (NodeData child : children) { | |
285 nodeTypesList.add(child.getNodeType()); | |
286 if (prev != null && !ElementUtils.typeEquals(child.getNodeType(), prev)) { | |
287 allSame = false; | |
288 } | |
289 prev = child.getNodeType(); | |
290 } | |
291 TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); | |
292 | |
293 Types types = getContext().getEnvironment().getTypeUtils(); | |
294 TypeMirror factoryType = getContext().getType(NodeFactory.class); | |
295 TypeMirror baseType; | |
296 if (allSame) { | |
297 baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), commonNodeSuperType); | |
298 } else { | |
299 baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); | |
300 } | |
301 TypeMirror listType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getType(List.class)), baseType); | |
302 | |
303 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); | |
304 | |
305 CodeTreeBuilder builder = method.createBuilder(); | |
306 builder.startReturn(); | |
307 builder.startStaticCall(getContext().getType(Arrays.class), "asList"); | |
308 | |
309 for (NodeData child : children) { | |
310 builder.startGroup(); | |
311 NodeData childNode = child; | |
312 List<NodeData> factories = new ArrayList<>(); | |
313 while (childNode.getDeclaringNode() != null) { | |
314 factories.add(childNode); | |
315 childNode = childNode.getDeclaringNode(); | |
316 } | |
317 Collections.reverse(factories); | |
318 for (NodeData nodeData : factories) { | |
319 builder.string(factoryClassName(nodeData)).string("."); | |
320 } | |
321 builder.string("getInstance()"); | |
322 builder.end(); | |
323 } | |
324 builder.end(); | |
325 builder.end(); | |
326 return method; | |
327 } | |
328 | |
329 private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { | |
330 List<ExecutableElement> constructors = NodeBaseFactory.findUserConstructors(generatedNode.asType()); | |
331 for (ExecutableElement constructor : constructors) { | |
332 clazz.add(createCreateMethod(node, createVisibility, constructor)); | |
333 } | |
334 } | |
335 | |
336 private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { | |
337 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor); | |
338 method.setSimpleName(CodeNames.of("create")); | |
339 method.getModifiers().clear(); | |
340 if (visibility != null) { | |
341 method.getModifiers().add(visibility); | |
342 } | |
343 method.getModifiers().add(Modifier.STATIC); | |
344 method.setReturnType(node.getNodeType()); | |
345 | |
346 CodeTreeBuilder body = method.createBuilder(); | |
347 body.startReturn(); | |
348 if (node.getSpecializations().isEmpty()) { | |
349 body.nullLiteral(); | |
350 } else { | |
351 body.startCall(NodeBaseFactory.nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME); | |
352 for (VariableElement var : method.getParameters()) { | |
353 body.string(var.getSimpleName().toString()); | |
354 } | |
355 body.end(); | |
356 } | |
357 body.end(); | |
358 return method; | |
359 } | |
360 | |
361 } |