# HG changeset patch # User Christian Humer # Date 1372414791 -7200 # Node ID 3cc5fb59916ebaaa592ebb84dba1b9611c83eaaa # Parent 6eb8d63cea347fac2fa18a5df26897c741dbc654 Truffle-DSL: Renamed @NodeClass to @NodeContainer. splitByMethodName is not an option anymore and is always enabled if a @NodeContainer is used. diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Wed Jun 26 17:21:59 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.codegen.test; - -import static com.oracle.truffle.api.codegen.test.TestHelper.*; -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrAccessContextFactory; -import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrConcatFactory; -import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrLengthFactory; -import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrSubstrFactory; -import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; -import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; - -public class BuiltinTest { - - @Test - public void testConcat() { - TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); - Str str1 = new Str("42"); - Str str2 = new Str(" is the number."); - assertEquals(str1.concat(str2), executeWith(node, str1, str2)); - } - - @Test(expected = UnsupportedOperationException.class) - public void testConcatUnsupported() { - TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); - executeWith(node, 42, new Str(" is the number.")); - } - - @Test - public void testSubstrSpecialized() { - TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); - Str str = new Str("test 42"); - - assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7)); - } - - @Test - public void testSubstrGeneric() { - TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); - Str str = new Str("test 42"); - - assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7")); - } - - @Test(expected = UnsupportedOperationException.class) - public void testSubstrUnsupported() { - TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); - executeWith(node, new Object(), "5", "7"); - } - - @Test - public void testLength() { - TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); - Str testStr = new Str("test 42"); - assertEquals(testStr.length(), executeWith(node, testStr)); - } - - @Test(expected = UnsupportedOperationException.class) - public void testLengthUnsupported() { - TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); - executeWith(node, new Object()); - } - - @Test - public void testAccessContext() { - Context context = new Context(); - TestRootNode node = createRoot(StrAccessContextFactory.getInstance(), context); - // accessible by node - assertSame(context, node.getNode().getContext()); - // accessible by execution - assertSame(context, executeWith(node)); - } - - @NodeClass(value = BuiltinNode.class, splitByMethodName = true) - static class Str { - - private final String internal; - - public Str(String internal) { - this.internal = internal; - } - - @Specialization - Str concat(Str s1) { - return new Str(internal + s1.internal); - } - - @Specialization - Str substr(int beginIndex, int endIndex) { - return new Str(internal.substring(beginIndex, endIndex)); - } - - @Generic - static Str substr(Object thisValue, Object beginIndex, Object endIndex) { - if (!(thisValue instanceof Str)) { - throw new UnsupportedOperationException(); - } - return ((Str) thisValue).substr(convertInt(beginIndex), convertInt(endIndex)); - } - - @Specialization - int length() { - return internal.length(); - } - - @Specialization - static Object accessContext(Context context) { - return context; - } - - static int convertInt(Object value) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } else if (value instanceof String) { - return Integer.parseInt((String) value); - } - throw new RuntimeException("Invalid datatype"); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Str) { - return internal.equals(((Str) obj).internal); - } - return super.equals(obj); - } - - @Override - public String toString() { - return internal; - } - - @Override - public int hashCode() { - return internal.hashCode(); - } - } - - @NodeChild(value = "children", type = ValueNode[].class) - abstract static class BuiltinNode extends ValueNode { - - protected final Context context; - - public BuiltinNode(BuiltinNode node) { - this(node.context); - } - - public BuiltinNode(Context context) { - this.context = context; - } - - public Context getContext() { - return context; - } - } - - static class Context { - - } - -} diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/NodeContainerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/NodeContainerTest.java Fri Jun 28 12:19:51 2013 +0200 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen.test; + +import static com.oracle.truffle.api.codegen.test.TestHelper.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.NodeContainerTestFactory.StrFactory.StrAccessContextFactory; +import com.oracle.truffle.api.codegen.test.NodeContainerTestFactory.StrFactory.StrConcatFactory; +import com.oracle.truffle.api.codegen.test.NodeContainerTestFactory.StrFactory.StrLengthFactory; +import com.oracle.truffle.api.codegen.test.NodeContainerTestFactory.StrFactory.StrSubstrFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class NodeContainerTest { + + @Test + public void testConcat() { + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); + Str str1 = new Str("42"); + Str str2 = new Str(" is the number."); + assertEquals(str1.concat(str2), executeWith(node, str1, str2)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConcatUnsupported() { + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); + executeWith(node, 42, new Str(" is the number.")); + } + + @Test + public void testSubstrSpecialized() { + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); + Str str = new Str("test 42"); + + assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7)); + } + + @Test + public void testSubstrGeneric() { + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); + Str str = new Str("test 42"); + + assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7")); + } + + @Test(expected = UnsupportedOperationException.class) + public void testSubstrUnsupported() { + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); + executeWith(node, new Object(), "5", "7"); + } + + @Test + public void testLength() { + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); + Str testStr = new Str("test 42"); + assertEquals(testStr.length(), executeWith(node, testStr)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testLengthUnsupported() { + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); + executeWith(node, new Object()); + } + + @Test + public void testAccessContext() { + Context context = new Context(); + TestRootNode node = createRoot(StrAccessContextFactory.getInstance(), context); + // accessible by node + assertSame(context, node.getNode().getContext()); + // accessible by execution + assertSame(context, executeWith(node)); + } + + @NodeContainer(BuiltinNode.class) + static class Str { + + private final String internal; + + public Str(String internal) { + this.internal = internal; + } + + @Specialization + Str concat(Str s1) { + return new Str(internal + s1.internal); + } + + @Specialization + Str substr(int beginIndex, int endIndex) { + return new Str(internal.substring(beginIndex, endIndex)); + } + + @Generic + static Str substr(Object thisValue, Object beginIndex, Object endIndex) { + if (!(thisValue instanceof Str)) { + throw new UnsupportedOperationException(); + } + return ((Str) thisValue).substr(convertInt(beginIndex), convertInt(endIndex)); + } + + @Specialization + int length() { + return internal.length(); + } + + @Specialization + static Object accessContext(Context context) { + return context; + } + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Str) { + return internal.equals(((Str) obj).internal); + } + return super.equals(obj); + } + + @Override + public String toString() { + return internal; + } + + @Override + public int hashCode() { + return internal.hashCode(); + } + } + + @NodeChild(value = "children", type = ValueNode[].class) + abstract static class BuiltinNode extends ValueNode { + + protected final Context context; + + public BuiltinNode(BuiltinNode node) { + this(node.context); + } + + public BuiltinNode(Context context) { + this.context = context; + } + + public Context getContext() { + return context; + } + } + + static class Context { + + } + +} diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Wed Jun 26 17:21:59 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Fri Jun 28 12:19:51 2013 +0200 @@ -26,7 +26,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.test.BuiltinTest.*; +import com.oracle.truffle.api.codegen.test.NodeContainerTest.*; import com.oracle.truffle.api.codegen.test.TypeSystemTest.*; /** diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Wed Jun 26 17:21:59 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Fri Jun 28 12:19:51 2013 +0200 @@ -41,7 +41,7 @@ * *
    *
  • What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}
  • - *
  • How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.BuiltinTest}
  • + *
  • How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.NodeContainerTest}
  • *
*

* diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Wed Jun 26 17:21:59 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Fri Jun 28 12:19:51 2013 +0200 @@ -36,7 +36,7 @@ String value() default ""; - Class type() default NodeClass.InheritNode.class; + Class type() default Node.class; /** * The {@link #executeWith()} property allows a node to pass the result of one child's diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java Wed Jun 26 17:21:59 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.codegen; - -import java.lang.annotation.*; - -import com.oracle.truffle.api.nodes.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.TYPE}) -public @interface NodeClass { - - public static final class InheritNode extends Node { - } - - Class value() default InheritNode.class; - - boolean splitByMethodName() default false; - -} diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeContainer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeContainer.java Fri Jun 28 12:19:51 2013 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * A node container can be used to enable Truffle-DSL in classes which do not extend {@link Node}. + * Compared to normal {@link Node} implementation the nodes are not identified by a class but by + * their method name. There are cases were method signatures are matching exactly but should be in + * the same {@link Node}. In this case use {@link NodeId} to disambiguate such cases. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeContainer { + + /** The node class to use as base class for {@link Node} definitions grouped by method names. */ + Class value(); + +} diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Jun 26 17:21:59 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Fri Jun 28 12:19:51 2013 +0200 @@ -37,7 +37,7 @@ private final String nodeId; private NodeData declaringNode; private List declaredNodes = new ArrayList<>(); - private boolean splitByMethodName; + private boolean nodeContainer; private TypeSystemData typeSystem; private List children; @@ -91,8 +91,8 @@ return shortName; } - public boolean isSplitByMethodName() { - return splitByMethodName; + public boolean isNodeContainer() { + return nodeContainer; } void setTypeSystem(TypeSystemData typeSystem) { @@ -107,8 +107,8 @@ return fields; } - void setSplitByMethodName(boolean splitByMethodName) { - this.splitByMethodName = splitByMethodName; + void setNodeContainer(boolean splitByMethodName) { + this.nodeContainer = splitByMethodName; } @Override diff -r 6eb8d63cea34 -r 3cc5fb59916e graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Jun 26 17:21:59 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Fri Jun 28 12:19:51 2013 +0200 @@ -31,7 +31,6 @@ import javax.tools.Diagnostic.Kind; import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.NodeClass.InheritNode; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality; @@ -42,7 +41,7 @@ public class NodeParser extends TemplateParser { public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, - NodeClass.class, NodeChild.class, NodeChildren.class, NodeId.class); + NodeContainer.class, NodeChild.class, NodeChildren.class, NodeId.class); private Map parsedNodes; @@ -90,6 +89,16 @@ return true; } + @Override + public Class getAnnotationType() { + return null; + } + + @Override + public List> getTypeDelegatedAnnotationTypes() { + return ANNOTATIONS; + } + private NodeData resolveNode(TypeElement rootType) { String typeName = Utils.getQualifiedName(rootType); if (parsedNodes.containsKey(typeName)) { @@ -133,7 +142,7 @@ List lookupTypes = findSuperClasses(new ArrayList(), templateType); Collections.reverse(lookupTypes); - AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class); + AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeContainer.class); TypeMirror nodeType = null; if (Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) { nodeType = templateType.asType(); @@ -152,9 +161,10 @@ } } - Set elementSet = new HashSet<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); + Elements elementUtil = context.getEnvironment().getElementUtils(); + Set elementSet = new HashSet<>(elementUtil.getAllMembers(templateType)); if (!Utils.typeEquals(templateType.asType(), nodeType)) { - elementSet.addAll(context.getEnvironment().getElementUtils().getAllMembers(Utils.fromTypeMirror(nodeType))); + elementSet.addAll(elementUtil.getAllMembers(Utils.fromTypeMirror(nodeType))); List nodeLookupTypes = findSuperClasses(new ArrayList(), Utils.fromTypeMirror(nodeType)); Collections.reverse(nodeLookupTypes); @@ -186,7 +196,7 @@ List nodes; - if (node.isSplitByMethodName()) { + if (node.isNodeContainer()) { nodes = splitNodeData(node); } else { nodes = new ArrayList<>(); @@ -198,7 +208,7 @@ verifyNode(splittedNode, elements); } - if (node.isSplitByMethodName()) { + if (node.isNodeContainer()) { node.setDeclaredNodes(nodes); node.setSpecializationListeners(new ArrayList()); node.setSpecializations(new ArrayList()); @@ -208,6 +218,226 @@ } } + private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List elements, List lookupTypes) { + NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); + + AnnotationMirror typeSystemMirror = findFirstAnnotation(lookupTypes, TypeSystemReference.class); + if (typeSystemMirror == null) { + nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType)); + return nodeData; + } + + TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); + if (typeSystem == null) { + nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSytemType)); + return nodeData; + } + + List assumptionsList = new ArrayList<>(); + + for (int i = lookupTypes.size() - 1; i >= 0; i--) { + TypeElement type = lookupTypes.get(i); + AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); + if (assumptions != null) { + List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); + for (String string : assumptionStrings) { + if (assumptionsList.contains(string)) { + assumptionsList.remove(string); + } + assumptionsList.add(string); + } + } + } + AnnotationMirror nodeInfoMirror = findFirstAnnotation(lookupTypes, NodeInfo.class); + if (nodeInfoMirror != null) { + nodeData.setShortName(Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName")); + } + + nodeData.setAssumptions(new ArrayList<>(assumptionsList)); + nodeData.setNodeType(nodeType); + AnnotationMirror nodeContainer = findFirstAnnotation(lookupTypes, NodeContainer.class); + nodeData.setNodeContainer(nodeContainer != null); + nodeData.setTypeSystem(typeSystem); + nodeData.setFields(parseFields(elements)); + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); + // parseChildren invokes cyclic parsing. + nodeData.setChildren(parseChildren(elements, lookupTypes)); + nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); + + return nodeData; + } + + private static List parseFields(List elements) { + List fields = new ArrayList<>(); + for (VariableElement field : ElementFilter.fieldsIn(elements)) { + if (field.getModifiers().contains(Modifier.STATIC)) { + continue; + } + if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { + fields.add(new NodeFieldData(field)); + } + } + return fields; + } + + private List parseChildren(List elements, final List typeHierarchy) { + Set shortCircuits = new HashSet<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); + if (mirror != null) { + shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); + } + } + Map castNodeTypes = new HashMap<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class); + if (mirror != null) { + List children = (Utils.getAnnotationValueList(String.class, mirror, "value")); + if (children != null) { + for (String child : children) { + castNodeTypes.put(child, method.getReturnType()); + } + } + } + } + + List parsedChildren = new ArrayList<>(); + List 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(); + if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) { + nodeClassType = null; + } + + if (nodeClassMirror != null) { + nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType); + } + + List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); + int index = 0; + for (AnnotationMirror childMirror : children) { + String name = Utils.getAnnotationValue(String.class, childMirror, "value"); + if (name.equals("")) { + name = "child" + index; + } + + Cardinality cardinality = Cardinality.ONE; + + TypeMirror childType = inheritType(childMirror, "type", nodeClassType); + if (childType.getKind() == TypeKind.ARRAY) { + cardinality = Cardinality.MANY; + } + + TypeMirror originalChildType = childType; + TypeMirror castNodeType = castNodeTypes.get(name); + if (castNodeType != null) { + childType = castNodeType; + } + + Element getter = findGetter(elements, name, childType); + + ExecutionKind kind = ExecutionKind.DEFAULT; + if (shortCircuits.contains(name)) { + kind = ExecutionKind.SHORT_CIRCUIT; + } + + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality, kind); + + parsedChildren.add(nodeChild); + + verifyNodeChild(nodeChild); + if (nodeChild.hasErrors()) { + continue; + } + + NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(childType)); + nodeChild.setNode(fieldNodeData); + if (fieldNodeData == null) { + nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); + } + + } + index++; + } + + List filteredChildren = new ArrayList<>(); + Set encounteredNames = new HashSet<>(); + for (int i = parsedChildren.size() - 1; i >= 0; i--) { + NodeChildData child = parsedChildren.get(i); + if (!encounteredNames.contains(child.getName())) { + filteredChildren.add(0, child); + encounteredNames.add(child.getName()); + } + } + + for (NodeChildData child : filteredChildren) { + List executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); + AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); + List executeWith = new ArrayList<>(); + for (String executeWithString : executeWithStrings) { + + if (child.getName().equals(executeWithString)) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); + continue; + } + + NodeChildData found = null; + boolean before = true; + for (NodeChildData resolveChild : filteredChildren) { + if (resolveChild == child) { + before = false; + continue; + } + if (resolveChild.getName().equals(executeWithString)) { + found = resolveChild; + break; + } + } + + if (found == null) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); + continue; + } else if (!before) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, + executeWithString); + continue; + } + executeWith.add(found); + } + child.setExecuteWith(executeWith); + if (child.getNodeData() == null) { + continue; + } + + List types = child.findGenericExecutableTypes(context); + if (types.isEmpty()) { + child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType())); + continue; + } + } + + return filteredChildren; + } + + private void parseMethods(final NodeData node, List elements) { + node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); + node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); + List generics = new GenericParser(context, node).parse(elements); + List specializations = new SpecializationMethodParser(context, node).parse(elements); + node.setCasts(new CreateCastParser(context, node).parse(elements)); + + List allSpecializations = new ArrayList<>(); + allSpecializations.addAll(generics); + allSpecializations.addAll(specializations); + + node.setSpecializations(allSpecializations); + } + private static List splitNodeData(NodeData node) { SortedMap> groupedSpecializations = groupByNodeId(node.getSpecializations()); SortedMap> groupedListeners = groupByNodeId(node.getSpecializationListeners()); @@ -252,33 +482,6 @@ return splitted; } - private static SortedMap> groupByNodeId(List methods) { - SortedMap> grouped = new TreeMap<>(); - for (M m : methods) { - List list = grouped.get(m.getId()); - if (list == null) { - list = new ArrayList<>(); - grouped.put(m.getId(), list); - } - list.add(m); - } - return grouped; - } - - private void parseMethods(final NodeData node, List elements) { - node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); - node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); - List generics = new GenericParser(context, node).parse(elements); - List specializations = new SpecializationMethodParser(context, node).parse(elements); - node.setCasts(new CreateCastParser(context, node).parse(elements)); - - List allSpecializations = new ArrayList<>(); - allSpecializations.addAll(generics); - allSpecializations.addAll(specializations); - - node.setSpecializations(allSpecializations); - } - private void finalizeSpecializations(List elements, final NodeData node) { List specializations = new ArrayList<>(node.getSpecializations()); @@ -394,6 +597,87 @@ } } + private void assignShortCircuitsToSpecializations(NodeData node) { + Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); + + boolean valid = true; + for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) { + String valueName = field.getName(); + List 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(node, 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; + } + + NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT); + for (SpecializationData specialization : node.getSpecializations()) { + List assignedShortCuts = new ArrayList<>(fields.length); + + for (int i = 0; i < fields.length; i++) { + List availableShortCuts = groupedShortCircuits.get(fields[i].getName()); + + 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 elements, SpecializationData specialization) { if (specialization.getGuardDefinitions().isEmpty()) { specialization.setGuards(Collections. emptyList()); @@ -546,83 +830,12 @@ verifySpecializationThrows(nodeData); } - private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List elements, List lookupTypes) { - NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); - - AnnotationMirror typeSystemMirror = findFirstAnnotation(lookupTypes, TypeSystemReference.class); - if (typeSystemMirror == null) { - nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType)); - return nodeData; - } - - TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); - if (typeSystem == null) { - nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSytemType)); - return nodeData; - } - - boolean splitByMethodName = false; - AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class); - if (nodeClass != null) { - splitByMethodName = Utils.getAnnotationValue(Boolean.class, nodeClass, "splitByMethodName"); - } - - List assumptionsList = new ArrayList<>(); - - for (int i = lookupTypes.size() - 1; i >= 0; i--) { - TypeElement type = lookupTypes.get(i); - AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); - if (assumptions != null) { - List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); - for (String string : assumptionStrings) { - if (assumptionsList.contains(string)) { - assumptionsList.remove(string); - } - assumptionsList.add(string); - } - } + private static void verifyNodeChild(NodeChildData nodeChild) { + if (nodeChild.getNodeType() == null) { + nodeChild.addError("No valid node type could be resoleved."); } - AnnotationMirror nodeInfoMirror = findFirstAnnotation(lookupTypes, NodeInfo.class); - if (nodeInfoMirror != null) { - nodeData.setShortName(Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName")); - } - - nodeData.setAssumptions(new ArrayList<>(assumptionsList)); - nodeData.setNodeType(nodeType); - nodeData.setSplitByMethodName(splitByMethodName); - nodeData.setTypeSystem(typeSystem); - nodeData.setFields(parseFields(elements)); - parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - // parseChildren invokes cyclic parsing. - nodeData.setChildren(parseChildren(elements, lookupTypes)); - nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - - return nodeData; - } - - 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; + // FIXME verify node child + // FIXME verify node type set } private static void verifyMissingAbstractMethods(NodeData nodeData, List originalElements) { @@ -691,361 +904,28 @@ nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); } - private static Map> groupExecutableTypes(List executableTypes) { - Map> groupedTypes = new HashMap<>(); - for (ExecutableTypeData type : executableTypes) { - int evaluatedCount = type.getEvaluatedCount(); - - List types = groupedTypes.get(evaluatedCount); - if (types == null) { - types = new ArrayList<>(); - groupedTypes.put(evaluatedCount, types); - } - types.add(type); - } - - for (List types : groupedTypes.values()) { - Collections.sort(types); - } - return groupedTypes; - } - - private AnnotationMirror findFirstAnnotation(List elements, Class annotation) { - for (Element element : elements) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation); - if (mirror != null) { - return mirror; - } - } - return null; - } - - private static List parseFields(List elements) { - List fields = new ArrayList<>(); - for (VariableElement field : ElementFilter.fieldsIn(elements)) { - if (field.getModifiers().contains(Modifier.STATIC)) { - continue; - } - if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { - fields.add(new NodeFieldData(field)); - } - } - return fields; - } - - private List parseChildren(List elements, final List typeHierarchy) { - Set shortCircuits = new HashSet<>(); - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); - if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); - } - } - Map castNodeTypes = new HashMap<>(); - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class); - if (mirror != null) { - List children = (Utils.getAnnotationValueList(String.class, mirror, "value")); - if (children != null) { - for (String child : children) { - castNodeTypes.put(child, method.getReturnType()); - } + 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++; } } - } - - List parsedChildren = new ArrayList<>(); - List typeHierarchyReversed = new ArrayList<>(typeHierarchy); - Collections.reverse(typeHierarchyReversed); - for (TypeElement type : typeHierarchyReversed) { - AnnotationMirror nodeClassMirror = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class); - AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class); - - TypeMirror nodeClassType = type.getSuperclass(); - if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) { - nodeClassType = null; - } - - if (nodeClassMirror != null) { - nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType); + if (args != -1 && args != signatureArgs) { + valid = false; + break; } - - List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); - int index = 0; - for (AnnotationMirror childMirror : children) { - String name = Utils.getAnnotationValue(String.class, childMirror, "value"); - if (name.equals("")) { - name = "child" + index; - } - - Cardinality cardinality = Cardinality.ONE; - - TypeMirror childType = inheritType(childMirror, "type", nodeClassType); - if (childType.getKind() == TypeKind.ARRAY) { - cardinality = Cardinality.MANY; - } - - TypeMirror originalChildType = childType; - TypeMirror castNodeType = castNodeTypes.get(name); - if (castNodeType != null) { - childType = castNodeType; - } - - Element getter = findGetter(elements, name, childType); - - ExecutionKind kind = ExecutionKind.DEFAULT; - if (shortCircuits.contains(name)) { - kind = ExecutionKind.SHORT_CIRCUIT; - } - - NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality, kind); - - parsedChildren.add(nodeChild); - - verifyNodeChild(nodeChild); - if (nodeChild.hasErrors()) { - continue; - } - - NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(childType)); - nodeChild.setNode(fieldNodeData); - if (fieldNodeData == null) { - nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); - } - - } - index++; + args = signatureArgs; } - - List filteredChildren = new ArrayList<>(); - Set encounteredNames = new HashSet<>(); - for (int i = parsedChildren.size() - 1; i >= 0; i--) { - NodeChildData child = parsedChildren.get(i); - if (!encounteredNames.contains(child.getName())) { - filteredChildren.add(0, child); - encounteredNames.add(child.getName()); + if (!valid) { + for (SpecializationData specialization : nodeData.getSpecializations()) { + specialization.addError("All specializations must have the same number of arguments."); } } - - for (NodeChildData child : filteredChildren) { - List executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); - AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); - List executeWith = new ArrayList<>(); - for (String executeWithString : executeWithStrings) { - - if (child.getName().equals(executeWithString)) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); - continue; - } - - NodeChildData found = null; - boolean before = true; - for (NodeChildData resolveChild : filteredChildren) { - if (resolveChild == child) { - before = false; - continue; - } - if (resolveChild.getName().equals(executeWithString)) { - found = resolveChild; - break; - } - } - - if (found == null) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); - continue; - } else if (!before) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, - executeWithString); - continue; - } - executeWith.add(found); - } - child.setExecuteWith(executeWith); - if (child.getNodeData() == null) { - continue; - } - - List types = child.findGenericExecutableTypes(context); - if (types.isEmpty()) { - child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType())); - continue; - } - } - - return filteredChildren; - } - - private static void verifyNodeChild(NodeChildData nodeChild) { - if (nodeChild.getNodeType() == null) { - nodeChild.addError("No valid node type could be resoleved."); - } - // FIXME verify node child - // FIXME verify node type set - } - - private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) { - TypeMirror inhertNodeType = context.getType(InheritNode.class); - TypeMirror value = Utils.getAnnotationValue(TypeMirror.class, annotation, valueName); - if (Utils.typeEquals(inhertNodeType, value)) { - return parentType; - } else { - return value; - } - } - - private Element findGetter(List elements, String variableName, TypeMirror type) { - if (type == null) { - return null; - } - String methodName; - if (Utils.typeEquals(type, context.getType(boolean.class))) { - methodName = "is" + Utils.firstLetterUpperCase(variableName); - } else { - methodName = "get" + Utils.firstLetterUpperCase(variableName); - } - - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.isAssignable(context, type, method.getReturnType())) { - return method; - } - } - return null; - } - - private void assignShortCircuitsToSpecializations(NodeData node) { - Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); - - boolean valid = true; - for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) { - String valueName = field.getName(); - List 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(node, 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; - } - - NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT); - for (SpecializationData specialization : node.getSpecializations()) { - List assignedShortCuts = new ArrayList<>(fields.length); - - for (int i = 0; i < fields.length; i++) { - List availableShortCuts = groupedShortCircuits.get(fields[i].getName()); - - 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 static void verifyNamingConvention(List 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 boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { - for (ActualParameter parameter : method.getParameters()) { - NodeChildData field = node.findChild(parameter.getSpecification().getName()); - if (field == null) { - continue; - } - ExecutableTypeData found = null; - List executableElements = field.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> groupShortCircuits(List shortCircuits) { - Map> group = new HashMap<>(); - for (ShortCircuitData shortCircuit : shortCircuits) { - List circuits = group.get(shortCircuit.getValueName()); - if (circuits == null) { - circuits = new ArrayList<>(); - group.put(shortCircuit.getValueName(), circuits); - } - circuits.add(shortCircuit); - } - return group; - } - - private static List findSuperClasses(List collection, TypeElement element) { - if (element.getSuperclass() != null) { - TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass()); - if (superElement != null) { - findSuperClasses(collection, superElement); - } - } - collection.add(element); - return collection; + return valid; } private static void verifySpecializationOrder(NodeData node) { @@ -1094,14 +974,129 @@ } } - @Override - public Class getAnnotationType() { + private static void verifyNamingConvention(List 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> groupExecutableTypes(List executableTypes) { + Map> groupedTypes = new HashMap<>(); + for (ExecutableTypeData type : executableTypes) { + int evaluatedCount = type.getEvaluatedCount(); + + List types = groupedTypes.get(evaluatedCount); + if (types == null) { + types = new ArrayList<>(); + groupedTypes.put(evaluatedCount, types); + } + types.add(type); + } + + for (List types : groupedTypes.values()) { + Collections.sort(types); + } + return groupedTypes; + } + + private AnnotationMirror findFirstAnnotation(List elements, Class annotation) { + for (Element element : elements) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation); + if (mirror != null) { + return mirror; + } + } return null; } - @Override - public List> getTypeDelegatedAnnotationTypes() { - return ANNOTATIONS; + private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) { + TypeMirror inhertNodeType = context.getTruffleTypes().getNode(); + TypeMirror value = Utils.getAnnotationValue(TypeMirror.class, annotation, valueName); + if (Utils.typeEquals(inhertNodeType, value)) { + return parentType; + } else { + return value; + } + } + + private Element findGetter(List elements, String variableName, TypeMirror type) { + if (type == null) { + return null; + } + String methodName; + if (Utils.typeEquals(type, context.getType(boolean.class))) { + methodName = "is" + Utils.firstLetterUpperCase(variableName); + } else { + methodName = "get" + Utils.firstLetterUpperCase(variableName); + } + + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.isAssignable(context, type, method.getReturnType())) { + return method; + } + } + return null; + } + + private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { + for (ActualParameter parameter : method.getParameters()) { + NodeChildData field = node.findChild(parameter.getSpecification().getName()); + if (field == null) { + continue; + } + ExecutableTypeData found = null; + List executableElements = field.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> groupShortCircuits(List shortCircuits) { + Map> group = new HashMap<>(); + for (ShortCircuitData shortCircuit : shortCircuits) { + List circuits = group.get(shortCircuit.getValueName()); + if (circuits == null) { + circuits = new ArrayList<>(); + group.put(shortCircuit.getValueName(), circuits); + } + circuits.add(shortCircuit); + } + return group; + } + + private static SortedMap> groupByNodeId(List methods) { + SortedMap> grouped = new TreeMap<>(); + for (M m : methods) { + List list = grouped.get(m.getId()); + if (list == null) { + list = new ArrayList<>(); + grouped.put(m.getId(), list); + } + list.add(m); + } + return grouped; + } + + private static List findSuperClasses(List collection, TypeElement element) { + if (element.getSuperclass() != null) { + TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + findSuperClasses(collection, superElement); + } + } + collection.add(element); + return collection; } }