comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java @ 13528:5a0c694ef735

Truffle-DSL: Removed API classes NodeId, NodeContainer and SpecializationListener.
author Christian Humer <christian.humer@gmail.com>
date Tue, 07 Jan 2014 18:52:32 +0100
parents 25ecb47a6d0e
children e8ef44830b50
comparison
equal deleted inserted replaced
13527:25ecb47a6d0e 13528:5a0c694ef735
32 32
33 import com.oracle.truffle.api.dsl.*; 33 import com.oracle.truffle.api.dsl.*;
34 import com.oracle.truffle.api.nodes.*; 34 import com.oracle.truffle.api.nodes.*;
35 import com.oracle.truffle.dsl.processor.*; 35 import com.oracle.truffle.dsl.processor.*;
36 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; 36 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality;
37 import com.oracle.truffle.dsl.processor.node.SpecializationData.*;
37 import com.oracle.truffle.dsl.processor.template.*; 38 import com.oracle.truffle.dsl.processor.template.*;
38 import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature; 39 import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature;
39 import com.oracle.truffle.dsl.processor.typesystem.*; 40 import com.oracle.truffle.dsl.processor.typesystem.*;
40 41
41 public class NodeParser extends TemplateParser<NodeData> { 42 public class NodeParser extends AbstractParser<NodeData> {
42 43
43 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, 44 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
44 NodeContainer.class, NodeChild.class, NodeChildren.class, NodeId.class); 45 NodeChildren.class);
45 46
46 private Map<String, NodeData> parsedNodes; 47 private Map<String, NodeData> parsedNodes;
47 48
48 public NodeParser(ProcessorContext c) { 49 public NodeParser(ProcessorContext c) {
49 super(c); 50 super(c);
50 } 51 }
51 52
52 @Override 53 @Override
53 protected NodeData parse(Element element, AnnotationMirror mirror) { 54 protected NodeData parse(Element element, AnnotationMirror mirror) {
54 assert element instanceof TypeElement;
55 NodeData node = null; 55 NodeData node = null;
56 try { 56 try {
57 parsedNodes = new HashMap<>(); 57 parsedNodes = new HashMap<>();
58 node = resolveNode((TypeElement) element); 58 node = resolveNode((TypeElement) element);
59 if (Log.DEBUG) { 59 if (Log.DEBUG) {
70 return node; 70 return node;
71 } 71 }
72 72
73 @Override 73 @Override
74 protected NodeData filterErrorElements(NodeData model) { 74 protected NodeData filterErrorElements(NodeData model) {
75 for (Iterator<NodeData> iterator = model.getDeclaredNodes().iterator(); iterator.hasNext();) { 75 for (Iterator<NodeData> iterator = model.getEnclosingNodes().iterator(); iterator.hasNext();) {
76 NodeData node = filterErrorElements(iterator.next()); 76 NodeData node = filterErrorElements(iterator.next());
77 if (node == null) { 77 if (node == null) {
78 iterator.remove(); 78 iterator.remove();
79 } 79 }
80 } 80 }
103 String typeName = Utils.getQualifiedName(rootType); 103 String typeName = Utils.getQualifiedName(rootType);
104 if (parsedNodes.containsKey(typeName)) { 104 if (parsedNodes.containsKey(typeName)) {
105 return parsedNodes.get(typeName); 105 return parsedNodes.get(typeName);
106 } 106 }
107 107
108 List<? extends TypeElement> types = ElementFilter.typesIn(rootType.getEnclosedElements()); 108 List<NodeData> enclosedNodes = new ArrayList<>();
109 109 for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) {
110 List<NodeData> children = new ArrayList<>(); 110 NodeData enclosedChild = resolveNode(enclosedType);
111 for (TypeElement childElement : types) { 111 if (enclosedChild != null) {
112 NodeData childNode = resolveNode(childElement); 112 enclosedNodes.add(enclosedChild);
113 if (childNode != null) { 113 }
114 children.add(childNode); 114 }
115 } 115
116 } 116 NodeData node = parseNode(rootType);
117 117 if (node == null && !enclosedNodes.isEmpty()) {
118 NodeData rootNode = parseNode(rootType); 118 node = new NodeData(rootType);
119 if (rootNode == null && children.size() > 0) { 119 }
120 rootNode = new NodeData(rootType, rootType.getSimpleName().toString()); 120
121 } 121 if (node != null) {
122 122 for (NodeData enclosedNode : enclosedNodes) {
123 parsedNodes.put(typeName, rootNode); 123 node.addEnclosedNode(enclosedNode);
124 124 }
125 if (rootNode != null) { 125 }
126 children.addAll(rootNode.getDeclaredNodes()); 126
127 rootNode.setDeclaredNodes(children); 127 parsedNodes.put(typeName, node);
128 } 128 return node;
129
130 return rootNode;
131 } 129 }
132 130
133 private NodeData parseNode(TypeElement originalTemplateType) { 131 private NodeData parseNode(TypeElement originalTemplateType) {
134 // reloading the type elements is needed for ecj 132 // reloading the type elements is needed for ecj
135 TypeElement templateType = Utils.fromTypeMirror(context.reloadTypeElement(originalTemplateType)); 133 TypeElement templateType = Utils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
137 if (Utils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) { 135 if (Utils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
138 // generated nodes should not get called again. 136 // generated nodes should not get called again.
139 return null; 137 return null;
140 } 138 }
141 139
142 List<TypeElement> lookupTypes = findSuperClasses(new ArrayList<TypeElement>(), templateType); 140 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
143 Collections.reverse(lookupTypes); 141 if (!Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) {
144
145 AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeContainer.class);
146 TypeMirror nodeType = null;
147 if (Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) {
148 nodeType = templateType.asType();
149 }
150 if (nodeClass != null) {
151 nodeType = inheritType(nodeClass, "value", nodeType);
152 }
153
154 if (nodeType == null) {
155 return null; 142 return null;
156 } 143 }
157 144
158 Elements elementUtil = context.getEnvironment().getElementUtils(); 145 List<? extends Element> elements = context.getEnvironment().getElementUtils().getAllMembers(templateType);
159 Set<Element> elementSet = new HashSet<>(elementUtil.getAllMembers(templateType)); 146
160 if (!Utils.typeEquals(templateType.asType(), nodeType)) { 147 NodeData node = parseNodeData(templateType, elements, lookupTypes);
161 elementSet.addAll(elementUtil.getAllMembers(Utils.fromTypeMirror(nodeType)));
162
163 List<TypeElement> nodeLookupTypes = findSuperClasses(new ArrayList<TypeElement>(), Utils.fromTypeMirror(nodeType));
164 Collections.reverse(nodeLookupTypes);
165 lookupTypes.addAll(nodeLookupTypes);
166
167 Set<TypeElement> types = new HashSet<>();
168 for (ListIterator<TypeElement> iterator = lookupTypes.listIterator(); iterator.hasNext();) {
169 TypeElement typeElement = iterator.next();
170 if (types.contains(typeElement)) {
171 iterator.remove();
172 } else {
173 types.add(typeElement);
174 }
175 }
176 }
177 List<Element> elements = new ArrayList<>(elementSet);
178
179 NodeData node = parseNodeData(templateType, nodeType, elements, lookupTypes);
180
181 if (node.hasErrors()) { 148 if (node.hasErrors()) {
182 return node; // error sync point 149 return node; // error sync point
183 } 150 }
184 151
185 parseMethods(node, elements); 152 initializeChildren(node);
153
154 node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements));
155 node.getSpecializations().addAll(new GenericParser(context, node).parse(elements));
156 node.getCasts().addAll(new CreateCastParser(context, node).parse(elements));
157 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements));
186 158
187 if (node.hasErrors()) { 159 if (node.hasErrors()) {
188 return node; 160 return node; // error sync point
189 } 161 }
190 162
191 List<NodeData> nodes; 163 verifySpecializationSameLength(node);
192 164 initializeSpecializations(elements, node);
193 if (node.isNodeContainer()) { 165 initializeShortCircuits(node); // requires specializations and polymorphic specializations
194 nodes = splitNodeData(node); 166
195 } else { 167 verifyVisibilities(node);
196 nodes = new ArrayList<>(); 168 verifySpecializationOrder(node);
197 nodes.add(node); 169 verifyMissingAbstractMethods(node, elements);
198 } 170 verifyConstructors(node);
199 171 verifyNamingConvention(node.getShortCircuits(), "needs");
200 for (NodeData splittedNode : nodes) { 172 verifySpecializationThrows(node);
201 if (templateType.getModifiers().contains(Modifier.PRIVATE) && splittedNode.getSpecializations().size() > 0) {
202 splittedNode.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName());
203 }
204
205 finalizeSpecializations(elements, splittedNode);
206 verifyNode(splittedNode, elements);
207 createPolymorphicSpecializations(splittedNode);
208 assignShortCircuitsToSpecializations(splittedNode);
209 }
210
211 if (node.isNodeContainer()) {
212 node.setDeclaredNodes(nodes);
213 node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
214 node.setSpecializations(new ArrayList<SpecializationData>());
215 }
216 return node; 173 return node;
217 } 174 }
218 175
219 private void createPolymorphicSpecializations(NodeData node) { 176 private NodeData parseNodeData(TypeElement templateType, List<? extends Element> elements, List<TypeElement> typeHierarchy) {
220 if (!node.needsRewrites(context) || !node.isPolymorphic()) {
221 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList());
222 return;
223 }
224
225 SpecializationData generic = node.getGenericSpecialization();
226
227 List<TypeData> polymorphicSignature = new ArrayList<>();
228 // TODO we should support more optimized for boxing
229 // List<ActualParameter> updatePolymorphic = generic.getReturnTypeAndParameters();
230 List<ActualParameter> updatePolymorphic = Arrays.asList();
231 for (ActualParameter genericParameter : updatePolymorphic) {
232 if (!genericParameter.getSpecification().isSignature()) {
233 continue;
234 }
235
236 Set<TypeData> usedTypes = new HashSet<>();
237 for (SpecializationData specialization : node.getSpecializations()) {
238 if (!specialization.isSpecialized()) {
239 continue;
240 }
241 ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName());
242 if (parameter == null) {
243 throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
244 }
245 usedTypes.add(parameter.getTypeSystemType());
246 }
247
248 TypeData polymorphicType;
249 if (usedTypes.size() == 1) {
250 polymorphicType = usedTypes.iterator().next();
251 } else {
252 polymorphicType = node.getTypeSystem().getGenericTypeData();
253 }
254 polymorphicSignature.add(polymorphicType);
255 }
256
257 SpecializationData specialization = new SpecializationData(generic, false, false, true);
258 specialization.updateSignature(new TypeSignature(polymorphicSignature));
259 specialization.setNode(node);
260 node.setGenericPolymorphicSpecialization(specialization);
261 // TODO remove polymoprhic specializations
262 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList());
263 }
264
265 private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> typeHierarchy) {
266 NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString());
267
268 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); 177 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
269 if (typeSystemMirror == null) { 178 if (typeSystemMirror == null) {
270 nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType)); 179 NodeData nodeData = new NodeData(templateType);
180 nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(templateType));
271 return nodeData; 181 return nodeData;
272 } 182 }
273 183
274 TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); 184 TypeMirror typeSystemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
275 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); 185 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true);
276 if (typeSystem == null) { 186 if (typeSystem == null) {
277 nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSytemType)); 187 NodeData nodeData = new NodeData(templateType);
188 nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSystemType));
278 return nodeData; 189 return nodeData;
279 } 190 }
280 191
281 AnnotationMirror polymorphicMirror = findFirstAnnotation(typeHierarchy, PolymorphicLimit.class); 192 AnnotationMirror polymorphicMirror = findFirstAnnotation(typeHierarchy, PolymorphicLimit.class);
193 int polymorphicLimit = -1;
282 if (polymorphicMirror != null) { 194 if (polymorphicMirror != null) {
283 AnnotationValue limitValue = Utils.getAnnotationValue(polymorphicMirror, "value"); 195 AnnotationValue limitValue = Utils.getAnnotationValue(polymorphicMirror, "value");
284 int polymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value"); 196 int customPolymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value");
285 if (polymorphicLimit < 1) { 197 if (customPolymorphicLimit < 1) {
198 NodeData nodeData = new NodeData(templateType);
286 nodeData.addError(limitValue, "Invalid polymorphic limit %s.", polymorphicLimit); 199 nodeData.addError(limitValue, "Invalid polymorphic limit %s.", polymorphicLimit);
287 } 200 return nodeData;
288 nodeData.setPolymorphicDepth(polymorphicLimit); 201 }
202 polymorphicLimit = customPolymorphicLimit;
289 } 203 }
290 204
291 List<String> assumptionsList = new ArrayList<>(); 205 List<String> assumptionsList = new ArrayList<>();
292 for (int i = typeHierarchy.size() - 1; i >= 0; i--) { 206 for (int i = typeHierarchy.size() - 1; i >= 0; i--) {
293 TypeElement type = typeHierarchy.get(i); 207 TypeElement type = typeHierarchy.get(i);
301 assumptionsList.add(string); 215 assumptionsList.add(string);
302 } 216 }
303 } 217 }
304 } 218 }
305 AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); 219 AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
220 String shortName = null;
306 if (nodeInfoMirror != null) { 221 if (nodeInfoMirror != null) {
307 nodeData.setShortName(Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName")); 222 shortName = Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
308 } 223 }
309 224
310 nodeData.setAssumptions(new ArrayList<>(assumptionsList)); 225 List<NodeFieldData> fields = parseFields(typeHierarchy, elements);
311 nodeData.setNodeType(nodeType); 226 List<NodeChildData> children = parseChildren(elements, typeHierarchy);
312 AnnotationMirror nodeContainer = findFirstAnnotation(typeHierarchy, NodeContainer.class); 227 List<NodeExecutionData> executions = parseExecutions(children, elements);
313 nodeData.setNodeContainer(nodeContainer != null); 228
314 nodeData.setTypeSystem(typeSystem); 229 NodeData nodeData = new NodeData(templateType, shortName, typeSystem, children, executions, fields, assumptionsList, polymorphicLimit);
315 nodeData.setFields(parseFields(typeHierarchy, elements));
316 nodeData.setChildren(parseChildren(nodeData, elements, typeHierarchy));
317 nodeData.setChildExecutions(parseDefaultSignature(nodeData, elements));
318 nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); 230 nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
319 231
320 // resolveChildren invokes cyclic parsing.
321 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); 232 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
322 resolveChildren(nodeData);
323 233
324 return nodeData; 234 return nodeData;
325 }
326
327 private List<NodeExecutionData> parseDefaultSignature(NodeData node, List<? extends Element> elements) {
328 if (node.getChildren() == null) {
329 return null;
330 }
331
332 // pre-parse short circuits
333 Set<String> shortCircuits = new HashSet<>();
334 List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
335 for (ExecutableElement method : methods) {
336 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
337 if (mirror != null) {
338 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
339 }
340 }
341
342 boolean hasVarArgs = false;
343 int maxSignatureSize = 0;
344 if (!node.getChildren().isEmpty()) {
345 int lastIndex = node.getChildren().size() - 1;
346 hasVarArgs = node.getChildren().get(lastIndex).getCardinality() == Cardinality.MANY;
347 if (hasVarArgs) {
348 maxSignatureSize = lastIndex;
349 } else {
350 maxSignatureSize = node.getChildren().size();
351 }
352 }
353
354 // pre-parse specializations
355 for (ExecutableElement method : methods) {
356 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class);
357 if (mirror == null) {
358 continue;
359 }
360
361 int currentArgumentCount = 0;
362 boolean skipShortCircuit = false;
363 for (VariableElement var : method.getParameters()) {
364 TypeMirror type = var.asType();
365 if (currentArgumentCount == 0) {
366 // skip optionals
367 if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) {
368 continue;
369 }
370 // TODO skip optional fields?
371 }
372 int childIndex = currentArgumentCount < node.getChildren().size() ? currentArgumentCount : node.getChildren().size() - 1;
373 if (childIndex == -1) {
374 continue;
375 }
376 if (!skipShortCircuit) {
377 NodeChildData child = node.getChildren().get(childIndex);
378 if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) {
379 skipShortCircuit = true;
380 continue;
381 }
382 } else {
383 skipShortCircuit = false;
384 }
385
386 currentArgumentCount++;
387 }
388 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount);
389 }
390
391 List<NodeExecutionData> executions = new ArrayList<>();
392 for (int i = 0; i < maxSignatureSize; i++) {
393 int childIndex = i;
394 boolean varArg = false;
395 if (childIndex >= node.getChildren().size() - 1) {
396 if (hasVarArgs) {
397 childIndex = node.getChildren().size() - 1;
398 varArg = hasVarArgs;
399 } else if (childIndex >= node.getChildren().size()) {
400 break;
401 }
402 }
403 int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1;
404 NodeChildData child = node.getChildren().get(childIndex);
405 boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex));
406 executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit));
407 }
408 return executions;
409 } 235 }
410 236
411 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) { 237 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) {
412 Set<String> names = new HashSet<>(); 238 Set<String> names = new HashSet<>();
413 239
450 } 276 }
451 277
452 return fields; 278 return fields;
453 } 279 }
454 280
455 private void resolveChildren(NodeData node) { 281 private List<NodeChildData> parseChildren(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
456 for (NodeChildData nodeChild : node.getChildren()) {
457 NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeChild.getNodeType()));
458 nodeChild.setNode(fieldNodeData);
459 if (fieldNodeData == null) {
460 nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(nodeChild.getNodeType()));
461 } else if (!Utils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) {
462 nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
463 NodeChild.class.getSimpleName(), Utils.getSimpleName(node.getTypeSystem().getTemplateType()), Utils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
464 }
465 if (fieldNodeData != null) {
466 List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context);
467 if (types.isEmpty()) {
468 AnnotationValue executeWithValue = Utils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith");
469 nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(),
470 Utils.getSimpleName(nodeChild.getNodeType()));
471 }
472 }
473 }
474 }
475
476 private List<NodeChildData> parseChildren(NodeData parent, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
477 Set<String> shortCircuits = new HashSet<>(); 282 Set<String> shortCircuits = new HashSet<>();
478 for (ExecutableElement method : ElementFilter.methodsIn(elements)) { 283 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
479 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); 284 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
480 if (mirror != null) { 285 if (mirror != null) {
481 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); 286 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
496 301
497 List<NodeChildData> parsedChildren = new ArrayList<>(); 302 List<NodeChildData> parsedChildren = new ArrayList<>();
498 List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy); 303 List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
499 Collections.reverse(typeHierarchyReversed); 304 Collections.reverse(typeHierarchyReversed);
500 for (TypeElement type : typeHierarchyReversed) { 305 for (TypeElement type : typeHierarchyReversed) {
501 AnnotationMirror nodeClassMirror = Utils.findAnnotationMirror(processingEnv, type, NodeContainer.class);
502 AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class); 306 AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class);
503 307
504 TypeMirror nodeClassType = type.getSuperclass(); 308 TypeMirror nodeClassType = type.getSuperclass();
505 if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) { 309 if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) {
506 nodeClassType = null; 310 nodeClassType = null;
507 }
508
509 if (nodeClassMirror != null) {
510 nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType);
511 } 311 }
512 312
513 List<AnnotationMirror> children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); 313 List<AnnotationMirror> children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class);
514 int index = 0; 314 int index = 0;
515 for (AnnotationMirror childMirror : children) { 315 for (AnnotationMirror childMirror : children) {
531 childType = castNodeType; 331 childType = castNodeType;
532 } 332 }
533 333
534 Element getter = findGetter(elements, name, childType); 334 Element getter = findGetter(elements, name, childType);
535 335
536 NodeChildData nodeChild = new NodeChildData(parent, type, childMirror, name, childType, originalChildType, getter, cardinality); 336 NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality);
537 337
538 parsedChildren.add(nodeChild); 338 parsedChildren.add(nodeChild);
539 339
540 verifyNodeChild(nodeChild); 340 if (nodeChild.getNodeType() == null) {
341 nodeChild.addError("No valid node type could be resoleved.");
342 }
541 if (nodeChild.hasErrors()) { 343 if (nodeChild.hasErrors()) {
542 continue; 344 continue;
543 } 345 }
544 346
545 index++; 347 index++;
597 } 399 }
598 400
599 return filteredChildren; 401 return filteredChildren;
600 } 402 }
601 403
602 private void parseMethods(final NodeData node, List<Element> elements) { 404 private List<NodeExecutionData> parseExecutions(List<NodeChildData> children, List<? extends Element> elements) {
603 node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); 405 if (children == null) {
604 node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); 406 return null;
605 List<SpecializationData> generics = new GenericParser(context, node).parse(elements); 407 }
606 List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements); 408
607 node.setCasts(new CreateCastParser(context, node).parse(elements)); 409 // pre-parse short circuits
608 410 Set<String> shortCircuits = new HashSet<>();
609 List<SpecializationData> allSpecializations = new ArrayList<>(); 411 List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
610 allSpecializations.addAll(generics); 412 for (ExecutableElement method : methods) {
611 allSpecializations.addAll(specializations); 413 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
612 414 if (mirror != null) {
613 node.setSpecializations(allSpecializations); 415 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
614 } 416 }
615 417 }
616 private static List<NodeData> splitNodeData(NodeData node) { 418
617 SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations()); 419 boolean hasVarArgs = false;
618 SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners()); 420 int maxSignatureSize = 0;
619 SortedMap<String, List<CreateCastData>> groupedCasts = groupByNodeId(node.getCasts()); 421 if (!children.isEmpty()) {
620 422 int lastIndex = children.size() - 1;
621 Set<String> ids = new TreeSet<>(); 423 hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY;
622 ids.addAll(groupedSpecializations.keySet()); 424 if (hasVarArgs) {
623 ids.addAll(groupedListeners.keySet()); 425 maxSignatureSize = lastIndex;
624 426 } else {
625 List<NodeData> splitted = new ArrayList<>(); 427 maxSignatureSize = children.size();
626 for (String id : ids) { 428 }
627 List<SpecializationData> specializations = groupedSpecializations.get(id); 429 }
628 List<SpecializationListenerData> listeners = groupedListeners.get(id); 430
629 List<CreateCastData> casts = groupedCasts.get(id); 431 // pre-parse specializations
630 432 for (ExecutableElement method : methods) {
631 if (specializations == null) { 433 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class);
632 specializations = new ArrayList<>(); 434 if (mirror == null) {
633 } 435 continue;
634 436 }
635 if (listeners == null) { 437
636 listeners = new ArrayList<>(); 438 int currentArgumentCount = 0;
637 } 439 boolean skipShortCircuit = false;
638 440 for (VariableElement var : method.getParameters()) {
639 String nodeId = node.getNodeId(); 441 TypeMirror type = var.asType();
640 if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { 442 if (currentArgumentCount == 0) {
641 nodeId = nodeId.substring(0, nodeId.length() - 4); 443 // skip optionals
642 } 444 if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) {
643 String newNodeId = nodeId + Utils.firstLetterUpperCase(id); 445 continue;
644 NodeData copy = new NodeData(node, id, newNodeId); 446 }
645 447 // TODO skip optional fields?
646 copy.setSpecializations(specializations); 448 }
647 copy.setSpecializationListeners(listeners); 449 int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1;
648 copy.setCasts(casts); 450 if (childIndex == -1) {
649 451 continue;
650 splitted.add(copy); 452 }
651 } 453 if (!skipShortCircuit) {
652 454 NodeChildData child = children.get(childIndex);
653 node.setSpecializations(new ArrayList<SpecializationData>()); 455 if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) {
654 node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); 456 skipShortCircuit = true;
655 node.setCasts(new ArrayList<CreateCastData>()); 457 continue;
656 458 }
657 return splitted; 459 } else {
658 } 460 skipShortCircuit = false;
659 461 }
660 private void finalizeSpecializations(List<Element> elements, final NodeData node) { 462
661 List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); 463 currentArgumentCount++;
662 464 }
663 if (specializations.isEmpty()) { 465 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount);
466 }
467
468 List<NodeExecutionData> executions = new ArrayList<>();
469 for (int i = 0; i < maxSignatureSize; i++) {
470 int childIndex = i;
471 boolean varArg = false;
472 if (childIndex >= children.size() - 1) {
473 if (hasVarArgs) {
474 childIndex = children.size() - 1;
475 varArg = hasVarArgs;
476 } else if (childIndex >= children.size()) {
477 break;
478 }
479 }
480 int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1;
481 NodeChildData child = children.get(childIndex);
482 boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex));
483 executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit));
484 }
485 return executions;
486 }
487
488 private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
489 Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>();
490 for (ExecutableTypeData type : executableTypes) {
491 int evaluatedCount = type.getEvaluatedCount();
492
493 List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount);
494 if (types == null) {
495 types = new ArrayList<>();
496 groupedTypes.put(evaluatedCount, types);
497 }
498 types.add(type);
499 }
500
501 for (List<ExecutableTypeData> types : groupedTypes.values()) {
502 Collections.sort(types);
503 }
504 return groupedTypes;
505 }
506
507 private void initializeChildren(NodeData node) {
508 for (NodeChildData nodeChild : node.getChildren()) {
509 NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeChild.getNodeType()));
510 nodeChild.setNode(fieldNodeData);
511 if (fieldNodeData == null) {
512 nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(nodeChild.getNodeType()));
513 } else if (!Utils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) {
514 nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
515 NodeChild.class.getSimpleName(), Utils.getSimpleName(node.getTypeSystem().getTemplateType()), Utils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
516 }
517 if (fieldNodeData != null) {
518 List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context);
519 if (types.isEmpty()) {
520 AnnotationValue executeWithValue = Utils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith");
521 nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(),
522 Utils.getSimpleName(nodeChild.getNodeType()));
523 }
524 }
525 }
526 }
527
528 private void initializeSpecializations(List<? extends Element> elements, final NodeData node) {
529 if (node.getSpecializations().isEmpty()) {
664 return; 530 return;
665 } 531 }
666 532
667 for (SpecializationData specialization : specializations) { 533 for (SpecializationData specialization : node.getSpecializations()) {
668 matchGuards(elements, specialization); 534 if (!specialization.isSpecialized()) {
669 } 535 continue;
670 536 }
671 List<SpecializationData> generics = new ArrayList<>(); 537 initializeGuards(elements, specialization);
672 for (SpecializationData spec : specializations) { 538 }
673 if (spec.isGeneric()) { 539
674 generics.add(spec); 540 initializeGeneric(node);
675 } 541 initializeUninitialized(node);
676 } 542 initializePolymorphism(node); // requires specializations
677 543 Collections.sort(node.getSpecializations());
678 if (generics.size() == 1 && specializations.size() == 1) { 544 initializeReachability(node);
679 for (SpecializationData generic : generics) { 545
680 generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); 546 // reduce polymorphicness if generic is not reachable
681 } 547 if (node.getGenericSpecialization() != null && !node.getGenericSpecialization().isReachable()) {
682 } 548 node.setPolymorphicDepth(1);
683 549 node.getSpecializations().remove(node.getPolymorphicSpecialization());
684 SpecializationData genericSpecialization = null; 550 }
685 if (generics.size() > 1) {
686 for (SpecializationData generic : generics) {
687 generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName());
688 }
689 return;
690 } else if (generics.size() == 1) {
691 genericSpecialization = generics.get(0);
692 } else if (node.needsRewrites(context)) {
693 genericSpecialization = createGenericSpecialization(node, specializations);
694 specializations.add(genericSpecialization);
695 }
696
697 if (genericSpecialization != null) {
698 for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) {
699 if (Utils.isObject(parameter.getType())) {
700 continue;
701 }
702 Set<String> types = new HashSet<>();
703 for (SpecializationData specialization : specializations) {
704 ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
705 if (actualParameter != null) {
706 types.add(Utils.getQualifiedName(actualParameter.getType()));
707 }
708 }
709 if (types.size() > 1) {
710 genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
711 }
712 }
713 TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), null, null, genericSpecialization.getReturnType(),
714 genericSpecialization.getParameters());
715 // should not use messages from generic specialization
716 uninializedMethod.getMessages().clear();
717 specializations.add(new SpecializationData(uninializedMethod, false, true, false));
718 }
719
720 Collections.sort(specializations);
721
722 node.setSpecializations(specializations);
723 551
724 List<SpecializationData> needsId = new ArrayList<>(); 552 List<SpecializationData> needsId = new ArrayList<>();
725 for (SpecializationData specialization : specializations) { 553 for (SpecializationData specialization : node.getSpecializations()) {
726 if (specialization.isGeneric()) { 554 if (specialization.isGeneric()) {
727 specialization.setId("Generic"); 555 specialization.setId("Generic");
728 } else if (specialization.isUninitialized()) { 556 } else if (specialization.isUninitialized()) {
729 specialization.setId("Uninitialized"); 557 specialization.setId("Uninitialized");
558 } else if (specialization.isPolymorphic()) {
559 specialization.setId("Polymorphic");
560 } else if (specialization.isSpecialized()) {
561 needsId.add(specialization);
730 } else { 562 } else {
731 needsId.add(specialization); 563 throw new AssertionError();
732 } 564 }
733 } 565 }
734 566
735 // verify specialization parameter length 567 // verify specialization parameter length
736 if (verifySpecializationParameters(node)) { 568 List<String> ids = initializeSpecializationIds(needsId);
737 List<String> ids = calculateSpecializationIds(needsId); 569 for (int i = 0; i < ids.size(); i++) {
738 for (int i = 0; i < ids.size(); i++) { 570 needsId.get(i).setId(ids.get(i));
739 needsId.get(i).setId(ids.get(i)); 571 }
740 } 572
741 } 573 }
742 574
743 // calculate reachability 575 private void initializeReachability(final NodeData node) {
744 SpecializationData prev = null; 576 SpecializationData prev = null;
745 int polymorphicCombinations = 0;
746 boolean reachable = true; 577 boolean reachable = true;
747 for (SpecializationData specialization : specializations) { 578 for (SpecializationData specialization : node.getSpecializations()) {
748 if (specialization.isUninitialized()) { 579 if (specialization.isUninitialized() || specialization.isPolymorphic()) {
749 specialization.setReachable(true); 580 specialization.setReachable(true);
750 continue; 581 continue;
751 } 582 }
752 if (prev != null && prev.equalsGuards(specialization) && prev.getExceptions().isEmpty()) { 583 if (prev != null && prev.equalsGuards(specialization) && prev.getExceptions().isEmpty()) {
753 specialization.addError("%s is not reachable.", specialization.isGeneric() ? "Generic" : "Specialization"); 584 specialization.addError("%s is not reachable.", specialization.isGeneric() ? "Generic" : "Specialization");
756 } 587 }
757 specialization.setReachable(reachable); 588 specialization.setReachable(reachable);
758 if (!specialization.hasRewrite(context)) { 589 if (!specialization.hasRewrite(context)) {
759 reachable = false; 590 reachable = false;
760 } 591 }
761 if (!specialization.isGeneric()) { 592 prev = specialization;
762 int combinations = 1; 593 }
763 for (ActualParameter parameter : specialization.getParameters()) { 594 }
764 if (!parameter.getSpecification().isSignature()) { 595
765 continue; 596 private static List<String> initializeSpecializationIds(List<SpecializationData> specializations) {
597 int lastSize = -1;
598 List<List<String>> signatureChunks = new ArrayList<>();
599 for (SpecializationData other : specializations) {
600 if (!other.isSpecialized()) {
601 continue;
602 }
603 List<String> paramIds = new LinkedList<>();
604 paramIds.add(Utils.getTypeId(other.getReturnType().getType()));
605 for (ActualParameter param : other.getParameters()) {
606 if (param.getSpecification().getExecution() == null) {
607 continue;
608 }
609 paramIds.add(Utils.getTypeId(param.getType()));
610 }
611 assert lastSize == -1 || lastSize == paramIds.size();
612 if (lastSize != -1 && lastSize != paramIds.size()) {
613 throw new AssertionError();
614 }
615 signatureChunks.add(paramIds);
616 lastSize = paramIds.size();
617 }
618
619 // reduce id vertically
620 for (int i = 0; i < lastSize; i++) {
621 String prev = null;
622 boolean allSame = true;
623 for (List<String> signature : signatureChunks) {
624 String arg = signature.get(i);
625 if (prev == null) {
626 prev = arg;
627 continue;
628 } else if (!prev.equals(arg)) {
629 allSame = false;
630 break;
631 }
632 prev = arg;
633 }
634
635 if (allSame) {
636 for (List<String> signature : signatureChunks) {
637 signature.remove(i);
638 }
639 lastSize--;
640 }
641 }
642
643 // reduce id horizontally
644 for (List<String> signature : signatureChunks) {
645 if (signature.isEmpty()) {
646 continue;
647 }
648 String prev = null;
649 boolean allSame = true;
650 for (String arg : signature) {
651 if (prev == null) {
652 prev = arg;
653 continue;
654 } else if (!prev.equals(arg)) {
655 allSame = false;
656 break;
657 }
658 prev = arg;
659 }
660
661 if (allSame) {
662 signature.clear();
663 signature.add(prev);
664 }
665 }
666
667 // create signatures
668 List<String> signatures = new ArrayList<>();
669 for (List<String> signatureChunk : signatureChunks) {
670 StringBuilder b = new StringBuilder();
671 if (signatureChunk.isEmpty()) {
672 b.append("Default");
673 } else {
674 for (String s : signatureChunk) {
675 b.append(s);
676 }
677 }
678 signatures.add(b.toString());
679 }
680
681 Map<String, Integer> counts = new HashMap<>();
682 for (String s1 : signatures) {
683 Integer count = counts.get(s1);
684 if (count == null) {
685 count = 0;
686 }
687 count++;
688 counts.put(s1, count);
689 }
690
691 for (String s : counts.keySet()) {
692 int count = counts.get(s);
693 if (count > 1) {
694 int number = 0;
695 for (ListIterator<String> iterator = signatures.listIterator(); iterator.hasNext();) {
696 String s2 = iterator.next();
697 if (s.equals(s2)) {
698 iterator.set(s2 + number);
699 number++;
766 } 700 }
767 TypeData type = parameter.getTypeSystemType(); 701 }
768 combinations *= node.getTypeSystem().lookupSourceTypes(type).size(); 702 }
769 } 703 }
770 polymorphicCombinations += combinations; 704
771 } 705 return signatures;
772 706 }
773 prev = specialization; 707
774 } 708 private void initializeGuards(List<? extends Element> elements, SpecializationData specialization) {
775
776 // initialize polymorphic depth
777 if (node.getPolymorphicDepth() < 0) {
778 node.setPolymorphicDepth(polymorphicCombinations - 1);
779 }
780
781 // reduce polymorphicness if generic is not reachable
782 if (node.getGenericSpecialization() != null && !node.getGenericSpecialization().isReachable()) {
783 node.setPolymorphicDepth(1);
784 }
785 }
786
787 private SpecializationData createGenericSpecialization(final NodeData node, List<SpecializationData> specializations) {
788 SpecializationData specialization = specializations.get(0);
789 GenericParser parser = new GenericParser(context, node);
790 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
791 specification.getImplicitRequiredTypes().clear();
792
793 List<TypeMirror> parameterTypes = new ArrayList<>();
794 int signatureIndex = 1;
795 for (ParameterSpec spec : specification.getRequired()) {
796 parameterTypes.add(createGenericType(spec, specializations, signatureIndex));
797 if (spec.isSignature()) {
798 signatureIndex++;
799 }
800 }
801 TypeMirror returnType = createGenericType(specification.getReturnType(), specializations, 0);
802 return parser.create("Generic", null, null, returnType, parameterTypes);
803 }
804
805 private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) {
806 NodeExecutionData execution = spec.getExecution();
807 if (execution == null) {
808 if (spec.getAllowedTypes().size() == 1) {
809 return spec.getAllowedTypes().get(0);
810 } else {
811 return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0]));
812 }
813 } else {
814 Set<TypeData> types = new HashSet<>();
815 for (SpecializationData specialization : specializations) {
816 types.add(specialization.getTypeSignature().get(signatureIndex));
817 }
818
819 NodeChildData child = execution.getChild();
820
821 TypeData genericType = null;
822 if (types.size() == 1) {
823 ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next());
824 if (executable != null && !executable.hasUnexpectedValue(context)) {
825 genericType = types.iterator().next();
826 }
827 }
828 if (genericType == null) {
829 genericType = child.findAnyGenericExecutableType(context).getType();
830 }
831 return genericType.getPrimitiveType();
832 }
833 }
834
835 private void assignShortCircuitsToSpecializations(NodeData node) {
836 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
837
838 boolean valid = true;
839 List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>();
840 for (NodeExecutionData execution : node.getChildExecutions()) {
841 if (!execution.isShortCircuit()) {
842 continue;
843 }
844 shortCircuitExecutions.add(execution);
845 String valueName = execution.getShortCircuitId();
846 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
847
848 if (availableCircuits == null || availableCircuits.isEmpty()) {
849 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
850 valid = false;
851 continue;
852 }
853
854 boolean sameMethodName = true;
855 String methodName = availableCircuits.get(0).getMethodName();
856 for (ShortCircuitData circuit : availableCircuits) {
857 if (!circuit.getMethodName().equals(methodName)) {
858 sameMethodName = false;
859 }
860 }
861
862 if (!sameMethodName) {
863 for (ShortCircuitData circuit : availableCircuits) {
864 circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName);
865 }
866 valid = false;
867 continue;
868 }
869
870 ShortCircuitData genericCircuit = null;
871 for (ShortCircuitData circuit : availableCircuits) {
872 if (isGenericShortCutMethod(circuit)) {
873 genericCircuit = circuit;
874 break;
875 }
876 }
877
878 if (genericCircuit == null) {
879 node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
880 valid = false;
881 continue;
882 }
883
884 for (ShortCircuitData circuit : availableCircuits) {
885 if (circuit != genericCircuit) {
886 circuit.setGenericShortCircuitMethod(genericCircuit);
887 }
888 }
889 }
890
891 if (!valid) {
892 return;
893 }
894
895 List<SpecializationData> specializations = new ArrayList<>();
896 specializations.addAll(node.getSpecializations());
897 specializations.addAll(node.getPolymorphicSpecializations());
898
899 for (SpecializationData specialization : specializations) {
900 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size());
901
902 for (NodeExecutionData shortCircuit : shortCircuitExecutions) {
903 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId());
904
905 ShortCircuitData genericShortCircuit = null;
906 ShortCircuitData compatibleShortCircuit = null;
907 for (ShortCircuitData circuit : availableShortCuts) {
908 if (circuit.isGeneric()) {
909 genericShortCircuit = circuit;
910 } else if (circuit.isCompatibleTo(specialization)) {
911 compatibleShortCircuit = circuit;
912 }
913 }
914
915 if (compatibleShortCircuit == null) {
916 compatibleShortCircuit = genericShortCircuit;
917 }
918 assignedShortCuts.add(compatibleShortCircuit);
919 }
920 specialization.setShortCircuits(assignedShortCuts);
921 }
922 }
923
924 private void matchGuards(List<Element> elements, SpecializationData specialization) {
925 if (specialization.getGuardDefinitions().isEmpty()) { 709 if (specialization.getGuardDefinitions().isEmpty()) {
926 specialization.setGuards(Collections.<GuardData> emptyList()); 710 specialization.setGuards(Collections.<GuardData> emptyList());
927 return; 711 return;
928 } 712 }
929 713
944 728
945 specialization.setGuards(foundGuards); 729 specialization.setGuards(foundGuards);
946 730
947 } 731 }
948 732
949 private static List<String> calculateSpecializationIds(List<SpecializationData> specializations) { 733 private void initializeGeneric(final NodeData node) {
950 int lastSize = -1; 734 if (!node.needsRewrites(context)) {
951 List<List<String>> signatureChunks = new ArrayList<>(); 735 return;
952 for (SpecializationData other : specializations) { 736 }
953 if (other.isUninitialized() || other.isGeneric()) { 737
954 continue; 738 List<SpecializationData> generics = new ArrayList<>();
955 } 739 for (SpecializationData spec : node.getSpecializations()) {
956 List<String> paramIds = new LinkedList<>(); 740 if (spec.isGeneric()) {
957 paramIds.add(Utils.getTypeId(other.getReturnType().getType())); 741 generics.add(spec);
958 for (ActualParameter param : other.getParameters()) { 742 }
959 if (param.getSpecification().getExecution() == null) { 743 }
744
745 if (generics.size() == 1 && node.getSpecializations().size() == 1) {
746 // TODO this limitation should be lifted
747 for (SpecializationData generic : generics) {
748 generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName());
749 }
750 }
751
752 if (generics.isEmpty()) {
753 node.getSpecializations().add(createGenericSpecialization(node));
754 } else {
755 if (generics.size() > 1) {
756 for (SpecializationData generic : generics) {
757 generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName());
758 }
759 }
760 }
761 }
762
763 private SpecializationData createGenericSpecialization(final NodeData node) {
764 SpecializationData specialization = node.getSpecializations().get(0);
765 GenericParser parser = new GenericParser(context, node);
766 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
767 specification.getImplicitRequiredTypes().clear();
768
769 List<TypeMirror> parameterTypes = new ArrayList<>();
770 int signatureIndex = 1;
771 for (ParameterSpec spec : specification.getRequired()) {
772 parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex));
773 if (spec.isSignature()) {
774 signatureIndex++;
775 }
776 }
777 TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0);
778 return parser.create("Generic", null, null, returnType, parameterTypes);
779 }
780
781 private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) {
782 NodeExecutionData execution = spec.getExecution();
783 if (execution == null) {
784 if (spec.getAllowedTypes().size() == 1) {
785 return spec.getAllowedTypes().get(0);
786 } else {
787 return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0]));
788 }
789 } else {
790 Set<TypeData> types = new HashSet<>();
791 for (SpecializationData specialization : specializations) {
792 types.add(specialization.getTypeSignature().get(signatureIndex));
793 }
794
795 NodeChildData child = execution.getChild();
796
797 TypeData genericType = null;
798 if (types.size() == 1) {
799 ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next());
800 if (executable != null && !executable.hasUnexpectedValue(context)) {
801 genericType = types.iterator().next();
802 }
803 }
804 if (genericType == null) {
805 genericType = child.findAnyGenericExecutableType(context).getType();
806 }
807 return genericType.getPrimitiveType();
808 }
809 }
810
811 private static void initializeUninitialized(final NodeData node) {
812 SpecializationData generic = node.getGenericSpecialization();
813 if (generic == null) {
814 return;
815 }
816 for (ActualParameter parameter : generic.getReturnTypeAndParameters()) {
817 if (Utils.isObject(parameter.getType())) {
818 continue;
819 }
820 Set<String> types = new HashSet<>();
821 for (SpecializationData specialization : node.getSpecializations()) {
822 ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
823 if (actualParameter != null) {
824 types.add(Utils.getQualifiedName(actualParameter.getType()));
825 }
826 }
827 if (types.size() > 1) {
828 generic.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
829 }
830 }
831 TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters());
832 // should not use messages from generic specialization
833 uninializedMethod.getMessages().clear();
834 node.getSpecializations().add(new SpecializationData(node, uninializedMethod, SpecializationKind.UNINITIALIZED));
835 }
836
837 private void initializePolymorphism(NodeData node) {
838 initializePolymorphicDepth(node);
839
840 if (!node.needsRewrites(context) || !node.isPolymorphic()) {
841 return;
842 }
843
844 SpecializationData generic = node.getGenericSpecialization();
845
846 List<TypeData> polymorphicSignature = new ArrayList<>();
847 List<ActualParameter> updatePolymorphic = Arrays.asList();
848 for (ActualParameter genericParameter : updatePolymorphic) {
849 if (!genericParameter.getSpecification().isSignature()) {
850 continue;
851 }
852
853 Set<TypeData> usedTypes = new HashSet<>();
854 for (SpecializationData specialization : node.getSpecializations()) {
855 if (!specialization.isSpecialized()) {
960 continue; 856 continue;
961 } 857 }
962 paramIds.add(Utils.getTypeId(param.getType())); 858 ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName());
963 } 859 if (parameter == null) {
964 assert lastSize == -1 || lastSize == paramIds.size(); 860 throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
965 if (lastSize != -1 && lastSize != paramIds.size()) { 861 }
966 throw new AssertionError(); 862 usedTypes.add(parameter.getTypeSystemType());
967 } 863 }
968 signatureChunks.add(paramIds); 864
969 lastSize = paramIds.size(); 865 TypeData polymorphicType;
970 } 866 if (usedTypes.size() == 1) {
971 867 polymorphicType = usedTypes.iterator().next();
972 // reduce id vertically 868 } else {
973 for (int i = 0; i < lastSize; i++) { 869 polymorphicType = node.getTypeSystem().getGenericTypeData();
974 String prev = null; 870 }
975 boolean allSame = true; 871 polymorphicSignature.add(polymorphicType);
976 for (List<String> signature : signatureChunks) { 872 }
977 String arg = signature.get(i); 873
978 if (prev == null) { 874 SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC);
979 prev = arg; 875 polymorphic.updateSignature(new TypeSignature(polymorphicSignature));
980 continue; 876 node.getSpecializations().add(polymorphic);
981 } else if (!prev.equals(arg)) { 877 }
982 allSame = false; 878
879 private static void initializePolymorphicDepth(final NodeData node) {
880 int polymorphicCombinations = 0;
881 for (SpecializationData specialization : node.getSpecializations()) {
882 if (specialization.isGeneric()) {
883 continue;
884 }
885
886 int combinations = 1;
887 for (ActualParameter parameter : specialization.getSignatureParameters()) {
888 combinations *= node.getTypeSystem().lookupSourceTypes(parameter.getTypeSystemType()).size();
889 }
890 polymorphicCombinations += combinations;
891 }
892
893 // initialize polymorphic depth
894 if (node.getPolymorphicDepth() < 0) {
895 node.setPolymorphicDepth(polymorphicCombinations - 1);
896 }
897
898 }
899
900 private void initializeShortCircuits(NodeData node) {
901 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
902
903 boolean valid = true;
904 List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>();
905 for (NodeExecutionData execution : node.getChildExecutions()) {
906 if (!execution.isShortCircuit()) {
907 continue;
908 }
909 shortCircuitExecutions.add(execution);
910 String valueName = execution.getShortCircuitId();
911 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
912
913 if (availableCircuits == null || availableCircuits.isEmpty()) {
914 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
915 valid = false;
916 continue;
917 }
918
919 boolean sameMethodName = true;
920 String methodName = availableCircuits.get(0).getMethodName();
921 for (ShortCircuitData circuit : availableCircuits) {
922 if (!circuit.getMethodName().equals(methodName)) {
923 sameMethodName = false;
924 }
925 }
926
927 if (!sameMethodName) {
928 for (ShortCircuitData circuit : availableCircuits) {
929 circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName);
930 }
931 valid = false;
932 continue;
933 }
934
935 ShortCircuitData genericCircuit = null;
936 for (ShortCircuitData circuit : availableCircuits) {
937 if (isGenericShortCutMethod(circuit)) {
938 genericCircuit = circuit;
983 break; 939 break;
984 } 940 }
985 prev = arg; 941 }
986 } 942
987 943 if (genericCircuit == null) {
988 if (allSame) { 944 node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
989 for (List<String> signature : signatureChunks) { 945 valid = false;
990 signature.remove(i); 946 continue;
991 } 947 }
992 lastSize--; 948
993 } 949 for (ShortCircuitData circuit : availableCircuits) {
994 } 950 if (circuit != genericCircuit) {
995 951 circuit.setGenericShortCircuitMethod(genericCircuit);
996 // reduce id horizontally 952 }
997 for (List<String> signature : signatureChunks) { 953 }
998 if (signature.isEmpty()) { 954 }
999 continue; 955
1000 } 956 if (!valid) {
1001 String prev = null; 957 return;
1002 boolean allSame = true; 958 }
1003 for (String arg : signature) { 959
1004 if (prev == null) { 960 List<SpecializationData> specializations = new ArrayList<>();
1005 prev = arg; 961 specializations.addAll(node.getSpecializations());
1006 continue; 962 for (SpecializationData specialization : specializations) {
1007 } else if (!prev.equals(arg)) { 963 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size());
1008 allSame = false; 964
965 for (NodeExecutionData shortCircuit : shortCircuitExecutions) {
966 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId());
967
968 ShortCircuitData genericShortCircuit = null;
969 ShortCircuitData compatibleShortCircuit = null;
970 for (ShortCircuitData circuit : availableShortCuts) {
971 if (circuit.isGeneric()) {
972 genericShortCircuit = circuit;
973 } else if (circuit.isCompatibleTo(specialization)) {
974 compatibleShortCircuit = circuit;
975 }
976 }
977
978 if (compatibleShortCircuit == null) {
979 compatibleShortCircuit = genericShortCircuit;
980 }
981 assignedShortCuts.add(compatibleShortCircuit);
982 }
983 specialization.setShortCircuits(assignedShortCuts);
984 }
985 }
986
987 private boolean isGenericShortCutMethod(ShortCircuitData method) {
988 for (ActualParameter parameter : method.getParameters()) {
989 NodeExecutionData execution = parameter.getSpecification().getExecution();
990 if (execution == null) {
991 continue;
992 }
993 ExecutableTypeData found = null;
994 List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context);
995 for (ExecutableTypeData executable : executableElements) {
996 if (executable.getType().equalsType(parameter.getTypeSystemType())) {
997 found = executable;
1009 break; 998 break;
1010 } 999 }
1011 prev = arg; 1000 }
1012 } 1001 if (found == null) {
1013 1002 return false;
1014 if (allSame) { 1003 }
1015 signature.clear(); 1004 }
1016 signature.add(prev); 1005 return true;
1017 } 1006 }
1018 } 1007
1019 1008 private static Map<String, List<ShortCircuitData>> groupShortCircuits(List<ShortCircuitData> shortCircuits) {
1020 // create signatures 1009 Map<String, List<ShortCircuitData>> group = new HashMap<>();
1021 List<String> signatures = new ArrayList<>(); 1010 for (ShortCircuitData shortCircuit : shortCircuits) {
1022 for (List<String> signatureChunk : signatureChunks) { 1011 List<ShortCircuitData> circuits = group.get(shortCircuit.getValueName());
1023 StringBuilder b = new StringBuilder(); 1012 if (circuits == null) {
1024 if (signatureChunk.isEmpty()) { 1013 circuits = new ArrayList<>();
1025 b.append("Default"); 1014 group.put(shortCircuit.getValueName(), circuits);
1015 }
1016 circuits.add(shortCircuit);
1017 }
1018 return group;
1019 }
1020
1021 private static boolean verifySpecializationSameLength(NodeData nodeData) {
1022 int lastArgs = -1;
1023 for (SpecializationData specializationData : nodeData.getSpecializations()) {
1024 int signatureArgs = specializationData.getSignatureSize();
1025 if (lastArgs == signatureArgs) {
1026 continue;
1027 }
1028 if (lastArgs != -1) {
1029 for (SpecializationData specialization : nodeData.getSpecializations()) {
1030 specialization.addError("All specializations must have the same number of arguments.");
1031 }
1032 return false;
1026 } else { 1033 } else {
1027 for (String s : signatureChunk) { 1034 lastArgs = signatureArgs;
1028 b.append(s); 1035 }
1029 } 1036 }
1030 } 1037 return true;
1031 signatures.add(b.toString()); 1038 }
1032 } 1039
1033 1040 private static void verifyVisibilities(NodeData node) {
1034 Map<String, Integer> counts = new HashMap<>(); 1041 if (node.getTemplateType().getModifiers().contains(Modifier.PRIVATE) && node.getSpecializations().size() > 0) {
1035 for (String s1 : signatures) { 1042 node.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName());
1036 Integer count = counts.get(s1); 1043 }
1037 if (count == null) {
1038 count = 0;
1039 }
1040 count++;
1041 counts.put(s1, count);
1042 }
1043
1044 for (String s : counts.keySet()) {
1045 int count = counts.get(s);
1046 if (count > 1) {
1047 int number = 0;
1048 for (ListIterator<String> iterator = signatures.listIterator(); iterator.hasNext();) {
1049 String s2 = iterator.next();
1050 if (s.equals(s2)) {
1051 iterator.set(s2 + number);
1052 number++;
1053 }
1054 }
1055 }
1056 }
1057
1058 return signatures;
1059 }
1060
1061 private void verifyNode(NodeData nodeData, List<? extends Element> elements) {
1062 // verify order is not ambiguous
1063 verifySpecializationOrder(nodeData);
1064
1065 verifyMissingAbstractMethods(nodeData, elements);
1066
1067 verifyConstructors(nodeData);
1068
1069 verifyNamingConvention(nodeData.getShortCircuits(), "needs");
1070
1071 verifySpecializationThrows(nodeData);
1072 }
1073
1074 private static void verifyNodeChild(NodeChildData nodeChild) {
1075 if (nodeChild.getNodeType() == null) {
1076 nodeChild.addError("No valid node type could be resoleved.");
1077 }
1078 // FIXME verify node child
1079 // FIXME verify node type set
1080 }
1081
1082 private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) {
1083 if (!nodeData.needsFactory()) {
1084 // missing abstract methods only needs to be implemented
1085 // if we need go generate factory for it.
1086 return;
1087 }
1088
1089 List<Element> elements = new ArrayList<>(originalElements);
1090
1091 Set<Element> unusedElements = new HashSet<>(elements);
1092 for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
1093 unusedElements.remove(method.getMethod());
1094 }
1095
1096 for (NodeFieldData field : nodeData.getFields()) {
1097 if (field.getGetter() != null) {
1098 unusedElements.remove(field.getGetter());
1099 }
1100 }
1101
1102 for (NodeChildData child : nodeData.getChildren()) {
1103 if (child.getAccessElement() != null) {
1104 unusedElements.remove(child.getAccessElement());
1105 }
1106 }
1107
1108 for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
1109 if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
1110 nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
1111 }
1112 }
1113 }
1114
1115 private void verifyConstructors(NodeData nodeData) {
1116 if (!nodeData.needsRewrites(context)) {
1117 // no specialization constructor is needed if the node never rewrites.
1118 return;
1119 }
1120
1121 TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
1122 List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
1123
1124 boolean parametersFound = false;
1125 for (ExecutableElement constructor : constructors) {
1126 if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) {
1127 parametersFound = true;
1128 }
1129 }
1130 if (!parametersFound) {
1131 return;
1132 }
1133 for (ExecutableElement e : constructors) {
1134 if (e.getParameters().size() == 1) {
1135 TypeMirror firstArg = e.getParameters().get(0).asType();
1136 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) {
1137 if (e.getModifiers().contains(Modifier.PRIVATE)) {
1138 nodeData.addError("The specialization constructor must not be private.");
1139 } else if (constructors.size() <= 1) {
1140 nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
1141 }
1142 return;
1143 }
1144 }
1145 }
1146
1147 // not found
1148 nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
1149 }
1150
1151 static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) {
1152 return constructor.getParameters().size() == 1 && Utils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection());
1153 }
1154
1155 private static boolean verifySpecializationParameters(NodeData nodeData) {
1156 boolean valid = true;
1157 int args = -1;
1158 for (SpecializationData specializationData : nodeData.getSpecializations()) {
1159 int signatureArgs = 0;
1160 for (ActualParameter param : specializationData.getParameters()) {
1161 if (param.getSpecification().isSignature()) {
1162 signatureArgs++;
1163 }
1164 }
1165 if (args != -1 && args != signatureArgs) {
1166 valid = false;
1167 break;
1168 }
1169 args = signatureArgs;
1170 }
1171 if (!valid) {
1172 for (SpecializationData specialization : nodeData.getSpecializations()) {
1173 specialization.addError("All specializations must have the same number of arguments.");
1174 }
1175 }
1176 return valid;
1177 } 1044 }
1178 1045
1179 private static void verifySpecializationOrder(NodeData node) { 1046 private static void verifySpecializationOrder(NodeData node) {
1180 List<SpecializationData> specializations = node.getSpecializations(); 1047 List<SpecializationData> specializations = node.getSpecializations();
1181 for (int i = 0; i < specializations.size(); i++) { 1048 for (int i = 0; i < specializations.size(); i++) {
1202 } 1069 }
1203 } 1070 }
1204 } 1071 }
1205 } 1072 }
1206 1073
1074 private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) {
1075 if (!nodeData.needsFactory()) {
1076 // missing abstract methods only needs to be implemented
1077 // if we need go generate factory for it.
1078 return;
1079 }
1080
1081 List<Element> elements = new ArrayList<>(originalElements);
1082 Set<Element> unusedElements = new HashSet<>(elements);
1083 for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
1084 unusedElements.remove(method.getMethod());
1085 }
1086
1087 for (NodeFieldData field : nodeData.getFields()) {
1088 if (field.getGetter() != null) {
1089 unusedElements.remove(field.getGetter());
1090 }
1091 }
1092
1093 for (NodeChildData child : nodeData.getChildren()) {
1094 if (child.getAccessElement() != null) {
1095 unusedElements.remove(child.getAccessElement());
1096 }
1097 }
1098
1099 for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
1100 if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
1101 nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
1102 }
1103 }
1104 }
1105
1106 private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
1107 for (int i = 0; i < methods.size(); i++) {
1108 TemplateMethod m1 = methods.get(i);
1109 if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) {
1110 m1.addError("Naming convention: method name must start with '%s'.", prefix);
1111 }
1112 }
1113 }
1114
1207 private static void verifySpecializationThrows(NodeData node) { 1115 private static void verifySpecializationThrows(NodeData node) {
1208 Map<String, SpecializationData> specializationMap = new HashMap<>(); 1116 Map<String, SpecializationData> specializationMap = new HashMap<>();
1209 for (SpecializationData spec : node.getSpecializations()) { 1117 for (SpecializationData spec : node.getSpecializations()) {
1210 specializationMap.put(spec.getMethodName(), spec); 1118 specializationMap.put(spec.getMethodName(), spec);
1211 } 1119 }
1220 } 1128 }
1221 } 1129 }
1222 } 1130 }
1223 } 1131 }
1224 1132
1225 private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) { 1133 private void verifyConstructors(NodeData nodeData) {
1226 for (int i = 0; i < methods.size(); i++) { 1134 if (!nodeData.needsRewrites(context)) {
1227 TemplateMethod m1 = methods.get(i); 1135 // no specialization constructor is needed if the node never rewrites.
1228 if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { 1136 return;
1229 m1.addError("Naming convention: method name must start with '%s'.", prefix); 1137 }
1230 } 1138
1231 } 1139 TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
1232 } 1140 List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
1233 1141
1234 private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) { 1142 boolean parametersFound = false;
1235 Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>(); 1143 for (ExecutableElement constructor : constructors) {
1236 for (ExecutableTypeData type : executableTypes) { 1144 if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) {
1237 int evaluatedCount = type.getEvaluatedCount(); 1145 parametersFound = true;
1238 1146 }
1239 List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount); 1147 }
1240 if (types == null) { 1148 if (!parametersFound) {
1241 types = new ArrayList<>(); 1149 return;
1242 groupedTypes.put(evaluatedCount, types); 1150 }
1243 } 1151 for (ExecutableElement e : constructors) {
1244 types.add(type); 1152 if (e.getParameters().size() == 1) {
1245 } 1153 TypeMirror firstArg = e.getParameters().get(0).asType();
1246 1154 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) {
1247 for (List<ExecutableTypeData> types : groupedTypes.values()) { 1155 if (e.getModifiers().contains(Modifier.PRIVATE)) {
1248 Collections.sort(types); 1156 nodeData.addError("The specialization constructor must not be private.");
1249 } 1157 } else if (constructors.size() <= 1) {
1250 return groupedTypes; 1158 nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
1159 }
1160 return;
1161 }
1162 }
1163 }
1164
1165 // not found
1166 nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
1167 }
1168
1169 static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) {
1170 return constructor.getParameters().size() == 1 && Utils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection());
1251 } 1171 }
1252 1172
1253 private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) { 1173 private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) {
1254 for (Element element : elements) { 1174 for (Element element : elements) {
1255 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation); 1175 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation);
1287 } 1207 }
1288 } 1208 }
1289 return null; 1209 return null;
1290 } 1210 }
1291 1211
1292 private boolean isGenericShortCutMethod(ShortCircuitData method) { 1212 private static List<TypeElement> collectSuperClasses(List<TypeElement> collection, TypeElement element) {
1293 for (ActualParameter parameter : method.getParameters()) { 1213 if (element != null) {
1294 NodeExecutionData execution = parameter.getSpecification().getExecution(); 1214 collection.add(element);
1295 if (execution == null) { 1215 if (element.getSuperclass() != null) {
1296 continue; 1216 collectSuperClasses(collection, Utils.fromTypeMirror(element.getSuperclass()));
1297 } 1217 }
1298 ExecutableTypeData found = null; 1218 }
1299 List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context);
1300 for (ExecutableTypeData executable : executableElements) {
1301 if (executable.getType().equalsType(parameter.getTypeSystemType())) {
1302 found = executable;
1303 break;
1304 }
1305 }
1306 if (found == null) {
1307 return false;
1308 }
1309 }
1310 return true;
1311 }
1312
1313 private static Map<String, List<ShortCircuitData>> groupShortCircuits(List<ShortCircuitData> shortCircuits) {
1314 Map<String, List<ShortCircuitData>> group = new HashMap<>();
1315 for (ShortCircuitData shortCircuit : shortCircuits) {
1316 List<ShortCircuitData> circuits = group.get(shortCircuit.getValueName());
1317 if (circuits == null) {
1318 circuits = new ArrayList<>();
1319 group.put(shortCircuit.getValueName(), circuits);
1320 }
1321 circuits.add(shortCircuit);
1322 }
1323 return group;
1324 }
1325
1326 private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) {
1327 SortedMap<String, List<M>> grouped = new TreeMap<>();
1328 for (M m : methods) {
1329 List<M> list = grouped.get(m.getId());
1330 if (list == null) {
1331 list = new ArrayList<>();
1332 grouped.put(m.getId(), list);
1333 }
1334 list.add(m);
1335 }
1336 return grouped;
1337 }
1338
1339 private static List<TypeElement> findSuperClasses(List<TypeElement> collection, TypeElement element) {
1340 if (element.getSuperclass() != null) {
1341 TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass());
1342 if (superElement != null) {
1343 findSuperClasses(collection, superElement);
1344 }
1345 }
1346 collection.add(element);
1347 return collection; 1219 return collection;
1348 } 1220 }
1349 1221
1350 } 1222 }