Mercurial > hg > truffle
diff 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 |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Tue Jan 07 12:22:47 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Tue Jan 07 18:52:32 2014 +0100 @@ -34,14 +34,15 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; +import com.oracle.truffle.dsl.processor.node.SpecializationData.*; import com.oracle.truffle.dsl.processor.template.*; import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature; import com.oracle.truffle.dsl.processor.typesystem.*; -public class NodeParser extends TemplateParser<NodeData> { +public class NodeParser extends AbstractParser<NodeData> { - public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, - NodeContainer.class, NodeChild.class, NodeChildren.class, NodeId.class); + public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, + NodeChildren.class); private Map<String, NodeData> parsedNodes; @@ -51,7 +52,6 @@ @Override protected NodeData parse(Element element, AnnotationMirror mirror) { - assert element instanceof TypeElement; NodeData node = null; try { parsedNodes = new HashMap<>(); @@ -72,7 +72,7 @@ @Override protected NodeData filterErrorElements(NodeData model) { - for (Iterator<NodeData> iterator = model.getDeclaredNodes().iterator(); iterator.hasNext();) { + for (Iterator<NodeData> iterator = model.getEnclosingNodes().iterator(); iterator.hasNext();) { NodeData node = filterErrorElements(iterator.next()); if (node == null) { iterator.remove(); @@ -105,29 +105,27 @@ return parsedNodes.get(typeName); } - List<? extends TypeElement> types = ElementFilter.typesIn(rootType.getEnclosedElements()); - - List<NodeData> children = new ArrayList<>(); - for (TypeElement childElement : types) { - NodeData childNode = resolveNode(childElement); - if (childNode != null) { - children.add(childNode); + List<NodeData> enclosedNodes = new ArrayList<>(); + for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) { + NodeData enclosedChild = resolveNode(enclosedType); + if (enclosedChild != null) { + enclosedNodes.add(enclosedChild); } } - NodeData rootNode = parseNode(rootType); - if (rootNode == null && children.size() > 0) { - rootNode = new NodeData(rootType, rootType.getSimpleName().toString()); + NodeData node = parseNode(rootType); + if (node == null && !enclosedNodes.isEmpty()) { + node = new NodeData(rootType); } - parsedNodes.put(typeName, rootNode); - - if (rootNode != null) { - children.addAll(rootNode.getDeclaredNodes()); - rootNode.setDeclaredNodes(children); + if (node != null) { + for (NodeData enclosedNode : enclosedNodes) { + node.addEnclosedNode(enclosedNode); + } } - return rootNode; + parsedNodes.put(typeName, node); + return node; } private NodeData parseNode(TypeElement originalTemplateType) { @@ -139,153 +137,69 @@ return null; } - List<TypeElement> lookupTypes = findSuperClasses(new ArrayList<TypeElement>(), templateType); - Collections.reverse(lookupTypes); - - AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeContainer.class); - TypeMirror nodeType = null; - if (Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) { - nodeType = templateType.asType(); - } - if (nodeClass != null) { - nodeType = inheritType(nodeClass, "value", nodeType); - } - - if (nodeType == null) { + List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType); + if (!Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) { return null; } - Elements elementUtil = context.getEnvironment().getElementUtils(); - Set<Element> elementSet = new HashSet<>(elementUtil.getAllMembers(templateType)); - if (!Utils.typeEquals(templateType.asType(), nodeType)) { - elementSet.addAll(elementUtil.getAllMembers(Utils.fromTypeMirror(nodeType))); - - List<TypeElement> nodeLookupTypes = findSuperClasses(new ArrayList<TypeElement>(), Utils.fromTypeMirror(nodeType)); - Collections.reverse(nodeLookupTypes); - lookupTypes.addAll(nodeLookupTypes); + List<? extends Element> elements = context.getEnvironment().getElementUtils().getAllMembers(templateType); - Set<TypeElement> types = new HashSet<>(); - for (ListIterator<TypeElement> iterator = lookupTypes.listIterator(); iterator.hasNext();) { - TypeElement typeElement = iterator.next(); - if (types.contains(typeElement)) { - iterator.remove(); - } else { - types.add(typeElement); - } - } - } - List<Element> elements = new ArrayList<>(elementSet); - - NodeData node = parseNodeData(templateType, nodeType, elements, lookupTypes); - + NodeData node = parseNodeData(templateType, elements, lookupTypes); if (node.hasErrors()) { return node; // error sync point } - parseMethods(node, elements); + initializeChildren(node); + + node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements)); + node.getSpecializations().addAll(new GenericParser(context, node).parse(elements)); + node.getCasts().addAll(new CreateCastParser(context, node).parse(elements)); + node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements)); if (node.hasErrors()) { - return node; - } - - List<NodeData> nodes; - - if (node.isNodeContainer()) { - nodes = splitNodeData(node); - } else { - nodes = new ArrayList<>(); - nodes.add(node); + return node; // error sync point } - for (NodeData splittedNode : nodes) { - if (templateType.getModifiers().contains(Modifier.PRIVATE) && splittedNode.getSpecializations().size() > 0) { - splittedNode.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); - } + verifySpecializationSameLength(node); + initializeSpecializations(elements, node); + initializeShortCircuits(node); // requires specializations and polymorphic specializations - finalizeSpecializations(elements, splittedNode); - verifyNode(splittedNode, elements); - createPolymorphicSpecializations(splittedNode); - assignShortCircuitsToSpecializations(splittedNode); - } - - if (node.isNodeContainer()) { - node.setDeclaredNodes(nodes); - node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); - node.setSpecializations(new ArrayList<SpecializationData>()); - } + verifyVisibilities(node); + verifySpecializationOrder(node); + verifyMissingAbstractMethods(node, elements); + verifyConstructors(node); + verifyNamingConvention(node.getShortCircuits(), "needs"); + verifySpecializationThrows(node); return node; } - private void createPolymorphicSpecializations(NodeData node) { - if (!node.needsRewrites(context) || !node.isPolymorphic()) { - node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); - return; - } - - SpecializationData generic = node.getGenericSpecialization(); - - List<TypeData> polymorphicSignature = new ArrayList<>(); - // TODO we should support more optimized for boxing - // List<ActualParameter> updatePolymorphic = generic.getReturnTypeAndParameters(); - List<ActualParameter> updatePolymorphic = Arrays.asList(); - for (ActualParameter genericParameter : updatePolymorphic) { - if (!genericParameter.getSpecification().isSignature()) { - continue; - } - - Set<TypeData> usedTypes = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isSpecialized()) { - continue; - } - ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName()); - if (parameter == null) { - throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); - } - usedTypes.add(parameter.getTypeSystemType()); - } - - TypeData polymorphicType; - if (usedTypes.size() == 1) { - polymorphicType = usedTypes.iterator().next(); - } else { - polymorphicType = node.getTypeSystem().getGenericTypeData(); - } - polymorphicSignature.add(polymorphicType); - } - - SpecializationData specialization = new SpecializationData(generic, false, false, true); - specialization.updateSignature(new TypeSignature(polymorphicSignature)); - specialization.setNode(node); - node.setGenericPolymorphicSpecialization(specialization); - // TODO remove polymoprhic specializations - node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); - } - - private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> typeHierarchy) { - NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); - + private NodeData parseNodeData(TypeElement templateType, List<? extends Element> elements, List<TypeElement> typeHierarchy) { AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) { - nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType)); + NodeData nodeData = new NodeData(templateType); + nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(templateType)); return nodeData; } - TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); + TypeMirror typeSystemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); if (typeSystem == null) { - nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSytemType)); + NodeData nodeData = new NodeData(templateType); + nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSystemType)); return nodeData; } AnnotationMirror polymorphicMirror = findFirstAnnotation(typeHierarchy, PolymorphicLimit.class); + int polymorphicLimit = -1; if (polymorphicMirror != null) { AnnotationValue limitValue = Utils.getAnnotationValue(polymorphicMirror, "value"); - int polymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value"); - if (polymorphicLimit < 1) { + int customPolymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value"); + if (customPolymorphicLimit < 1) { + NodeData nodeData = new NodeData(templateType); nodeData.addError(limitValue, "Invalid polymorphic limit %s.", polymorphicLimit); + return nodeData; } - nodeData.setPolymorphicDepth(polymorphicLimit); + polymorphicLimit = customPolymorphicLimit; } List<String> assumptionsList = new ArrayList<>(); @@ -303,109 +217,21 @@ } } AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); + String shortName = null; if (nodeInfoMirror != null) { - nodeData.setShortName(Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName")); - } - - nodeData.setAssumptions(new ArrayList<>(assumptionsList)); - nodeData.setNodeType(nodeType); - AnnotationMirror nodeContainer = findFirstAnnotation(typeHierarchy, NodeContainer.class); - nodeData.setNodeContainer(nodeContainer != null); - nodeData.setTypeSystem(typeSystem); - nodeData.setFields(parseFields(typeHierarchy, elements)); - nodeData.setChildren(parseChildren(nodeData, elements, typeHierarchy)); - nodeData.setChildExecutions(parseDefaultSignature(nodeData, elements)); - nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - - // resolveChildren invokes cyclic parsing. - parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - resolveChildren(nodeData); - - return nodeData; - } - - private List<NodeExecutionData> parseDefaultSignature(NodeData node, List<? extends Element> elements) { - if (node.getChildren() == null) { - return null; - } - - // pre-parse short circuits - Set<String> shortCircuits = new HashSet<>(); - List<ExecutableElement> methods = ElementFilter.methodsIn(elements); - for (ExecutableElement method : methods) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); - if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); - } - } - - boolean hasVarArgs = false; - int maxSignatureSize = 0; - if (!node.getChildren().isEmpty()) { - int lastIndex = node.getChildren().size() - 1; - hasVarArgs = node.getChildren().get(lastIndex).getCardinality() == Cardinality.MANY; - if (hasVarArgs) { - maxSignatureSize = lastIndex; - } else { - maxSignatureSize = node.getChildren().size(); - } + shortName = Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName"); } - // pre-parse specializations - for (ExecutableElement method : methods) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class); - if (mirror == null) { - continue; - } + List<NodeFieldData> fields = parseFields(typeHierarchy, elements); + List<NodeChildData> children = parseChildren(elements, typeHierarchy); + List<NodeExecutionData> executions = parseExecutions(children, elements); - int currentArgumentCount = 0; - boolean skipShortCircuit = false; - for (VariableElement var : method.getParameters()) { - TypeMirror type = var.asType(); - if (currentArgumentCount == 0) { - // skip optionals - if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) { - continue; - } - // TODO skip optional fields? - } - int childIndex = currentArgumentCount < node.getChildren().size() ? currentArgumentCount : node.getChildren().size() - 1; - if (childIndex == -1) { - continue; - } - if (!skipShortCircuit) { - NodeChildData child = node.getChildren().get(childIndex); - if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { - skipShortCircuit = true; - continue; - } - } else { - skipShortCircuit = false; - } + NodeData nodeData = new NodeData(templateType, shortName, typeSystem, children, executions, fields, assumptionsList, polymorphicLimit); + nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - currentArgumentCount++; - } - maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); - } + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - List<NodeExecutionData> executions = new ArrayList<>(); - for (int i = 0; i < maxSignatureSize; i++) { - int childIndex = i; - boolean varArg = false; - if (childIndex >= node.getChildren().size() - 1) { - if (hasVarArgs) { - childIndex = node.getChildren().size() - 1; - varArg = hasVarArgs; - } else if (childIndex >= node.getChildren().size()) { - break; - } - } - int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; - NodeChildData child = node.getChildren().get(childIndex); - boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex)); - executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); - } - return executions; + return nodeData; } private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) { @@ -452,28 +278,7 @@ return fields; } - private void resolveChildren(NodeData node) { - for (NodeChildData nodeChild : node.getChildren()) { - NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeChild.getNodeType())); - nodeChild.setNode(fieldNodeData); - if (fieldNodeData == null) { - nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(nodeChild.getNodeType())); - } else if (!Utils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { - nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), - NodeChild.class.getSimpleName(), Utils.getSimpleName(node.getTypeSystem().getTemplateType()), Utils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); - } - if (fieldNodeData != null) { - List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context); - if (types.isEmpty()) { - AnnotationValue executeWithValue = Utils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith"); - nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(), - Utils.getSimpleName(nodeChild.getNodeType())); - } - } - } - } - - private List<NodeChildData> parseChildren(NodeData parent, List<? extends Element> elements, final List<TypeElement> typeHierarchy) { + private List<NodeChildData> parseChildren(List<? extends Element> elements, final List<TypeElement> typeHierarchy) { Set<String> shortCircuits = new HashSet<>(); for (ExecutableElement method : ElementFilter.methodsIn(elements)) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); @@ -498,7 +303,6 @@ List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy); Collections.reverse(typeHierarchyReversed); for (TypeElement type : typeHierarchyReversed) { - AnnotationMirror nodeClassMirror = Utils.findAnnotationMirror(processingEnv, type, NodeContainer.class); AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class); TypeMirror nodeClassType = type.getSuperclass(); @@ -506,10 +310,6 @@ nodeClassType = null; } - if (nodeClassMirror != null) { - nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType); - } - List<AnnotationMirror> children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); int index = 0; for (AnnotationMirror childMirror : children) { @@ -533,11 +333,13 @@ Element getter = findGetter(elements, name, childType); - NodeChildData nodeChild = new NodeChildData(parent, type, childMirror, name, childType, originalChildType, getter, cardinality); + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality); parsedChildren.add(nodeChild); - verifyNodeChild(nodeChild); + if (nodeChild.getNodeType() == null) { + nodeChild.addError("No valid node type could be resoleved."); + } if (nodeChild.hasErrors()) { continue; } @@ -599,153 +401,182 @@ return filteredChildren; } - private void parseMethods(final NodeData node, List<Element> elements) { - node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); - node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); - List<SpecializationData> generics = new GenericParser(context, node).parse(elements); - List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements); - node.setCasts(new CreateCastParser(context, node).parse(elements)); + private List<NodeExecutionData> parseExecutions(List<NodeChildData> children, List<? extends Element> elements) { + if (children == null) { + return null; + } + + // pre-parse short circuits + Set<String> shortCircuits = new HashSet<>(); + List<ExecutableElement> methods = ElementFilter.methodsIn(elements); + for (ExecutableElement method : methods) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); + if (mirror != null) { + shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); + } + } + + boolean hasVarArgs = false; + int maxSignatureSize = 0; + if (!children.isEmpty()) { + int lastIndex = children.size() - 1; + hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY; + if (hasVarArgs) { + maxSignatureSize = lastIndex; + } else { + maxSignatureSize = children.size(); + } + } + + // pre-parse specializations + for (ExecutableElement method : methods) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class); + if (mirror == null) { + continue; + } - List<SpecializationData> allSpecializations = new ArrayList<>(); - allSpecializations.addAll(generics); - allSpecializations.addAll(specializations); + int currentArgumentCount = 0; + boolean skipShortCircuit = false; + for (VariableElement var : method.getParameters()) { + TypeMirror type = var.asType(); + if (currentArgumentCount == 0) { + // skip optionals + if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) { + continue; + } + // TODO skip optional fields? + } + int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1; + if (childIndex == -1) { + continue; + } + if (!skipShortCircuit) { + NodeChildData child = children.get(childIndex); + if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { + skipShortCircuit = true; + continue; + } + } else { + skipShortCircuit = false; + } - node.setSpecializations(allSpecializations); + currentArgumentCount++; + } + maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); + } + + List<NodeExecutionData> executions = new ArrayList<>(); + for (int i = 0; i < maxSignatureSize; i++) { + int childIndex = i; + boolean varArg = false; + if (childIndex >= children.size() - 1) { + if (hasVarArgs) { + childIndex = children.size() - 1; + varArg = hasVarArgs; + } else if (childIndex >= children.size()) { + break; + } + } + int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; + NodeChildData child = children.get(childIndex); + boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex)); + executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); + } + return executions; } - private static List<NodeData> splitNodeData(NodeData node) { - SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations()); - SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners()); - SortedMap<String, List<CreateCastData>> groupedCasts = groupByNodeId(node.getCasts()); - - Set<String> ids = new TreeSet<>(); - ids.addAll(groupedSpecializations.keySet()); - ids.addAll(groupedListeners.keySet()); + private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) { + Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>(); + for (ExecutableTypeData type : executableTypes) { + int evaluatedCount = type.getEvaluatedCount(); - List<NodeData> splitted = new ArrayList<>(); - for (String id : ids) { - List<SpecializationData> specializations = groupedSpecializations.get(id); - List<SpecializationListenerData> listeners = groupedListeners.get(id); - List<CreateCastData> casts = groupedCasts.get(id); - - if (specializations == null) { - specializations = new ArrayList<>(); + List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount); + if (types == null) { + types = new ArrayList<>(); + groupedTypes.put(evaluatedCount, types); } - - if (listeners == null) { - listeners = new ArrayList<>(); - } - - String nodeId = node.getNodeId(); - if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { - nodeId = nodeId.substring(0, nodeId.length() - 4); - } - String newNodeId = nodeId + Utils.firstLetterUpperCase(id); - NodeData copy = new NodeData(node, id, newNodeId); - - copy.setSpecializations(specializations); - copy.setSpecializationListeners(listeners); - copy.setCasts(casts); - - splitted.add(copy); + types.add(type); } - node.setSpecializations(new ArrayList<SpecializationData>()); - node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); - node.setCasts(new ArrayList<CreateCastData>()); - - return splitted; + for (List<ExecutableTypeData> types : groupedTypes.values()) { + Collections.sort(types); + } + return groupedTypes; } - private void finalizeSpecializations(List<Element> elements, final NodeData node) { - List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); + private void initializeChildren(NodeData node) { + for (NodeChildData nodeChild : node.getChildren()) { + NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeChild.getNodeType())); + nodeChild.setNode(fieldNodeData); + if (fieldNodeData == null) { + nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(nodeChild.getNodeType())); + } else if (!Utils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { + nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), + NodeChild.class.getSimpleName(), Utils.getSimpleName(node.getTypeSystem().getTemplateType()), Utils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); + } + if (fieldNodeData != null) { + List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context); + if (types.isEmpty()) { + AnnotationValue executeWithValue = Utils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith"); + nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(), + Utils.getSimpleName(nodeChild.getNodeType())); + } + } + } + } - if (specializations.isEmpty()) { + private void initializeSpecializations(List<? extends Element> elements, final NodeData node) { + if (node.getSpecializations().isEmpty()) { return; } - for (SpecializationData specialization : specializations) { - matchGuards(elements, specialization); - } - - List<SpecializationData> generics = new ArrayList<>(); - for (SpecializationData spec : specializations) { - if (spec.isGeneric()) { - generics.add(spec); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; } - } - - if (generics.size() == 1 && specializations.size() == 1) { - for (SpecializationData generic : generics) { - generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); - } - } - - SpecializationData genericSpecialization = null; - if (generics.size() > 1) { - for (SpecializationData generic : generics) { - generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); - } - return; - } else if (generics.size() == 1) { - genericSpecialization = generics.get(0); - } else if (node.needsRewrites(context)) { - genericSpecialization = createGenericSpecialization(node, specializations); - specializations.add(genericSpecialization); + initializeGuards(elements, specialization); } - if (genericSpecialization != null) { - for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) { - if (Utils.isObject(parameter.getType())) { - continue; - } - Set<String> types = new HashSet<>(); - for (SpecializationData specialization : specializations) { - ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName()); - if (actualParameter != null) { - types.add(Utils.getQualifiedName(actualParameter.getType())); - } - } - if (types.size() > 1) { - genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData())); - } - } - TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), null, null, genericSpecialization.getReturnType(), - genericSpecialization.getParameters()); - // should not use messages from generic specialization - uninializedMethod.getMessages().clear(); - specializations.add(new SpecializationData(uninializedMethod, false, true, false)); + initializeGeneric(node); + initializeUninitialized(node); + initializePolymorphism(node); // requires specializations + Collections.sort(node.getSpecializations()); + initializeReachability(node); + + // reduce polymorphicness if generic is not reachable + if (node.getGenericSpecialization() != null && !node.getGenericSpecialization().isReachable()) { + node.setPolymorphicDepth(1); + node.getSpecializations().remove(node.getPolymorphicSpecialization()); } - Collections.sort(specializations); - - node.setSpecializations(specializations); - List<SpecializationData> needsId = new ArrayList<>(); - for (SpecializationData specialization : specializations) { + for (SpecializationData specialization : node.getSpecializations()) { if (specialization.isGeneric()) { specialization.setId("Generic"); } else if (specialization.isUninitialized()) { specialization.setId("Uninitialized"); + } else if (specialization.isPolymorphic()) { + specialization.setId("Polymorphic"); + } else if (specialization.isSpecialized()) { + needsId.add(specialization); } else { - needsId.add(specialization); + throw new AssertionError(); } } // verify specialization parameter length - if (verifySpecializationParameters(node)) { - List<String> ids = calculateSpecializationIds(needsId); - for (int i = 0; i < ids.size(); i++) { - needsId.get(i).setId(ids.get(i)); - } + List<String> ids = initializeSpecializationIds(needsId); + for (int i = 0; i < ids.size(); i++) { + needsId.get(i).setId(ids.get(i)); } - // calculate reachability + } + + private void initializeReachability(final NodeData node) { SpecializationData prev = null; - int polymorphicCombinations = 0; boolean reachable = true; - for (SpecializationData specialization : specializations) { - if (specialization.isUninitialized()) { + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isUninitialized() || specialization.isPolymorphic()) { specialization.setReachable(true); continue; } @@ -758,199 +589,15 @@ if (!specialization.hasRewrite(context)) { reachable = false; } - if (!specialization.isGeneric()) { - int combinations = 1; - for (ActualParameter parameter : specialization.getParameters()) { - if (!parameter.getSpecification().isSignature()) { - continue; - } - TypeData type = parameter.getTypeSystemType(); - combinations *= node.getTypeSystem().lookupSourceTypes(type).size(); - } - polymorphicCombinations += combinations; - } - prev = specialization; } - - // initialize polymorphic depth - if (node.getPolymorphicDepth() < 0) { - node.setPolymorphicDepth(polymorphicCombinations - 1); - } - - // reduce polymorphicness if generic is not reachable - if (node.getGenericSpecialization() != null && !node.getGenericSpecialization().isReachable()) { - node.setPolymorphicDepth(1); - } - } - - private SpecializationData createGenericSpecialization(final NodeData node, List<SpecializationData> specializations) { - SpecializationData specialization = specializations.get(0); - GenericParser parser = new GenericParser(context, node); - MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); - specification.getImplicitRequiredTypes().clear(); - - List<TypeMirror> parameterTypes = new ArrayList<>(); - int signatureIndex = 1; - for (ParameterSpec spec : specification.getRequired()) { - parameterTypes.add(createGenericType(spec, specializations, signatureIndex)); - if (spec.isSignature()) { - signatureIndex++; - } - } - TypeMirror returnType = createGenericType(specification.getReturnType(), specializations, 0); - return parser.create("Generic", null, null, returnType, parameterTypes); - } - - private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) { - NodeExecutionData execution = spec.getExecution(); - if (execution == null) { - if (spec.getAllowedTypes().size() == 1) { - return spec.getAllowedTypes().get(0); - } else { - return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); - } - } else { - Set<TypeData> types = new HashSet<>(); - for (SpecializationData specialization : specializations) { - types.add(specialization.getTypeSignature().get(signatureIndex)); - } - - NodeChildData child = execution.getChild(); - - TypeData genericType = null; - if (types.size() == 1) { - ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); - if (executable != null && !executable.hasUnexpectedValue(context)) { - genericType = types.iterator().next(); - } - } - if (genericType == null) { - genericType = child.findAnyGenericExecutableType(context).getType(); - } - return genericType.getPrimitiveType(); - } } - private void assignShortCircuitsToSpecializations(NodeData node) { - Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); - - boolean valid = true; - List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>(); - for (NodeExecutionData execution : node.getChildExecutions()) { - if (!execution.isShortCircuit()) { - continue; - } - shortCircuitExecutions.add(execution); - String valueName = execution.getShortCircuitId(); - List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); - - if (availableCircuits == null || availableCircuits.isEmpty()) { - node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); - valid = false; - continue; - } - - boolean sameMethodName = true; - String methodName = availableCircuits.get(0).getMethodName(); - for (ShortCircuitData circuit : availableCircuits) { - if (!circuit.getMethodName().equals(methodName)) { - sameMethodName = false; - } - } - - if (!sameMethodName) { - for (ShortCircuitData circuit : availableCircuits) { - circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName); - } - valid = false; - continue; - } - - ShortCircuitData genericCircuit = null; - for (ShortCircuitData circuit : availableCircuits) { - if (isGenericShortCutMethod(circuit)) { - genericCircuit = circuit; - break; - } - } - - if (genericCircuit == null) { - node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); - valid = false; - continue; - } - - for (ShortCircuitData circuit : availableCircuits) { - if (circuit != genericCircuit) { - circuit.setGenericShortCircuitMethod(genericCircuit); - } - } - } - - if (!valid) { - return; - } - - List<SpecializationData> specializations = new ArrayList<>(); - specializations.addAll(node.getSpecializations()); - specializations.addAll(node.getPolymorphicSpecializations()); - - for (SpecializationData specialization : specializations) { - List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size()); - - for (NodeExecutionData shortCircuit : shortCircuitExecutions) { - List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId()); - - ShortCircuitData genericShortCircuit = null; - ShortCircuitData compatibleShortCircuit = null; - for (ShortCircuitData circuit : availableShortCuts) { - if (circuit.isGeneric()) { - genericShortCircuit = circuit; - } else if (circuit.isCompatibleTo(specialization)) { - compatibleShortCircuit = circuit; - } - } - - if (compatibleShortCircuit == null) { - compatibleShortCircuit = genericShortCircuit; - } - assignedShortCuts.add(compatibleShortCircuit); - } - specialization.setShortCircuits(assignedShortCuts); - } - } - - private void matchGuards(List<Element> elements, SpecializationData specialization) { - if (specialization.getGuardDefinitions().isEmpty()) { - specialization.setGuards(Collections.<GuardData> emptyList()); - return; - } - - List<GuardData> foundGuards = new ArrayList<>(); - List<ExecutableElement> methods = ElementFilter.methodsIn(elements); - for (String guardDefinition : specialization.getGuardDefinitions()) { - GuardParser parser = new GuardParser(context, specialization, guardDefinition); - List<GuardData> guards = parser.parse(methods); - if (!guards.isEmpty()) { - foundGuards.add(guards.get(0)); - } else { - // error no guard found - MethodSpec spec = parser.createSpecification(specialization.getMethod(), null); - spec.applyTypeDefinitions("types"); - specialization.addError("Guard with method name '%s' not found. Expected signature: %n%s", guardDefinition, spec.toSignatureString("guard")); - } - } - - specialization.setGuards(foundGuards); - - } - - private static List<String> calculateSpecializationIds(List<SpecializationData> specializations) { + private static List<String> initializeSpecializationIds(List<SpecializationData> specializations) { int lastSize = -1; List<List<String>> signatureChunks = new ArrayList<>(); for (SpecializationData other : specializations) { - if (other.isUninitialized() || other.isGeneric()) { + if (!other.isSpecialized()) { continue; } List<String> paramIds = new LinkedList<>(); @@ -1058,25 +705,370 @@ return signatures; } - private void verifyNode(NodeData nodeData, List<? extends Element> elements) { - // verify order is not ambiguous - verifySpecializationOrder(nodeData); + private void initializeGuards(List<? extends Element> elements, SpecializationData specialization) { + if (specialization.getGuardDefinitions().isEmpty()) { + specialization.setGuards(Collections.<GuardData> emptyList()); + return; + } + + List<GuardData> foundGuards = new ArrayList<>(); + List<ExecutableElement> methods = ElementFilter.methodsIn(elements); + for (String guardDefinition : specialization.getGuardDefinitions()) { + GuardParser parser = new GuardParser(context, specialization, guardDefinition); + List<GuardData> guards = parser.parse(methods); + if (!guards.isEmpty()) { + foundGuards.add(guards.get(0)); + } else { + // error no guard found + MethodSpec spec = parser.createSpecification(specialization.getMethod(), null); + spec.applyTypeDefinitions("types"); + specialization.addError("Guard with method name '%s' not found. Expected signature: %n%s", guardDefinition, spec.toSignatureString("guard")); + } + } + + specialization.setGuards(foundGuards); + + } + + private void initializeGeneric(final NodeData node) { + if (!node.needsRewrites(context)) { + return; + } - verifyMissingAbstractMethods(nodeData, elements); + List<SpecializationData> generics = new ArrayList<>(); + for (SpecializationData spec : node.getSpecializations()) { + if (spec.isGeneric()) { + generics.add(spec); + } + } + + if (generics.size() == 1 && node.getSpecializations().size() == 1) { + // TODO this limitation should be lifted + for (SpecializationData generic : generics) { + generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); + } + } + + if (generics.isEmpty()) { + node.getSpecializations().add(createGenericSpecialization(node)); + } else { + if (generics.size() > 1) { + for (SpecializationData generic : generics) { + generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); + } + } + } + } + + private SpecializationData createGenericSpecialization(final NodeData node) { + SpecializationData specialization = node.getSpecializations().get(0); + GenericParser parser = new GenericParser(context, node); + MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); + specification.getImplicitRequiredTypes().clear(); + + List<TypeMirror> parameterTypes = new ArrayList<>(); + int signatureIndex = 1; + for (ParameterSpec spec : specification.getRequired()) { + parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex)); + if (spec.isSignature()) { + signatureIndex++; + } + } + TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0); + return parser.create("Generic", null, null, returnType, parameterTypes); + } - verifyConstructors(nodeData); + private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) { + NodeExecutionData execution = spec.getExecution(); + if (execution == null) { + if (spec.getAllowedTypes().size() == 1) { + return spec.getAllowedTypes().get(0); + } else { + return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); + } + } else { + Set<TypeData> types = new HashSet<>(); + for (SpecializationData specialization : specializations) { + types.add(specialization.getTypeSignature().get(signatureIndex)); + } + + NodeChildData child = execution.getChild(); + + TypeData genericType = null; + if (types.size() == 1) { + ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); + if (executable != null && !executable.hasUnexpectedValue(context)) { + genericType = types.iterator().next(); + } + } + if (genericType == null) { + genericType = child.findAnyGenericExecutableType(context).getType(); + } + return genericType.getPrimitiveType(); + } + } - verifyNamingConvention(nodeData.getShortCircuits(), "needs"); + private static void initializeUninitialized(final NodeData node) { + SpecializationData generic = node.getGenericSpecialization(); + if (generic == null) { + return; + } + for (ActualParameter parameter : generic.getReturnTypeAndParameters()) { + if (Utils.isObject(parameter.getType())) { + continue; + } + Set<String> types = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName()); + if (actualParameter != null) { + types.add(Utils.getQualifiedName(actualParameter.getType())); + } + } + if (types.size() > 1) { + generic.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData())); + } + } + TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); + // should not use messages from generic specialization + uninializedMethod.getMessages().clear(); + node.getSpecializations().add(new SpecializationData(node, uninializedMethod, SpecializationKind.UNINITIALIZED)); + } + + private void initializePolymorphism(NodeData node) { + initializePolymorphicDepth(node); + + if (!node.needsRewrites(context) || !node.isPolymorphic()) { + return; + } - verifySpecializationThrows(nodeData); + SpecializationData generic = node.getGenericSpecialization(); + + List<TypeData> polymorphicSignature = new ArrayList<>(); + List<ActualParameter> updatePolymorphic = Arrays.asList(); + for (ActualParameter genericParameter : updatePolymorphic) { + if (!genericParameter.getSpecification().isSignature()) { + continue; + } + + Set<TypeData> usedTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName()); + if (parameter == null) { + throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + } + usedTypes.add(parameter.getTypeSystemType()); + } + + TypeData polymorphicType; + if (usedTypes.size() == 1) { + polymorphicType = usedTypes.iterator().next(); + } else { + polymorphicType = node.getTypeSystem().getGenericTypeData(); + } + polymorphicSignature.add(polymorphicType); + } + + SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); + polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); + node.getSpecializations().add(polymorphic); } - private static void verifyNodeChild(NodeChildData nodeChild) { - if (nodeChild.getNodeType() == null) { - nodeChild.addError("No valid node type could be resoleved."); + private static void initializePolymorphicDepth(final NodeData node) { + int polymorphicCombinations = 0; + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isGeneric()) { + continue; + } + + int combinations = 1; + for (ActualParameter parameter : specialization.getSignatureParameters()) { + combinations *= node.getTypeSystem().lookupSourceTypes(parameter.getTypeSystemType()).size(); + } + polymorphicCombinations += combinations; + } + + // initialize polymorphic depth + if (node.getPolymorphicDepth() < 0) { + node.setPolymorphicDepth(polymorphicCombinations - 1); + } + + } + + private void initializeShortCircuits(NodeData node) { + Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); + + boolean valid = true; + List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>(); + for (NodeExecutionData execution : node.getChildExecutions()) { + if (!execution.isShortCircuit()) { + continue; + } + shortCircuitExecutions.add(execution); + String valueName = execution.getShortCircuitId(); + List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); + + if (availableCircuits == null || availableCircuits.isEmpty()) { + node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); + valid = false; + continue; + } + + boolean sameMethodName = true; + String methodName = availableCircuits.get(0).getMethodName(); + for (ShortCircuitData circuit : availableCircuits) { + if (!circuit.getMethodName().equals(methodName)) { + sameMethodName = false; + } + } + + if (!sameMethodName) { + for (ShortCircuitData circuit : availableCircuits) { + circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName); + } + valid = false; + continue; + } + + ShortCircuitData genericCircuit = null; + for (ShortCircuitData circuit : availableCircuits) { + if (isGenericShortCutMethod(circuit)) { + genericCircuit = circuit; + break; + } + } + + if (genericCircuit == null) { + node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); + valid = false; + continue; + } + + for (ShortCircuitData circuit : availableCircuits) { + if (circuit != genericCircuit) { + circuit.setGenericShortCircuitMethod(genericCircuit); + } + } + } + + if (!valid) { + return; } - // FIXME verify node child - // FIXME verify node type set + + List<SpecializationData> specializations = new ArrayList<>(); + specializations.addAll(node.getSpecializations()); + for (SpecializationData specialization : specializations) { + List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size()); + + for (NodeExecutionData shortCircuit : shortCircuitExecutions) { + List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId()); + + ShortCircuitData genericShortCircuit = null; + ShortCircuitData compatibleShortCircuit = null; + for (ShortCircuitData circuit : availableShortCuts) { + if (circuit.isGeneric()) { + genericShortCircuit = circuit; + } else if (circuit.isCompatibleTo(specialization)) { + compatibleShortCircuit = circuit; + } + } + + if (compatibleShortCircuit == null) { + compatibleShortCircuit = genericShortCircuit; + } + assignedShortCuts.add(compatibleShortCircuit); + } + specialization.setShortCircuits(assignedShortCuts); + } + } + + private boolean isGenericShortCutMethod(ShortCircuitData method) { + for (ActualParameter parameter : method.getParameters()) { + NodeExecutionData execution = parameter.getSpecification().getExecution(); + if (execution == null) { + continue; + } + ExecutableTypeData found = null; + List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context); + for (ExecutableTypeData executable : executableElements) { + if (executable.getType().equalsType(parameter.getTypeSystemType())) { + found = executable; + break; + } + } + if (found == null) { + return false; + } + } + return true; + } + + private static Map<String, List<ShortCircuitData>> groupShortCircuits(List<ShortCircuitData> shortCircuits) { + Map<String, List<ShortCircuitData>> group = new HashMap<>(); + for (ShortCircuitData shortCircuit : shortCircuits) { + List<ShortCircuitData> circuits = group.get(shortCircuit.getValueName()); + if (circuits == null) { + circuits = new ArrayList<>(); + group.put(shortCircuit.getValueName(), circuits); + } + circuits.add(shortCircuit); + } + return group; + } + + private static boolean verifySpecializationSameLength(NodeData nodeData) { + int lastArgs = -1; + for (SpecializationData specializationData : nodeData.getSpecializations()) { + int signatureArgs = specializationData.getSignatureSize(); + if (lastArgs == signatureArgs) { + continue; + } + if (lastArgs != -1) { + for (SpecializationData specialization : nodeData.getSpecializations()) { + specialization.addError("All specializations must have the same number of arguments."); + } + return false; + } else { + lastArgs = signatureArgs; + } + } + return true; + } + + private static void verifyVisibilities(NodeData node) { + if (node.getTemplateType().getModifiers().contains(Modifier.PRIVATE) && node.getSpecializations().size() > 0) { + node.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); + } + } + + private static void verifySpecializationOrder(NodeData node) { + List<SpecializationData> specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size(); i++) { + SpecializationData m1 = specializations.get(i); + for (int j = i + 1; j < specializations.size(); j++) { + SpecializationData m2 = specializations.get(j); + int inferredOrder = m1.compareBySignature(m2); + + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + int specOrder = m1.getOrder() - m2.getOrder(); + if (specOrder == 0) { + m1.addError("Order value %d used multiple times", m1.getOrder()); + m2.addError("Order value %d used multiple times", m1.getOrder()); + return; + } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { + m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + return; + } + } else if (inferredOrder == 0) { + SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); + m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); + return; + } + } + } } private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) { @@ -1087,7 +1079,6 @@ } List<Element> elements = new ArrayList<>(originalElements); - Set<Element> unusedElements = new HashSet<>(elements); for (TemplateMethod method : nodeData.getAllTemplateMethods()) { unusedElements.remove(method.getMethod()); @@ -1112,6 +1103,33 @@ } } + private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) { + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { + m1.addError("Naming convention: method name must start with '%s'.", prefix); + } + } + } + + private static void verifySpecializationThrows(NodeData node) { + Map<String, SpecializationData> specializationMap = new HashMap<>(); + for (SpecializationData spec : node.getSpecializations()) { + specializationMap.put(spec.getMethodName(), spec); + } + for (SpecializationData sourceSpecialization : node.getSpecializations()) { + if (sourceSpecialization.getExceptions() != null) { + for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { + for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { + if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { + throwsData.addError("Duplicate exception type."); + } + } + } + } + } + } + private void verifyConstructors(NodeData nodeData) { if (!nodeData.needsRewrites(context)) { // no specialization constructor is needed if the node never rewrites. @@ -1152,104 +1170,6 @@ return constructor.getParameters().size() == 1 && Utils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection()); } - private static boolean verifySpecializationParameters(NodeData nodeData) { - boolean valid = true; - int args = -1; - for (SpecializationData specializationData : nodeData.getSpecializations()) { - int signatureArgs = 0; - for (ActualParameter param : specializationData.getParameters()) { - if (param.getSpecification().isSignature()) { - signatureArgs++; - } - } - if (args != -1 && args != signatureArgs) { - valid = false; - break; - } - args = signatureArgs; - } - if (!valid) { - for (SpecializationData specialization : nodeData.getSpecializations()) { - specialization.addError("All specializations must have the same number of arguments."); - } - } - return valid; - } - - private static void verifySpecializationOrder(NodeData node) { - List<SpecializationData> specializations = node.getSpecializations(); - for (int i = 0; i < specializations.size(); i++) { - SpecializationData m1 = specializations.get(i); - for (int j = i + 1; j < specializations.size(); j++) { - SpecializationData m2 = specializations.get(j); - int inferredOrder = m1.compareBySignature(m2); - - if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { - int specOrder = m1.getOrder() - m2.getOrder(); - if (specOrder == 0) { - m1.addError("Order value %d used multiple times", m1.getOrder()); - m2.addError("Order value %d used multiple times", m1.getOrder()); - return; - } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { - m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - return; - } - } else if (inferredOrder == 0) { - SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); - m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); - return; - } - } - } - } - - private static void verifySpecializationThrows(NodeData node) { - Map<String, SpecializationData> specializationMap = new HashMap<>(); - for (SpecializationData spec : node.getSpecializations()) { - specializationMap.put(spec.getMethodName(), spec); - } - for (SpecializationData sourceSpecialization : node.getSpecializations()) { - if (sourceSpecialization.getExceptions() != null) { - for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { - for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { - if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { - throwsData.addError("Duplicate exception type."); - } - } - } - } - } - } - - private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) { - for (int i = 0; i < methods.size(); i++) { - TemplateMethod m1 = methods.get(i); - if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { - m1.addError("Naming convention: method name must start with '%s'.", prefix); - } - } - } - - private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) { - Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>(); - for (ExecutableTypeData type : executableTypes) { - int evaluatedCount = type.getEvaluatedCount(); - - List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount); - if (types == null) { - types = new ArrayList<>(); - groupedTypes.put(evaluatedCount, types); - } - types.add(type); - } - - for (List<ExecutableTypeData> types : groupedTypes.values()) { - Collections.sort(types); - } - return groupedTypes; - } - private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) { for (Element element : elements) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation); @@ -1289,61 +1209,13 @@ return null; } - private boolean isGenericShortCutMethod(ShortCircuitData method) { - for (ActualParameter parameter : method.getParameters()) { - NodeExecutionData execution = parameter.getSpecification().getExecution(); - if (execution == null) { - continue; - } - ExecutableTypeData found = null; - List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context); - for (ExecutableTypeData executable : executableElements) { - if (executable.getType().equalsType(parameter.getTypeSystemType())) { - found = executable; - break; - } - } - if (found == null) { - return false; + private static List<TypeElement> collectSuperClasses(List<TypeElement> collection, TypeElement element) { + if (element != null) { + collection.add(element); + if (element.getSuperclass() != null) { + collectSuperClasses(collection, Utils.fromTypeMirror(element.getSuperclass())); } } - return true; - } - - private static Map<String, List<ShortCircuitData>> groupShortCircuits(List<ShortCircuitData> shortCircuits) { - Map<String, List<ShortCircuitData>> group = new HashMap<>(); - for (ShortCircuitData shortCircuit : shortCircuits) { - List<ShortCircuitData> circuits = group.get(shortCircuit.getValueName()); - if (circuits == null) { - circuits = new ArrayList<>(); - group.put(shortCircuit.getValueName(), circuits); - } - circuits.add(shortCircuit); - } - return group; - } - - private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) { - SortedMap<String, List<M>> grouped = new TreeMap<>(); - for (M m : methods) { - List<M> list = grouped.get(m.getId()); - if (list == null) { - list = new ArrayList<>(); - grouped.put(m.getId(), list); - } - list.add(m); - } - return grouped; - } - - private static List<TypeElement> findSuperClasses(List<TypeElement> collection, TypeElement element) { - if (element.getSuperclass() != null) { - TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass()); - if (superElement != null) { - findSuperClasses(collection, superElement); - } - } - collection.add(element); return collection; }