changeset 10591:3cc5fb59916e

Truffle-DSL: Renamed @NodeClass to @NodeContainer. splitByMethodName is not an option anymore and is always enabled if a @NodeContainer is used.
author Christian Humer <christian.humer@gmail.com>
date Fri, 28 Jun 2013 12:19:51 +0200
parents 6eb8d63cea34
children 99b58803d6d9
files graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/NodeContainerTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeContainer.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java
diffstat 9 files changed, 695 insertions(+), 698 deletions(-) [+]
line wrap: on
line diff
--- 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<BuiltinNode> 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<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
-        executeWith(node, 42, new Str(" is the number."));
-    }
-
-    @Test
-    public void testSubstrSpecialized() {
-        TestRootNode<BuiltinNode> 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<BuiltinNode> 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<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
-        executeWith(node, new Object(), "5", "7");
-    }
-
-    @Test
-    public void testLength() {
-        TestRootNode<BuiltinNode> 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<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
-        executeWith(node, new Object());
-    }
-
-    @Test
-    public void testAccessContext() {
-        Context context = new Context();
-        TestRootNode<BuiltinNode> 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 {
-
-    }
-
-}
--- /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<BuiltinNode> 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<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
+        executeWith(node, 42, new Str(" is the number."));
+    }
+
+    @Test
+    public void testSubstrSpecialized() {
+        TestRootNode<BuiltinNode> 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<BuiltinNode> 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<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
+        executeWith(node, new Object(), "5", "7");
+    }
+
+    @Test
+    public void testLength() {
+        TestRootNode<BuiltinNode> 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<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
+        executeWith(node, new Object());
+    }
+
+    @Test
+    public void testAccessContext() {
+        Context context = new Context();
+        TestRootNode<BuiltinNode> 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 {
+
+    }
+
+}
--- 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.*;
 
 /**
--- 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 @@
  *
  * <ul>
  * <li>What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}</li>
- * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.BuiltinTest}</li>
+ * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.NodeContainerTest}</li>
  * </ul>
  * </p>
  *
--- 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
--- 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<? extends Node> value() default InheritNode.class;
-
-    boolean splitByMethodName() default false;
-
-}
--- /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<? extends Node> value();
+
+}
--- 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<NodeData> declaredNodes = new ArrayList<>();
-    private boolean splitByMethodName;
+    private boolean nodeContainer;
 
     private TypeSystemData typeSystem;
     private List<NodeChildData> 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
--- 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<NodeData> {
 
     public static final List<Class<? extends Annotation>> 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<String, NodeData> parsedNodes;
 
@@ -90,6 +89,16 @@
         return true;
     }
 
+    @Override
+    public Class<? extends Annotation> getAnnotationType() {
+        return null;
+    }
+
+    @Override
+    public List<Class<? extends Annotation>> getTypeDelegatedAnnotationTypes() {
+        return ANNOTATIONS;
+    }
+
     private NodeData resolveNode(TypeElement rootType) {
         String typeName = Utils.getQualifiedName(rootType);
         if (parsedNodes.containsKey(typeName)) {
@@ -133,7 +142,7 @@
         List<TypeElement> lookupTypes = findSuperClasses(new ArrayList<TypeElement>(), 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<Element> elementSet = new HashSet<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
+        Elements elementUtil = context.getEnvironment().getElementUtils();
+        Set<Element> 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<TypeElement> nodeLookupTypes = findSuperClasses(new ArrayList<TypeElement>(), Utils.fromTypeMirror(nodeType));
             Collections.reverse(nodeLookupTypes);
@@ -186,7 +196,7 @@
 
         List<NodeData> 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<SpecializationListenerData>());
             node.setSpecializations(new ArrayList<SpecializationData>());
@@ -208,6 +218,226 @@
         }
     }
 
+    private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> 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<String> 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<String> 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<NodeFieldData> parseFields(List<? extends Element> elements) {
+        List<NodeFieldData> 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<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);
+            if (mirror != null) {
+                shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
+            }
+        }
+        Map<String, TypeMirror> castNodeTypes = new HashMap<>();
+        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
+            AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class);
+            if (mirror != null) {
+                List<String> children = (Utils.getAnnotationValueList(String.class, mirror, "value"));
+                if (children != null) {
+                    for (String child : children) {
+                        castNodeTypes.put(child, method.getReturnType());
+                    }
+                }
+            }
+        }
+
+        List<NodeChildData> parsedChildren = new ArrayList<>();
+        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();
+            if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) {
+                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) {
+                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<NodeChildData> filteredChildren = new ArrayList<>();
+        Set<String> 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<String> executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
+            AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
+            List<NodeChildData> 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<ExecutableTypeData> 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<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));
+
+        List<SpecializationData> allSpecializations = new ArrayList<>();
+        allSpecializations.addAll(generics);
+        allSpecializations.addAll(specializations);
+
+        node.setSpecializations(allSpecializations);
+    }
+
     private static List<NodeData> splitNodeData(NodeData node) {
         SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations());
         SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners());
@@ -252,33 +482,6 @@
         return splitted;
     }
 
-    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 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));
-
-        List<SpecializationData> allSpecializations = new ArrayList<>();
-        allSpecializations.addAll(generics);
-        allSpecializations.addAll(specializations);
-
-        node.setSpecializations(allSpecializations);
-    }
-
     private void finalizeSpecializations(List<Element> elements, final NodeData node) {
         List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
 
@@ -394,6 +597,87 @@
         }
     }
 
+    private void assignShortCircuitsToSpecializations(NodeData node) {
+        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
+
+        boolean valid = true;
+        for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) {
+            String valueName = field.getName();
+            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(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<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
+
+            for (int i = 0; i < fields.length; i++) {
+                List<ShortCircuitData> 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<Element> elements, SpecializationData specialization) {
         if (specialization.getGuardDefinitions().isEmpty()) {
             specialization.setGuards(Collections.<GuardData> emptyList());
@@ -546,83 +830,12 @@
         verifySpecializationThrows(nodeData);
     }
 
-    private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> 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<String> 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<String> 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<? extends Element> originalElements) {
@@ -691,361 +904,28 @@
         nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
-    private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
-        Map<Integer, List<ExecutableTypeData>> groupedTypes = new HashMap<>();
-        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);
-            if (mirror != null) {
-                return mirror;
-            }
-        }
-        return null;
-    }
-
-    private static List<NodeFieldData> parseFields(List<? extends Element> elements) {
-        List<NodeFieldData> 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<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);
-            if (mirror != null) {
-                shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
-            }
-        }
-        Map<String, TypeMirror> castNodeTypes = new HashMap<>();
-        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
-            AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class);
-            if (mirror != null) {
-                List<String> 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<NodeChildData> parsedChildren = new ArrayList<>();
-        List<TypeElement> 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<AnnotationMirror> 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<NodeChildData> filteredChildren = new ArrayList<>();
-        Set<String> 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<String> executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
-            AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
-            List<NodeChildData> 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<ExecutableTypeData> 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<? extends Element> 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<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
-
-        boolean valid = true;
-        for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) {
-            String valueName = field.getName();
-            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(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<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
-
-            for (int i = 0; i < fields.length; i++) {
-                List<ShortCircuitData> 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<? 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 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<ExecutableTypeData> 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<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 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;
+        return valid;
     }
 
     private static void verifySpecializationOrder(NodeData node) {
@@ -1094,14 +974,129 @@
         }
     }
 
-    @Override
-    public Class<? extends Annotation> getAnnotationType() {
+    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 HashMap<>();
+        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);
+            if (mirror != null) {
+                return mirror;
+            }
+        }
         return null;
     }
 
-    @Override
-    public List<Class<? extends Annotation>> 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<? extends Element> 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<ExecutableTypeData> 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<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;
     }
 
 }