Mercurial > hg > graal-jvmci-8
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 } |