Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java @ 8252:0905d796944a
Refactored codegen error model to make error redirection a lot easier.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Wed, 13 Mar 2013 19:58:28 +0100 |
parents | cb70ed101b5f |
children | 4dc7034317ec |
comparison
equal
deleted
inserted
replaced
8251:cb70ed101b5f | 8252:0905d796944a |
---|---|
26 import java.util.*; | 26 import java.util.*; |
27 | 27 |
28 import javax.lang.model.element.*; | 28 import javax.lang.model.element.*; |
29 import javax.lang.model.type.*; | 29 import javax.lang.model.type.*; |
30 import javax.lang.model.util.*; | 30 import javax.lang.model.util.*; |
31 import javax.tools.Diagnostic.*; | |
31 | 32 |
32 import com.oracle.truffle.api.codegen.*; | 33 import com.oracle.truffle.api.codegen.*; |
33 import com.oracle.truffle.api.nodes.Node.Child; | 34 import com.oracle.truffle.api.nodes.Node.Child; |
34 import com.oracle.truffle.api.nodes.Node.Children; | 35 import com.oracle.truffle.api.nodes.Node.Children; |
35 import com.oracle.truffle.codegen.processor.*; | 36 import com.oracle.truffle.codegen.processor.*; |
54 assert element instanceof TypeElement; | 55 assert element instanceof TypeElement; |
55 NodeData node = null; | 56 NodeData node = null; |
56 try { | 57 try { |
57 parsedNodes = new HashMap<>(); | 58 parsedNodes = new HashMap<>(); |
58 node = resolveNode((TypeElement) element); | 59 node = resolveNode((TypeElement) element); |
60 if (Log.DEBUG) { | |
61 NodeData parsed = parsedNodes.get(Utils.getQualifiedName((TypeElement) element)); | |
62 if (node != null) { | |
63 String dump = parsed.dump(); | |
64 log.message(Kind.ERROR, null, null, null, dump); | |
65 System.out.println(dump); | |
66 } | |
67 } | |
59 } finally { | 68 } finally { |
60 parsedNodes = null; | 69 parsedNodes = null; |
61 } | 70 } |
71 | |
62 return node; | 72 return node; |
73 } | |
74 | |
75 @Override | |
76 protected NodeData filterErrorElements(NodeData model) { | |
77 for (Iterator<NodeData> iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) { | |
78 NodeData node = filterErrorElements(iterator.next()); | |
79 if (node == null) { | |
80 iterator.remove(); | |
81 } | |
82 } | |
83 if (model.hasErrors()) { | |
84 return null; | |
85 } | |
86 return model; | |
63 } | 87 } |
64 | 88 |
65 @Override | 89 @Override |
66 public boolean isDelegateToRootDeclaredType() { | 90 public boolean isDelegateToRootDeclaredType() { |
67 return true; | 91 return true; |
80 NodeData childNode = resolveNode(childElement); | 104 NodeData childNode = resolveNode(childElement); |
81 if (childNode != null) { | 105 if (childNode != null) { |
82 children.add(childNode); | 106 children.add(childNode); |
83 } | 107 } |
84 } | 108 } |
109 | |
85 NodeData rootNode = parseNode(rootType); | 110 NodeData rootNode = parseNode(rootType); |
86 if (rootNode == null && children.size() > 0) { | 111 boolean hasErrors = rootNode != null ? rootNode.hasErrors() : false; |
87 rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString()); | 112 if ((rootNode == null || hasErrors) && children.size() > 0) { |
113 rootNode = new NodeData(rootType, rootType.getSimpleName().toString()); | |
88 } | 114 } |
89 | 115 |
90 parsedNodes.put(typeName, rootNode); | 116 parsedNodes.put(typeName, rootNode); |
91 | 117 |
92 if (rootNode != null) { | 118 if (rootNode != null) { |
93 children.addAll(rootNode.getDeclaredChildren()); | 119 children.addAll(rootNode.getDeclaredChildren()); |
94 rootNode.setDeclaredChildren(children); | 120 rootNode.setDeclaredChildren(children); |
95 } | |
96 | |
97 if (Log.DEBUG) { | |
98 NodeData parsed = parsedNodes.get(typeName); | |
99 if (parsed != null) { | |
100 String dump = parsed.dump(); | |
101 String valid = rootNode != null ? "" : " failed"; | |
102 String msg = String.format("Node parsing %s : %s", valid, dump); | |
103 log.error(msg); | |
104 System.out.println(msg); | |
105 } | |
106 } | 121 } |
107 | 122 |
108 return rootNode; | 123 return rootNode; |
109 } | 124 } |
110 | 125 |
119 if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { | 134 if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { |
120 return null; // not a node | 135 return null; // not a node |
121 } | 136 } |
122 | 137 |
123 if (type.getModifiers().contains(Modifier.PRIVATE)) { | 138 if (type.getModifiers().contains(Modifier.PRIVATE)) { |
124 return null; // not visible | 139 // TODO error message here!? |
140 return null; // not visible, not a node | |
125 } | 141 } |
126 | 142 |
127 TypeElement nodeType; | 143 TypeElement nodeType; |
128 boolean needsSplit; | 144 boolean needsSplit; |
129 if (methodNodes != null) { | 145 if (methodNodes != null) { |
133 needsSplit = false; | 149 needsSplit = false; |
134 nodeType = type; | 150 nodeType = type; |
135 } | 151 } |
136 | 152 |
137 NodeData nodeData = parseNodeData(type, nodeType); | 153 NodeData nodeData = parseNodeData(type, nodeType); |
138 if (nodeData == null) { | 154 if (nodeData.hasErrors()) { |
139 return null; | 155 return nodeData; // error sync point |
140 } | 156 } |
141 | 157 |
142 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); | 158 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); |
143 nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements)); | 159 nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements)); |
144 if (nodeData.getExtensionElements() != null) { | 160 if (nodeData.getExtensionElements() != null) { |
145 elements.addAll(nodeData.getExtensionElements()); | 161 elements.addAll(nodeData.getExtensionElements()); |
146 } | 162 } |
147 | 163 parseMethods(nodeData, elements); |
148 if (!parseMethods(nodeData, elements)) { | 164 |
149 return null; | 165 if (nodeData.hasErrors()) { |
166 return nodeData; | |
150 } | 167 } |
151 | 168 |
152 List<NodeData> nodes; | 169 List<NodeData> nodes; |
153 if (needsSplit) { | 170 if (needsSplit) { |
154 nodes = splitNodeData(nodeData); | 171 nodes = splitNodeData(nodeData); |
155 if (nodes == null) { | |
156 return null; | |
157 } | |
158 } else { | 172 } else { |
159 nodes = new ArrayList<>(); | 173 nodes = new ArrayList<>(); |
160 nodes.add(nodeData); | 174 nodes.add(nodeData); |
161 } | 175 } |
162 | 176 |
163 boolean valid = true; | |
164 for (NodeData splittedNode : nodes) { | 177 for (NodeData splittedNode : nodes) { |
165 if (!finalizeSpecializations(splittedNode)) { | 178 finalizeSpecializations(splittedNode); |
166 valid = false; | 179 verifyNode(splittedNode); |
167 } | |
168 if (!verifyNode(splittedNode)) { | |
169 valid = false; | |
170 } | |
171 } | |
172 | |
173 if (!valid) { | |
174 return null; | |
175 } | 180 } |
176 | 181 |
177 if (needsSplit) { | 182 if (needsSplit) { |
178 nodeData.setDeclaredChildren(nodes); | 183 nodeData.setDeclaredChildren(nodes); |
179 nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); | 184 nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); |
235 list.add(m); | 240 list.add(m); |
236 } | 241 } |
237 return grouped; | 242 return grouped; |
238 } | 243 } |
239 | 244 |
240 private boolean parseMethods(final NodeData node, List<Element> elements) { | 245 private void parseMethods(final NodeData node, List<Element> elements) { |
241 node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); | 246 node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); |
242 node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); | 247 node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); |
243 node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); | 248 node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); |
244 List<SpecializationData> generics = new GenericParser(context, node).parse(elements); | 249 List<SpecializationData> generics = new GenericParser(context, node).parse(elements); |
245 List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements); | 250 List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements); |
246 | 251 |
247 if (generics == null || specializations == null || node.getGuards() == null || node.getShortCircuits() == null || node.getSpecializationListeners() == null) { | |
248 return false; | |
249 } | |
250 | |
251 List<SpecializationData> allSpecializations = new ArrayList<>(); | 252 List<SpecializationData> allSpecializations = new ArrayList<>(); |
252 allSpecializations.addAll(generics); | 253 allSpecializations.addAll(generics); |
253 allSpecializations.addAll(specializations); | 254 allSpecializations.addAll(specializations); |
254 | 255 |
255 node.setSpecializations(allSpecializations); | 256 node.setSpecializations(allSpecializations); |
256 | 257 } |
257 return true; | 258 |
258 } | 259 private void finalizeSpecializations(final NodeData node) { |
259 | |
260 private boolean finalizeSpecializations(final NodeData node) { | |
261 List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); | 260 List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); |
262 | 261 |
263 if (specializations.isEmpty()) { | 262 if (specializations.isEmpty()) { |
264 return true; | 263 return; |
265 } | 264 } |
266 | 265 |
267 List<SpecializationData> generics = new ArrayList<>(); | 266 List<SpecializationData> generics = new ArrayList<>(); |
268 for (SpecializationData spec : specializations) { | 267 for (SpecializationData spec : specializations) { |
269 if (spec.isGeneric()) { | 268 if (spec.isGeneric()) { |
271 } | 270 } |
272 } | 271 } |
273 | 272 |
274 if (generics.size() == 1 && specializations.size() == 1) { | 273 if (generics.size() == 1 && specializations.size() == 1) { |
275 for (SpecializationData generic : generics) { | 274 for (SpecializationData generic : generics) { |
276 log.error(generic.getMethod(), "@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); | 275 generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); |
277 } | 276 } |
278 } | 277 } |
279 | 278 |
280 SpecializationData genericSpecialization = null; | 279 SpecializationData genericSpecialization = null; |
281 if (generics.size() > 1) { | 280 if (generics.size() > 1) { |
282 for (SpecializationData generic : generics) { | 281 for (SpecializationData generic : generics) { |
283 log.error(generic.getMethod(), "Only @%s is allowed per operation.", Generic.class.getSimpleName()); | 282 generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); |
284 } | 283 } |
285 return false; | 284 return; |
286 } else if (generics.size() == 1) { | 285 } else if (generics.size() == 1) { |
287 genericSpecialization = generics.get(0); | 286 genericSpecialization = generics.get(0); |
288 if (!node.needsRewrites(context)) { | |
289 log.error(genericSpecialization.getMethod(), "Generic specialization is not reachable.", Generic.class.getSimpleName()); | |
290 return false; | |
291 } | |
292 } else if (node.needsRewrites(context)) { | 287 } else if (node.needsRewrites(context)) { |
293 SpecializationData specialization = specializations.get(0); | 288 SpecializationData specialization = specializations.get(0); |
294 GenericParser parser = new GenericParser(context, node); | 289 GenericParser parser = new GenericParser(context, node); |
295 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null); | 290 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null); |
296 | 291 |
341 node.setSpecializations(specializations); | 336 node.setSpecializations(specializations); |
342 | 337 |
343 for (SpecializationData specialization : specializations) { | 338 for (SpecializationData specialization : specializations) { |
344 specialization.setId(findUniqueSpecializationId(specialization)); | 339 specialization.setId(findUniqueSpecializationId(specialization)); |
345 } | 340 } |
346 | |
347 return true; | |
348 } | 341 } |
349 | 342 |
350 private static String findUniqueSpecializationId(SpecializationData specialization) { | 343 private static String findUniqueSpecializationId(SpecializationData specialization) { |
351 | 344 |
352 String name; | 345 String name; |
433 } | 426 } |
434 return nameBuilder.toString(); | 427 return nameBuilder.toString(); |
435 } | 428 } |
436 } | 429 } |
437 | 430 |
438 private boolean verifyNode(NodeData nodeData) { | 431 private void verifyNode(NodeData nodeData) { |
439 // verify specialization parameter length | 432 // verify specialization parameter length |
440 if (!verifySpecializationParameters(nodeData)) { | 433 verifySpecializationParameters(nodeData); |
441 return false; | |
442 } | |
443 | 434 |
444 // verify order is not ambiguous | 435 // verify order is not ambiguous |
445 if (!verifySpecializationOrder(nodeData)) { | 436 verifySpecializationOrder(nodeData); |
446 return false; | 437 |
447 } | 438 verifyMissingAbstractMethods(nodeData); |
448 | 439 |
449 if (!verifyMissingAbstractMethods(nodeData)) { | 440 assignShortCircuitsToSpecializations(nodeData); |
450 return false; | 441 |
451 } | 442 verifyConstructors(nodeData); |
452 | |
453 if (!assignShortCircuitsToSpecializations(nodeData)) { | |
454 return false; | |
455 } | |
456 | |
457 if (!verifyConstructors(nodeData)) { | |
458 return false; | |
459 } | |
460 | 443 |
461 // if (!verifyNamingConvention(specializations, "do")) { | 444 // if (!verifyNamingConvention(specializations, "do")) { |
462 // return null; | 445 // return null; |
463 // } | 446 // } |
464 // | 447 // |
465 // if (!verifyNamesUnique(specializations)) { | 448 // if (!verifyNamesUnique(specializations)) { |
466 // return null; | 449 // return null; |
467 // } | 450 // } |
468 | 451 |
469 if (!verifyNamingConvention(nodeData.getShortCircuits(), "needs")) { | 452 verifyNamingConvention(nodeData.getShortCircuits(), "needs"); |
470 return false; | 453 |
471 } | 454 verifySpecializationThrows(nodeData); |
472 | |
473 if (!verifySpecializationThrows(nodeData)) { | |
474 return false; | |
475 } | |
476 | |
477 return true; | |
478 } | 455 } |
479 | 456 |
480 private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) { | 457 private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) { |
481 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType)); | 458 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType)); |
482 List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType); | 459 List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType); |
483 Collections.reverse(typeHierarchy); | 460 Collections.reverse(typeHierarchy); |
461 NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); | |
484 | 462 |
485 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); | 463 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); |
486 if (typeSystemMirror == null) { | 464 if (typeSystemMirror == null) { |
487 log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString()); | 465 nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString()); |
488 return null; | 466 return nodeData; |
489 } | 467 } |
490 | 468 |
491 TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); | 469 TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); |
492 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); | 470 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); |
493 if (typeSystem == null) { | 471 if (typeSystem == null) { |
494 log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); | 472 nodeData.addError("The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); |
495 return null; | 473 return nodeData; |
496 } | 474 } |
497 | 475 |
498 NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString()); | |
499 nodeData.setNodeType(nodeType.asType()); | 476 nodeData.setNodeType(nodeType.asType()); |
477 nodeData.setTypeSystem(typeSystem); | |
500 | 478 |
501 List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); | 479 List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); |
502 | |
503 nodeData.setExecutableTypes(executableTypes); | 480 nodeData.setExecutableTypes(executableTypes); |
504 | |
505 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); | 481 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); |
506 | 482 nodeData.setFields(parseFields(nodeData, elements, typeHierarchy)); |
507 List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy); | |
508 if (fields == null) { | |
509 return null; | |
510 } | |
511 nodeData.setFields(fields); | |
512 | 483 |
513 return nodeData; | 484 return nodeData; |
514 } | 485 } |
515 | 486 |
516 private boolean verifySpecializationParameters(NodeData nodeData) { | 487 private static void verifySpecializationParameters(NodeData nodeData) { |
517 boolean valid = true; | 488 boolean valid = true; |
518 int args = -1; | 489 int args = -1; |
519 for (SpecializationData specializationData : nodeData.getSpecializations()) { | 490 for (SpecializationData specializationData : nodeData.getSpecializations()) { |
520 int specializationArgs = 0; | 491 int specializationArgs = 0; |
521 for (ActualParameter param : specializationData.getParameters()) { | 492 for (ActualParameter param : specializationData.getParameters()) { |
529 } | 500 } |
530 args = specializationArgs; | 501 args = specializationArgs; |
531 } | 502 } |
532 if (!valid) { | 503 if (!valid) { |
533 for (SpecializationData specialization : nodeData.getSpecializations()) { | 504 for (SpecializationData specialization : nodeData.getSpecializations()) { |
534 context.getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), "All specializations must have the same number of arguments."); | 505 specialization.addError("All specializations must have the same number of arguments."); |
535 } | 506 } |
536 } | 507 } |
537 return valid; | 508 } |
538 } | 509 |
539 | 510 private void verifyMissingAbstractMethods(NodeData nodeData) { |
540 private boolean verifyMissingAbstractMethods(NodeData nodeData) { | 511 if (!nodeData.needsFactory()) { |
541 if (nodeData.needsFactory()) { | |
542 // missing abstract methods only needs to be implemented | 512 // missing abstract methods only needs to be implemented |
543 // if we need go generate factory for it. | 513 // if we need go generate factory for it. |
544 return true; | 514 return; |
545 } | 515 } |
546 | 516 |
547 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType())); | 517 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType())); |
548 | 518 |
549 Set<Element> unusedElements = new HashSet<>(elements); | 519 Set<Element> unusedElements = new HashSet<>(elements); |
552 } | 522 } |
553 if (nodeData.getExtensionElements() != null) { | 523 if (nodeData.getExtensionElements() != null) { |
554 unusedElements.removeAll(nodeData.getExtensionElements()); | 524 unusedElements.removeAll(nodeData.getExtensionElements()); |
555 } | 525 } |
556 | 526 |
557 boolean valid = true; | |
558 for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { | 527 for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { |
559 if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { | 528 if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { |
560 context.getLog().error(nodeData.getTemplateType(), "The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), | 529 nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod)); |
561 Utils.getReadableSignature(unusedMethod)); | 530 } |
562 valid = false; | 531 } |
563 } | 532 } |
564 } | 533 |
565 | 534 private void verifyConstructors(NodeData nodeData) { |
566 return valid; | |
567 } | |
568 | |
569 private boolean verifyConstructors(NodeData nodeData) { | |
570 TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType()); | |
571 if (!nodeData.needsRewrites(context)) { | 535 if (!nodeData.needsRewrites(context)) { |
572 // no specialization constructor is needed if the node never rewrites. | 536 // no specialization constructor is needed if the node never rewrites. |
573 return true; | 537 return; |
574 } | 538 } |
539 | |
540 TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType()); | |
575 | 541 |
576 List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); | 542 List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); |
577 for (ExecutableElement e : constructors) { | 543 for (ExecutableElement e : constructors) { |
578 if (e.getParameters().size() == 1) { | 544 if (e.getParameters().size() == 1) { |
579 TypeMirror firstArg = e.getParameters().get(0).asType(); | 545 TypeMirror firstArg = e.getParameters().get(0).asType(); |
580 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) { | 546 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) { |
581 if (e.getModifiers().contains(Modifier.PRIVATE)) { | 547 if (e.getModifiers().contains(Modifier.PRIVATE)) { |
582 context.getLog().error(e, "The specialization constructor must not be private."); | 548 nodeData.addError("The specialization constructor must not be private."); |
583 return false; | |
584 } else if (constructors.size() <= 1) { | 549 } else if (constructors.size() <= 1) { |
585 context.getLog().error(e, "The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); | 550 nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); |
586 return false; | |
587 } | 551 } |
588 return true; | 552 return; |
589 } | 553 } |
590 } | 554 } |
591 } | 555 } |
592 | 556 |
593 // not found | 557 // not found |
594 context.getLog().error(type, "Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); | 558 nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); |
595 return false; | |
596 } | 559 } |
597 | 560 |
598 private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) { | 561 private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) { |
599 List<ExecutableTypeData> filteredExecutableTypes = new ArrayList<>(); | 562 List<ExecutableTypeData> filteredExecutableTypes = new ArrayList<>(); |
600 for (ExecutableTypeData t1 : executableTypes) { | 563 for (ExecutableTypeData t1 : executableTypes) { |
655 if (mirror != null) { | 618 if (mirror != null) { |
656 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); | 619 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); |
657 } | 620 } |
658 } | 621 } |
659 | 622 |
660 boolean valid = true; | |
661 | |
662 List<NodeFieldData> fields = new ArrayList<>(); | 623 List<NodeFieldData> fields = new ArrayList<>(); |
663 for (VariableElement var : ElementFilter.fieldsIn(elements)) { | 624 for (VariableElement var : ElementFilter.fieldsIn(elements)) { |
664 if (var.getModifiers().contains(Modifier.STATIC)) { | 625 if (var.getModifiers().contains(Modifier.STATIC)) { |
665 continue; | 626 continue; |
666 } | 627 } |
670 continue; | 631 continue; |
671 } | 632 } |
672 } | 633 } |
673 | 634 |
674 NodeFieldData field = parseField(nodeData, var, shortCircuits); | 635 NodeFieldData field = parseField(nodeData, var, shortCircuits); |
675 if (field != null) { | 636 if (field.getExecutionKind() != ExecutionKind.IGNORE) { |
676 if (field.getExecutionKind() != ExecutionKind.IGNORE) { | 637 fields.add(field); |
677 fields.add(field); | 638 } |
678 } | 639 } |
679 } else { | |
680 valid = false; | |
681 } | |
682 } | |
683 | |
684 // TODO parse getters | |
685 if (!valid) { | |
686 return null; | |
687 } | |
688 | |
689 sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy); | 640 sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy); |
690 return fields; | 641 return fields; |
691 } | 642 } |
692 | 643 |
693 private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set<String> foundShortCircuits) { | 644 private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set<String> foundShortCircuits) { |
719 nodeType = null; | 670 nodeType = null; |
720 mirror = null; | 671 mirror = null; |
721 kind = null; | 672 kind = null; |
722 } | 673 } |
723 | 674 |
724 NodeData fieldNodeData = null; | 675 NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution); |
725 if (nodeType != null) { | 676 if (nodeType != null) { |
726 fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType)); | 677 NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType)); |
727 Element errorElement = Utils.typeEquals(parentNodeData.getTemplateType().asType(), var.getEnclosingElement().asType()) ? var : parentNodeData.getTemplateType(); | 678 fieldData.setNode(fieldNodeData); |
728 | 679 |
729 if (fieldNodeData == null) { | 680 if (fieldNodeData == null) { |
730 // TODO redirect errors from resolve. | 681 fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(nodeType)); |
731 context.getLog().error(errorElement, "Node type '%s' is invalid.", Utils.getQualifiedName(nodeType)); | |
732 return null; | |
733 } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) { | 682 } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) { |
734 // TODO better error handling for (no or multiple?) | 683 fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType)); |
735 context.getLog().error(errorElement, "No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType)); | |
736 return null; | |
737 } | 684 } |
738 | 685 |
739 // TODO correct handling of access elements | 686 // TODO correct handling of access elements |
740 if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) { | 687 if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) { |
741 execution = ExecutionKind.IGNORE; | 688 execution = ExecutionKind.IGNORE; |
742 } | 689 } |
743 } | 690 } |
744 return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution); | 691 return fieldData; |
745 } | 692 } |
746 | 693 |
747 private Element findAccessElement(VariableElement variableElement) { | 694 private Element findAccessElement(VariableElement variableElement) { |
748 Element enclosed = variableElement.getEnclosingElement(); | 695 Element enclosed = variableElement.getEnclosingElement(); |
749 if (!enclosed.getKind().isClass()) { | 696 if (!enclosed.getKind().isClass()) { |
793 return index1 - index2; | 740 return index1 - index2; |
794 } | 741 } |
795 }); | 742 }); |
796 } | 743 } |
797 | 744 |
798 private boolean assignShortCircuitsToSpecializations(NodeData node) { | 745 private void assignShortCircuitsToSpecializations(NodeData node) { |
799 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); | 746 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); |
800 | 747 |
801 boolean valid = true; | 748 boolean valid = true; |
802 | |
803 for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { | 749 for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { |
804 String valueName = field.getName(); | 750 String valueName = field.getName(); |
805 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); | 751 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); |
806 | 752 |
807 if (availableCircuits == null || availableCircuits.isEmpty()) { | 753 if (availableCircuits == null || availableCircuits.isEmpty()) { |
808 log.error(node.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); | 754 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); |
809 valid = false; | 755 valid = false; |
810 continue; | 756 continue; |
811 } | 757 } |
812 | 758 |
813 boolean sameMethodName = true; | 759 boolean sameMethodName = true; |
818 } | 764 } |
819 } | 765 } |
820 | 766 |
821 if (!sameMethodName) { | 767 if (!sameMethodName) { |
822 for (ShortCircuitData circuit : availableCircuits) { | 768 for (ShortCircuitData circuit : availableCircuits) { |
823 log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName); | 769 circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName); |
824 } | 770 } |
825 valid = false; | 771 valid = false; |
826 continue; | 772 continue; |
827 } | 773 } |
828 | 774 |
833 break; | 779 break; |
834 } | 780 } |
835 } | 781 } |
836 | 782 |
837 if (genericCircuit == null) { | 783 if (genericCircuit == null) { |
838 log.error(node.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); | 784 node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); |
839 valid = false; | 785 valid = false; |
840 continue; | 786 continue; |
841 } | 787 } |
842 | 788 |
843 for (ShortCircuitData circuit : availableCircuits) { | 789 for (ShortCircuitData circuit : availableCircuits) { |
846 } | 792 } |
847 } | 793 } |
848 } | 794 } |
849 | 795 |
850 if (!valid) { | 796 if (!valid) { |
851 return valid; | 797 return; |
852 } | 798 } |
853 | 799 |
854 NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT); | 800 NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT); |
855 for (SpecializationData specialization : node.getSpecializations()) { | 801 for (SpecializationData specialization : node.getSpecializations()) { |
856 ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length]; | 802 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length); |
857 | 803 |
858 for (int i = 0; i < fields.length; i++) { | 804 for (int i = 0; i < fields.length; i++) { |
859 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(fields[i].getName()); | 805 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(fields[i].getName()); |
860 | 806 |
861 ShortCircuitData genericShortCircuit = null; | 807 ShortCircuitData genericShortCircuit = null; |
808 ShortCircuitData compatibleShortCircuit = null; | |
862 for (ShortCircuitData circuit : availableShortCuts) { | 809 for (ShortCircuitData circuit : availableShortCuts) { |
863 if (circuit.isGeneric()) { | 810 if (circuit.isGeneric()) { |
864 genericShortCircuit = circuit; | 811 genericShortCircuit = circuit; |
865 } else if (circuit.isCompatibleTo(specialization)) { | 812 } else if (circuit.isCompatibleTo(specialization)) { |
866 assignedShortCuts[i] = circuit; | 813 compatibleShortCircuit = circuit; |
867 } | 814 } |
868 } | 815 } |
869 | 816 |
870 if (assignedShortCuts[i] == null) { | 817 if (compatibleShortCircuit == null) { |
871 assignedShortCuts[i] = genericShortCircuit; | 818 compatibleShortCircuit = genericShortCircuit; |
872 } | 819 } |
820 assignedShortCuts.add(compatibleShortCircuit); | |
873 } | 821 } |
874 specialization.setShortCircuits(assignedShortCuts); | 822 specialization.setShortCircuits(assignedShortCuts); |
875 } | 823 } |
876 return true; | 824 } |
877 } | 825 |
878 | 826 private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) { |
879 private boolean verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) { | |
880 boolean valid = true; | |
881 for (int i = 0; i < methods.size(); i++) { | 827 for (int i = 0; i < methods.size(); i++) { |
882 TemplateMethod m1 = methods.get(i); | 828 TemplateMethod m1 = methods.get(i); |
883 if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { | 829 if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { |
884 log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix); | 830 m1.addError("Naming convention: method name must start with '%s'.", prefix); |
885 valid = false; | 831 } |
886 } | 832 } |
887 } | |
888 return valid; | |
889 } | |
890 | |
891 @SuppressWarnings("unused") | |
892 private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) { | |
893 boolean valid = true; | |
894 for (int i = 0; i < methods.size(); i++) { | |
895 TemplateMethod m1 = methods.get(i); | |
896 for (int j = i + 1; j < methods.size(); j++) { | |
897 TemplateMethod m2 = methods.get(j); | |
898 | |
899 if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) { | |
900 log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); | |
901 log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); | |
902 return false; | |
903 } | |
904 } | |
905 } | |
906 return valid; | |
907 } | 833 } |
908 | 834 |
909 private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { | 835 private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { |
910 for (ActualParameter parameter : method.getParameters()) { | 836 for (ActualParameter parameter : method.getParameters()) { |
911 NodeFieldData field = node.findField(parameter.getSpecification().getName()); | 837 NodeFieldData field = node.findField(parameter.getSpecification().getName()); |
956 } | 882 } |
957 collection.add(element); | 883 collection.add(element); |
958 return collection; | 884 return collection; |
959 } | 885 } |
960 | 886 |
961 private boolean verifySpecializationOrder(NodeData node) { | 887 private static void verifySpecializationOrder(NodeData node) { |
962 TypeSystemData typeSystem = node.getTypeSystem(); | 888 TypeSystemData typeSystem = node.getTypeSystem(); |
963 List<SpecializationData> specializations = node.getSpecializations(); | 889 List<SpecializationData> specializations = node.getSpecializations(); |
964 | 890 |
965 for (int i = 0; i < specializations.size(); i++) { | 891 for (int i = 0; i < specializations.size(); i++) { |
966 SpecializationData m1 = specializations.get(i); | 892 SpecializationData m1 = specializations.get(i); |
969 int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); | 895 int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); |
970 | 896 |
971 if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { | 897 if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { |
972 int specOrder = m1.getOrder() - m2.getOrder(); | 898 int specOrder = m1.getOrder() - m2.getOrder(); |
973 if (specOrder == 0) { | 899 if (specOrder == 0) { |
974 log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); | 900 m1.addError("Order value %d used multiple times", m1.getOrder()); |
975 log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); | 901 m2.addError("Order value %d used multiple times", m1.getOrder()); |
976 return false; | 902 return; |
977 } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { | 903 } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { |
978 log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); | 904 m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); |
979 log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); | 905 m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); |
980 return false; | 906 return; |
981 } | 907 } |
982 } else if (inferredOrder == 0) { | 908 } else if (inferredOrder == 0) { |
983 SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); | 909 SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); |
984 log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); | 910 m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); |
985 return false; | 911 return; |
986 } | 912 } |
987 } | 913 } |
988 } | 914 } |
989 return true; | 915 } |
990 } | 916 |
991 | 917 private static void verifySpecializationThrows(NodeData node) { |
992 private boolean verifySpecializationThrows(NodeData node) { | |
993 Map<String, SpecializationData> specializationMap = new HashMap<>(); | 918 Map<String, SpecializationData> specializationMap = new HashMap<>(); |
994 for (SpecializationData spec : node.getSpecializations()) { | 919 for (SpecializationData spec : node.getSpecializations()) { |
995 specializationMap.put(spec.getMethodName(), spec); | 920 specializationMap.put(spec.getMethodName(), spec); |
996 } | 921 } |
997 boolean valid = true; | |
998 for (SpecializationData sourceSpecialization : node.getSpecializations()) { | 922 for (SpecializationData sourceSpecialization : node.getSpecializations()) { |
999 if (sourceSpecialization.getExceptions() != null) { | 923 if (sourceSpecialization.getExceptions() != null) { |
1000 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { | 924 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { |
1001 for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { | 925 for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { |
1002 if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { | 926 if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { |
1003 AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "rewriteOn"); | 927 throwsData.addError("Duplicate exception type."); |
1004 log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type."); | |
1005 valid = false; | |
1006 } | 928 } |
1007 } | 929 } |
1008 } | 930 } |
1009 } | 931 } |
1010 } | 932 } |
1011 return valid; | |
1012 } | 933 } |
1013 | 934 |
1014 private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { | 935 private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { |
1015 if (m1 == m2) { | 936 if (m1 == m2) { |
1016 return 0; | 937 return 0; |