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;