changeset 7886:3828c6119073

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 26 Feb 2013 11:55:00 +0100
parents 45bce3579308 (current diff) dbbdc0a30a16 (diff)
children d99bce9bbbb2
files
diffstat 22 files changed, 1457 insertions(+), 542 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Tue Feb 26 11:55:00 2013 +0100
@@ -758,7 +758,7 @@
                 if (blockChanged) {
                     block.localsLiveIn.clear();
                     block.localsLiveIn.or(block.localsLiveOut);
-                    block.localsLiveIn.xor(block.localsLiveKill);
+                    block.localsLiveIn.andNot(block.localsLiveKill);
                     block.localsLiveIn.or(block.localsLiveGen);
                     Debug.log("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.blockID, block.startBci, block.endBci, block.localsLiveIn, block.localsLiveOut, block.localsLiveGen,
                                     block.localsLiveKill);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java	Tue Feb 26 11:55:00 2013 +0100
@@ -0,0 +1,66 @@
+/*
+ * 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.util.*;
+
+/**
+ * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate
+ * generated node classes without using reflection.
+ */
+public interface NodeFactory<T> {
+
+    /**
+     * Instantiates the node using the arguments array. The arguments length and types must suffice
+     * one of the returned signatures in {@link #getNodeSignatures()}. If the arguments array does
+     * not suffice one of the node signatures an {@link IllegalArgumentException} is thrown.
+     * 
+     * @param arguments the argument values
+     * @return the instantiated node
+     * @throws IllegalArgumentException
+     */
+    T createNode(Object... arguments);
+
+    /**
+     * Instantiates a new specialized variant of the node. This is an optional method and throws an
+     * {@link UnsupportedOperationException} if not supported.
+     * 
+     * @param thisNode the current node
+     * @param specializionClasses
+     * @return the specialized node
+     */
+    T createNodeSpecialized(T thisNode, Class<?>... specializionClasses);
+
+    /**
+     * Returns the node class that will get created by {@link #createNode(Object...)}. The node
+     * class does not match exactly to the instantiated object but they are guaranteed to be
+     * assignable.
+     */
+    Class<T> getNodeClass();
+
+    /**
+     * Returns a list of signatures that can be used to invoke {@link #createNode(Object...)}.
+     */
+    List<List<Class<?>>> getNodeSignatures();
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Tue Feb 26 11:55:00 2013 +0100
@@ -28,6 +28,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.intrinsics.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.nodes.Node.Children;
@@ -44,6 +45,7 @@
     private final TypeMirror stableAnnotation;
     private final TypeMirror contentStableAnnotation;
     private final TypeMirror typeConversion;
+    private final TypeMirror truffleIntrinsics;
 
     private final List<String> errors = new ArrayList<>();
 
@@ -55,6 +57,7 @@
         stableAnnotation = getRequired(context, Child.class);
         contentStableAnnotation = getRequired(context, Children.class);
         typeConversion = getRequired(context, TypeConversion.class);
+        truffleIntrinsics = getRequired(context, TruffleIntrinsics.class);
     }
 
     public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) {
@@ -77,6 +80,10 @@
         return type;
     }
 
+    public TypeMirror getTruffleIntrinsics() {
+        return truffleIntrinsics;
+    }
+
     public TypeMirror getTypeConversion() {
         return typeConversion;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Feb 26 11:55:00 2013 +0100
@@ -47,6 +47,14 @@
         }
     }
 
+    public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) {
+        TypeMirror boxedType = primitiveType;
+        if (boxedType.getKind().isPrimitive()) {
+            boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType();
+        }
+        return boxedType;
+    }
+
     public static List<AnnotationMirror> collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element,
                     Class<? extends Annotation> annotationClass) {
         List<AnnotationMirror> result = Utils.getAnnotationValueList(markerAnnotation, elementName);
@@ -61,6 +69,42 @@
         return result;
     }
 
+    public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) {
+        if (types.length == 0) {
+            return context.getType(Object.class);
+        }
+        TypeMirror prev = types[0];
+        for (int i = 1; i < types.length; i++) {
+            prev = getCommonSuperType(context, prev, types[i]);
+        }
+        return prev;
+    }
+
+    public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror type1, TypeMirror type2) {
+        if (typeEquals(type1, type2)) {
+            return type1;
+        }
+        TypeElement element1 = fromTypeMirror(type1);
+        TypeElement element2 = fromTypeMirror(type2);
+        if (element1 == null || element2 == null) {
+            return context.getType(Object.class);
+        }
+
+        List<TypeElement> element1Types = getDirectSuperTypes(element1);
+        element1Types.add(0, element1);
+        List<TypeElement> element2Types = getDirectSuperTypes(element2);
+        element2Types.add(0, element2);
+
+        for (TypeElement superType1 : element1Types) {
+            for (TypeElement superType2 : element2Types) {
+                if (typeEquals(superType1.asType(), superType2.asType())) {
+                    return superType2.asType();
+                }
+            }
+        }
+        return context.getType(Object.class);
+    }
+
     public static String getReadableSignature(ExecutableElement method) {
         // TODO toString does not guarantee a good signature
         return method.toString();
@@ -146,31 +190,43 @@
             case LONG:
                 return "long";
             case DECLARED:
-                return getGenericName(fromTypeMirror(mirror));
+                return getDeclaredName((DeclaredType) mirror);
             case ARRAY:
                 return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]";
             case VOID:
                 return "void";
+            case WILDCARD:
+                return getWildcardName((WildcardType) mirror);
             case TYPEVAR:
-                return ((TypeParameterElement) ((TypeVariable) mirror).asElement()).getSimpleName().toString();
+                return "?";
             default:
                 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror);
         }
     }
 
-    private static String getGenericName(TypeElement element) {
-        String simpleName = element.getSimpleName().toString();
+    private static String getWildcardName(WildcardType type) {
+        StringBuilder b = new StringBuilder();
+        if (type.getExtendsBound() != null) {
+            b.append("? extends ").append(getSimpleName(type.getExtendsBound()));
+        } else if (type.getSuperBound() != null) {
+            b.append("? super ").append(getSimpleName(type.getExtendsBound()));
+        }
+        return b.toString();
+    }
 
-        if (element.getTypeParameters().size() == 0) {
+    private static String getDeclaredName(DeclaredType element) {
+        String simpleName = element.asElement().getSimpleName().toString();
+
+        if (element.getTypeArguments().size() == 0) {
             return simpleName;
         }
 
         StringBuilder b = new StringBuilder(simpleName);
         b.append("<");
-        if (element.getTypeParameters().size() > 0) {
-            for (int i = 0; i < element.getTypeParameters().size(); i++) {
-                b.append("?");
-                if (i < element.getTypeParameters().size() - 1) {
+        if (element.getTypeArguments().size() > 0) {
+            for (int i = 0; i < element.getTypeArguments().size(); i++) {
+                b.append(getSimpleName(element.getTypeArguments().get(i)));
+                if (i < element.getTypeArguments().size() - 1) {
                     b.append(", ");
                 }
             }
@@ -282,6 +338,19 @@
         return null;
     }
 
+    public static List<TypeElement> getDirectSuperTypes(TypeElement element) {
+        List<TypeElement> types = new ArrayList<>();
+        if (element.getSuperclass() != null) {
+            TypeElement superElement = fromTypeMirror(element.getSuperclass());
+            if (superElement != null) {
+                types.add(superElement);
+                types.addAll(getDirectSuperTypes(superElement));
+            }
+        }
+
+        return types;
+    }
+
     public static List<TypeElement> getSuperTypes(TypeElement element) {
         List<TypeElement> types = new ArrayList<>();
         List<TypeElement> superTypes = null;
@@ -468,8 +537,10 @@
             for (int i = 0; i < params.length; i++) {
                 TypeMirror param1 = params[i];
                 TypeMirror param2 = method.getParameters().get(i).asType();
-                if (!getQualifiedName(param1).equals(getQualifiedName(param2))) {
-                    continue method;
+                if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) {
+                    if (!getQualifiedName(param1).equals(getQualifiedName(param2))) {
+                        continue method;
+                    }
                 }
             }
             return method;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Feb 26 11:55:00 2013 +0100
@@ -114,7 +114,7 @@
     }
 
     public CodeTreeBuilder createBuilder() {
-        CodeTreeBuilder builder = new CodeTreeBuilder();
+        CodeTreeBuilder builder = new CodeTreeBuilder(null);
         this.bodyTree = builder.getTree();
         this.bodyTree.setEnclosingElement(this);
         this.body = null;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Feb 26 11:55:00 2013 +0100
@@ -33,17 +33,25 @@
 
 public class CodeTreeBuilder {
 
+    private final CodeTreeBuilder parent;
+
     private BuilderCodeTree currentElement;
     private final BuilderCodeTree root;
 
-    public CodeTreeBuilder() {
+    private int treeCount;
+
+    public CodeTreeBuilder(CodeTreeBuilder parent) {
         this.root = new BuilderCodeTree(GROUP, null, null);
         this.currentElement = root;
+        this.parent = parent;
     }
 
-    public CodeTreeBuilder(CodeTree tree) {
-        this.root = (BuilderCodeTree) tree;
-        this.currentElement = root;
+    public int getTreeCount() {
+        return treeCount;
+    }
+
+    public boolean isEmpty() {
+        return treeCount == 0;
     }
 
     public CodeTreeBuilder statement(String statement) {
@@ -55,11 +63,11 @@
     }
 
     public static CodeTreeBuilder createBuilder() {
-        return new CodeTreeBuilder();
+        return new CodeTreeBuilder(null);
     }
 
     public static CodeTree singleString(String s) {
-        return new CodeTreeBuilder().string(s).getTree();
+        return new CodeTreeBuilder(null).string(s).getTree();
     }
 
     private CodeTreeBuilder push(CodeTreeKind kind) {
@@ -89,11 +97,14 @@
                 currentElement = tree;
                 break;
         }
+        treeCount++;
         return this;
     }
 
     private void clearLast(CodeTreeKind kind) {
-        clearLastRec(kind, currentElement.getEnclosedElements());
+        if (clearLastRec(kind, currentElement.getEnclosedElements())) {
+            treeCount--;
+        }
     }
 
     public CodeTreeBuilder startStatement() {
@@ -193,6 +204,24 @@
         return this;
     }
 
+    private CodeTreeBuilder startCurlyBracesCommaGroup() {
+        startGroup();
+        string("{").startCommaGroup();
+        registerCallBack(new EndCallback() {
+
+            @Override
+            public void beforeEnd() {
+            }
+
+            @Override
+            public void afterEnd() {
+                string("}");
+            }
+        });
+        endAfter();
+        return this;
+    }
+
     public CodeTreeBuilder startParantheses() {
         startGroup();
         string("(").startGroup();
@@ -211,6 +240,10 @@
         return this;
     }
 
+    public CodeTreeBuilder doubleQuote(String s) {
+        return startGroup().string("\"").string(s).string("\"").end();
+    }
+
     public CodeTreeBuilder startDoubleQuote() {
         startGroup().string("\"");
         registerCallBack(new EndCallback() {
@@ -271,6 +304,15 @@
         return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter();
     }
 
+    public boolean startIf(boolean elseIf) {
+        if (elseIf) {
+            startElseIf();
+        } else {
+            startIf();
+        }
+        return true;
+    }
+
     public CodeTreeBuilder startElseIf() {
         clearLast(CodeTreeKind.NEW_LINE);
         return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter();
@@ -346,6 +388,19 @@
         return startStatement().string("assert ");
     }
 
+    public CodeTreeBuilder startNewArray(ArrayType arrayType, CodeTree size) {
+        startGroup().string("new ").type(arrayType.getComponentType()).string("[");
+        if (size != null) {
+            tree(size);
+        }
+        string("]");
+        if (size == null) {
+            string(" ");
+            startCurlyBracesCommaGroup().endAfter();
+        }
+        return this;
+    }
+
     public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) {
         return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter();
     }
@@ -358,6 +413,13 @@
         return push(CodeTreeKind.INDENT);
     }
 
+    public CodeTreeBuilder end(int times) {
+        for (int i = 0; i < times; i++) {
+            end();
+        }
+        return this;
+    }
+
     public CodeTreeBuilder end() {
         BuilderCodeTree tree = currentElement;
         EndCallback callback = tree.getAtEndListener();
@@ -372,9 +434,9 @@
     }
 
     private void toParent() {
-        Element parent = currentElement.getEnclosingElement();
+        Element parentElement = currentElement.getEnclosingElement();
         if (currentElement != root) {
-            this.currentElement = (BuilderCodeTree) parent;
+            this.currentElement = (BuilderCodeTree) parentElement;
         } else {
             this.currentElement = root;
         }
@@ -433,7 +495,7 @@
     }
 
     public CodeTreeBuilder create() {
-        return new CodeTreeBuilder();
+        return new CodeTreeBuilder(null);
     }
 
     public CodeTreeBuilder type(TypeMirror type) {
@@ -496,7 +558,11 @@
         while (element != null && (element.getKind() != ElementKind.METHOD)) {
             element = element.getEnclosingElement();
         }
-        return element != null ? (ExecutableElement) element : null;
+        ExecutableElement found = element != null ? (ExecutableElement) element : null;
+        if (found == null && parent != null) {
+            found = parent.findMethod();
+        }
+        return found;
     }
 
     public CodeTreeBuilder returnTrue() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java	Tue Feb 26 11:55:00 2013 +0100
@@ -58,7 +58,7 @@
     }
 
     public CodeTreeBuilder createInitBuilder() {
-        CodeTreeBuilder builder = new CodeTreeBuilder();
+        CodeTreeBuilder builder = new CodeTreeBuilder(null);
         init = builder.getTree();
         init.setEnclosingElement(this);
         return builder;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Feb 26 11:55:00 2013 +0100
@@ -36,9 +36,16 @@
 
 public abstract class AbstractCodeWriter extends CodeElementScanner<Void, Void> {
 
+    private static final int LINE_LENGTH = 200;
+    private static final int LINE_WRAP_INDENTS = 3;
+    private static final String IDENT_STRING = "    ";
+    private static final String LN = "\n"; /* unix style */
+
     protected Writer writer;
     private int indent;
     private boolean newLine;
+    private int lineLength;
+    private boolean lineWrapping = false;
 
     private OrganizedImports imports;
 
@@ -56,8 +63,7 @@
             Writer w = null;
             try {
                 imports = OrganizedImports.organize(e);
-
-                w = createWriter(e);
+                w = new TrimTrailingSpaceWriter(createWriter(e));
                 writer = w;
                 writeRootClass(e);
             } catch (IOException ex) {
@@ -145,7 +151,7 @@
 
         write(" {").writeLn();
         writeEmptyLn();
-        indent();
+        indent(1);
 
         List<VariableElement> staticFields = getStaticFields(e);
         List<VariableElement> instanceFields = getInstanceFields(e);
@@ -191,7 +197,7 @@
             clazz.accept(this, null);
         }
 
-        dedent();
+        dedent(1);
         write("}");
         writeEmptyLn();
     }
@@ -262,6 +268,14 @@
         } else {
             writeModifiers(f.getModifiers());
             write(typeSimpleName(f.asType()));
+
+            if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
+                ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
+                if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) {
+                    write("...");
+                }
+            }
+
             write(" ");
             write(f.getSimpleName());
             if (init != null) {
@@ -474,9 +488,9 @@
             writeLn(";");
         } else if (e.getBodyTree() != null) {
             writeLn(" {");
-            indent();
+            indent(1);
             e.getBodyTree().acceptCodeElementScanner(this, p);
-            dedent();
+            dedent(1);
             writeLn("}");
         } else if (e.getBody() != null) {
             write(" {");
@@ -509,11 +523,11 @@
                 }
                 break;
             case INDENT:
-                indent();
+                indent(1);
                 for (CodeTree tree : e.getEnclosedElements()) {
                     tree.acceptCodeElementScanner(this, p);
                 }
-                dedent();
+                dedent(1);
                 break;
             case NEW_LINE:
                 writeLn();
@@ -565,25 +579,28 @@
         }
     }
 
-    private static final String LN = "\n";
-
-    protected void indent() {
-        indent++;
+    protected void indent(int count) {
+        indent += count;
     }
 
-    protected void dedent() {
-        indent--;
+    protected void dedent(int count) {
+        indent -= count;
     }
 
     protected void writeLn() {
-        write(LN);
-        newLine = true;
+        writeLn("");
     }
 
     protected void writeLn(String text) {
         write(text);
         write(LN);
+        lineLength = 0;
         newLine = true;
+        if (lineWrapping) {
+            dedent(LINE_WRAP_INDENTS);
+            lineWrapping = false;
+        }
+        lineWrapping = false;
     }
 
     protected void writeEmptyLn() {
@@ -596,10 +613,23 @@
 
     private AbstractCodeWriter write(String m) {
         try {
+            lineLength += m.length();
             if (newLine && m != LN) {
                 writeIndent();
                 newLine = false;
             }
+            if (lineLength > LINE_LENGTH && m.length() > 0) {
+                char firstChar = m.charAt(0);
+                if (Character.isAlphabetic(firstChar)) {
+                    if (!lineWrapping) {
+                        indent(LINE_WRAP_INDENTS);
+                    }
+                    lineWrapping = true;
+                    lineLength = 0;
+                    write(LN);
+                    writeIndent();
+                }
+            }
             writer.write(m);
         } catch (IOException e) {
             throw new RuntimeException(e);
@@ -609,7 +639,57 @@
 
     private void writeIndent() throws IOException {
         for (int i = 0; i < indent; i++) {
-            writer.write("    ");
+            lineLength += IDENT_STRING.length();
+            writer.write(IDENT_STRING);
         }
     }
+
+    private static class TrimTrailingSpaceWriter extends Writer {
+
+        private final Writer delegate;
+        private final StringBuilder buffer = new StringBuilder();
+
+        public TrimTrailingSpaceWriter(Writer delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public void close() throws IOException {
+            this.delegate.close();
+        }
+
+        @Override
+        public void flush() throws IOException {
+            this.delegate.flush();
+        }
+
+        @Override
+        public void write(char[] cbuf, int off, int len) throws IOException {
+            buffer.append(cbuf, off, len);
+            int newLinePoint = buffer.indexOf(LN);
+
+            if (newLinePoint != -1) {
+                String lhs = trimTrailing(buffer.substring(0, newLinePoint));
+                delegate.write(lhs);
+                delegate.write(LN);
+                buffer.delete(0, newLinePoint + 1);
+            }
+        }
+
+        private static String trimTrailing(String s) {
+            int cut = 0;
+            for (int i = s.length() - 1; i >= 0; i--) {
+                if (Character.isWhitespace(s.charAt(i))) {
+                    cut++;
+                } else {
+                    break;
+                }
+            }
+            if (cut > 0) {
+                return s.substring(0, s.length() - cut);
+            }
+            return s;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Tue Feb 26 11:55:00 2013 +0100
@@ -63,19 +63,71 @@
     }
 
     public String useImport(TypeMirror type) {
-        String simpleName = getSimpleName(type);
-        TypeMirror usedByType = simpleNamesUsed.get(type);
+        switch (type.getKind()) {
+            case BOOLEAN:
+            case BYTE:
+            case CHAR:
+            case DOUBLE:
+            case FLOAT:
+            case SHORT:
+            case INT:
+            case LONG:
+            case VOID:
+                return Utils.getSimpleName(type);
+            case DECLARED:
+                return createDeclaredTypeName((DeclaredType) type);
+            case ARRAY:
+                return useImport(((ArrayType) type).getComponentType()) + "[]";
+            case WILDCARD:
+                return createWildcardName((WildcardType) type);
+            case TYPEVAR:
+                return "?";
+            default:
+                throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type);
+        }
+    }
+
+    private String createWildcardName(WildcardType type) {
+        StringBuilder b = new StringBuilder();
+        if (type.getExtendsBound() != null) {
+            b.append("? extends ").append(useImport(type.getExtendsBound()));
+        } else if (type.getSuperBound() != null) {
+            b.append("? super ").append(useImport(type.getExtendsBound()));
+        }
+        return b.toString();
+    }
+
+    private String createDeclaredTypeName(DeclaredType type) {
+        String name = type.asElement().getSimpleName().toString();
+
+        TypeMirror usedByType = simpleNamesUsed.get(name);
         if (usedByType == null) {
-            simpleNamesUsed.put(simpleName, type);
+            simpleNamesUsed.put(name, type);
             usedByType = type;
-        } else if (!typeEquals(type, usedByType)) {
-            // we need a qualified name
-            return getQualifiedName(type);
         }
 
-        // we can use the simple name
-        addUsage(type, importUsage);
-        return simpleName;
+        if (typeEquals(type, usedByType)) {
+            addUsage(type, importUsage);
+        } else {
+            name = getQualifiedName(type);
+        }
+
+        if (type.getTypeArguments().size() == 0) {
+            return name;
+        }
+
+        StringBuilder b = new StringBuilder(name);
+        b.append("<");
+        if (type.getTypeArguments().size() > 0) {
+            for (int i = 0; i < type.getTypeArguments().size(); i++) {
+                b.append(useImport(type.getTypeArguments().get(i)));
+                if (i < type.getTypeArguments().size() - 1) {
+                    b.append(", ");
+                }
+            }
+        }
+        b.append(">");
+        return b.toString();
     }
 
     public String useStaticFieldImport(TypeMirror type, String fieldName) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Feb 26 11:55:00 2013 +0100
@@ -31,6 +31,7 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
+import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.ast.*;
 import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
@@ -69,7 +70,8 @@
 
     private static String specializationId(SpecializationData specialization) {
         String name = "";
-        if (specialization.getNode().getSpecializations().length > 1) {
+        NodeData node = specialization.getNode();
+        if (node.getSpecializations().length > 1) {
             name = specialization.getMethodName();
             if (name.startsWith("do")) {
                 name = name.substring(2);
@@ -82,8 +84,8 @@
         return field.getName() + "Value";
     }
 
-    private static String valueName(TemplateMethod method, ActualParameter param) {
-        NodeData node = (NodeData) method.getTemplate();
+    private static String valueName(ActualParameter param) {
+        NodeData node = (NodeData) param.getMethod().getTemplate();
         NodeFieldData field = node.findField(param.getSpecification().getName());
         if (field != null) {
             return valueName(field);
@@ -92,6 +94,14 @@
         }
     }
 
+    private static String castValueName(ActualParameter parameter) {
+        return valueName(parameter) + "Cast";
+    }
+
+    private static String castValueName(NodeFieldData field) {
+        return valueName(field) + "Cast";
+    }
+
     private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) {
         if (forceFrame) {
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame"));
@@ -101,7 +111,7 @@
             if (forceFrame && spec.getName().equals("frame")) {
                 continue;
             }
-            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter)));
+            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
         }
     }
 
@@ -118,21 +128,28 @@
             if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else {
-                builder.string(valueName(specialization, parameter));
+                builder.string(valueName(parameter));
             }
         }
     }
 
-    private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization) {
-        for (ActualParameter param : specialization.getParameters()) {
-            TypeData typeData = param.getActualTypeData(specialization.getNode().getTypeSystem());
-            if (typeData == null || typeData.isGeneric()) {
-                body.string(valueName(specialization, param));
+    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) {
+        NodeData node = targetSpecialization.getNode();
+        TypeSystemData typeSystem = node.getTypeSystem();
+
+        for (ActualParameter targetParameter : targetSpecialization.getParameters()) {
+            ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getSpecification().getName());
+            TypeData targetType = targetParameter.getActualTypeData(typeSystem);
+
+            TypeData valueType = null;
+            if (valueParameter != null) {
+                valueType = valueParameter.getActualTypeData(typeSystem);
+            }
+
+            if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) {
+                body.string(valueName(targetParameter));
             } else {
-                String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData);
-                startCallTypeSystemMethod(context, body, specialization.getNode(), methodName);
-                body.string(valueName(specialization, param));
-                body.end().end();
+                body.string(castValueName(targetParameter));
             }
         }
     }
@@ -173,6 +190,14 @@
         return prefix;
     }
 
+    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        startCallTypeSystemMethod(context, builder, node, methodName);
+        builder.string(value);
+        builder.end().end();
+        return builder.getRoot();
+    }
+
     private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) {
         VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem());
         assert singleton != null;
@@ -182,44 +207,205 @@
         body.string(".").startCall(methodName);
     }
 
-    private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) {
-        TypeSystemData typeSystem = specialization.getNode().getTypeSystem();
-        // Implict guards based on method signature
-        String andOperator = prefix;
-        if (needsCast) {
-            for (NodeFieldData field : specialization.getNode().getFields()) {
-                ActualParameter param = specialization.findParameter(field.getName());
-                TypeData type = param.getActualTypeData(typeSystem);
-                if (type == null || type.isGeneric()) {
-                    continue;
-                }
+    private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization,
+                    CodeTree guardedStatements, CodeTree elseStatements) {
+
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization);
+        CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization);
+
+        int ifCount = 0;
 
-                body.string(andOperator);
-                startCallTypeSystemMethod(context, body, specialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(type));
-                body.string(valueName(specialization, param));
-                body.end().end(); // call
-                andOperator = " && ";
-            }
+        if (implicitGuards != null) {
+            builder.startIf();
+            builder.tree(implicitGuards);
+            builder.end();
+            builder.startBlock();
+            ifCount++;
+        }
+
+        if (explicitGuards != null || !onSpecialization) {
+            builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization));
+        }
+
+        if (explicitGuards != null) {
+            builder.startIf();
+            builder.tree(explicitGuards);
+            builder.end();
+            builder.startBlock();
+            ifCount++;
         }
 
-        if (specialization.getGuards().length > 0) {
-            // Explicitly specified guards
-            for (SpecializationGuardData guard : specialization.getGuards()) {
-                if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
-                    body.string(andOperator);
+        if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) {
+            builder.startIf().string(conditionPrefix).end().startBlock();
+            ifCount++;
+        }
+
+        builder.tree(guardedStatements);
+
+        builder.end(ifCount);
+        if (ifCount > 0 && elseStatements != null) {
+            builder.startElseBlock();
+            builder.tree(elseStatements);
+            builder.end();
+        }
 
-                    startCallOperationMethod(body, guard.getGuardDeclaration());
+        return builder.getRoot();
+    }
 
-                    if (needsCast) {
-                        addValueParameterNamesWithCasts(context, body, specialization);
-                    } else {
-                        addValueParameterNames(body, specialization, null, false);
-                    }
-                    body.end().end(); // call
+    private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization,
+                    boolean onSpecialization) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
+        if (guardedSpecialization.getGuards().length > 0) {
+            // Explicitly specified guards
+            for (SpecializationGuardData guard : guardedSpecialization.getGuards()) {
+                if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
+                    builder.string(andOperator);
+
+                    startCallOperationMethod(builder, guard.getGuardDeclaration());
+                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization);
+
+                    builder.end().end(); // call
                     andOperator = " && ";
                 }
             }
         }
+
+        return builder.isEmpty() ? null : builder.getRoot();
+    }
+
+    private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+        NodeData node = guardedSpecialization.getNode();
+
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        // Implict guards based on method signature
+        for (NodeFieldData field : node.getFields()) {
+            ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
+            ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
+
+            CodeTree cast = createCast(parent, field, valueParam, guardedParam);
+            if (cast == null) {
+                continue;
+            }
+            builder.tree(cast);
+        }
+
+        return builder.getRoot();
+    }
+
+    private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+        NodeData node = guardedSpecialization.getNode();
+
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        // Implict guards based on method signature
+        String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
+        for (NodeFieldData field : node.getFields()) {
+            ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
+            ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
+
+            CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam);
+            if (implicitGuard == null) {
+                continue;
+            }
+
+            builder.string(andOperator);
+            builder.tree(implicitGuard);
+            andOperator = " && ";
+        }
+
+        return builder.isEmpty() ? null : builder.getRoot();
+    }
+
+    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+        NodeData node = field.getNodeData();
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+        TypeData targetType = target.getActualTypeData(node.getTypeSystem());
+        TypeData sourceType = source.getActualTypeData(node.getTypeSystem());
+
+        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+            return null;
+        }
+
+        builder.startGroup();
+
+        if (field.isShortCircuit()) {
+            ActualParameter shortCircuit = target.getPreviousParameter();
+            assert shortCircuit != null;
+            builder.string("(");
+            builder.string("!").string(valueName(shortCircuit));
+            builder.string(" || ");
+        }
+
+        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem())));
+        builder.string(valueName(field));
+        builder.end().end(); // call
+
+        if (field.isShortCircuit()) {
+            builder.string(")");
+        }
+
+        builder.end(); // group
+
+        return builder.getRoot();
+    }
+
+    private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+        NodeData node = field.getNodeData();
+        TypeSystemData typeSystem = node.getTypeSystem();
+
+        TypeData sourceType = source.getActualTypeData(typeSystem);
+        TypeData targetType = target.getActualTypeData(typeSystem);
+
+        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+            return null;
+        }
+
+        CodeTree condition = null;
+        if (field.isShortCircuit()) {
+            ActualParameter shortCircuit = target.getPreviousParameter();
+            assert shortCircuit != null;
+            condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
+        }
+
+        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target));
+
+        return createLazyAssignment(parent, castValueName(field), target.getActualType(), condition, value);
+    }
+
+    /**
+     * <pre>
+     * variant1 $condition != null
+     * 
+     * $type $name = defaultValue($type);
+     * if ($condition) {
+     *     $name = $value;
+     * }
+     * 
+     * variant2 $condition != null
+     * $type $name = $value;
+     * </pre>
+     * 
+     * .
+     */
+    private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        if (condition == null) {
+            builder.declaration(type, name, value);
+        } else {
+            builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot());
+
+            builder.startIf().tree(condition).end();
+            builder.startBlock();
+            builder.startStatement();
+            builder.string(name);
+            builder.string(" = ");
+            builder.tree(value);
+            builder.end(); // statement
+            builder.end(); // block
+        }
+        return builder.getRoot();
     }
 
     @Override
@@ -237,11 +423,7 @@
             add(factory, node);
         }
 
-        if (node.getSpecializations() == null) {
-            return;
-        }
-
-        if (node.needsFactory() || childTypes.size() > 0) {
+        if (node.needsFactory() || node.getNodeChildren().size() > 0) {
             add(new NodeFactoryFactory(context, childTypes), node);
         }
     }
@@ -326,6 +508,15 @@
                 for (SpecializationData specialization : node.getSpecializations()) {
                     add(new SpecializedNodeFactory(context), specialization);
                 }
+
+                TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType());
+                clazz.getImplements().add(nodeFactory);
+                clazz.add(createCreateNodeMethod(node));
+                clazz.add(createCreateNodeSpecializedMethod(node));
+                clazz.add(createGetNodeClassMethod(node));
+                clazz.add(createGetNodeSignaturesMethod(node));
+                clazz.add(createGetInstanceMethod(node, createVisibility));
+                clazz.add(createInstanceConstant(node, clazz.asType()));
             }
 
             for (NodeData childNode : childTypes.keySet()) {
@@ -346,9 +537,236 @@
                     clazz.add(type);
                 }
             }
+
+            List<NodeData> children = node.getNodeChildren();
+            if (node.getParent() == null && children.size() > 0) {
+                clazz.add(createGetFactories(node));
+            }
+
+        }
+
+        private CodeExecutableElement createGetNodeClassMethod(NodeData node) {
+            Types types = getContext().getEnvironment().getTypeUtils();
+            TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass");
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startReturn().typeLiteral(node.getNodeType()).end();
+            return method;
+        }
+
+        private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) {
+            Types types = getContext().getEnvironment().getTypeUtils();
+            TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class));
+            TypeMirror classType = getContext().getType(Class.class);
+            TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType));
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures");
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startReturn();
+            builder.startStaticCall(getContext().getType(Arrays.class), "asList");
+            List<ExecutableElement> constructors = findUserConstructors(node);
+            for (ExecutableElement constructor : constructors) {
+                builder.startGroup();
+                builder.type(getContext().getType(Arrays.class));
+                builder.string(".<").type(getContext().getType(Class.class)).string(">");
+                builder.startCall("asList");
+                for (VariableElement param : constructor.getParameters()) {
+                    builder.typeLiteral(param.asType());
+                }
+                builder.end();
+                builder.end();
+            }
+            builder.end();
+            builder.end();
+            return method;
+        }
+
+        private CodeExecutableElement createCreateNodeMethod(NodeData node) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode");
+            CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments");
+            method.setVarArgs(true);
+            method.addParameter(arguments);
+
+            CodeTreeBuilder builder = method.createBuilder();
+            List<ExecutableElement> signatures = findUserConstructors(node);
+            boolean ifStarted = false;
+
+            for (ExecutableElement element : signatures) {
+                ifStarted = builder.startIf(ifStarted);
+                builder.string("arguments.length == " + element.getParameters().size());
+
+                int index = 0;
+                for (VariableElement param : element.getParameters()) {
+                    builder.string(" && ");
+                    if (!param.asType().getKind().isPrimitive()) {
+                        builder.string("(arguments[" + index + "] == null || ");
+                    }
+                    builder.string("arguments[" + index + "] instanceof ");
+                    builder.type(Utils.boxType(getContext(), param.asType()));
+                    if (!param.asType().getKind().isPrimitive()) {
+                        builder.string(")");
+                    }
+                    index++;
+                }
+                builder.end();
+                builder.startBlock();
+
+                builder.startReturn().startCall("create");
+                index = 0;
+                for (VariableElement param : element.getParameters()) {
+                    builder.startGroup();
+                    builder.string("(").type(param.asType()).string(") ");
+                    builder.string("arguments[").string(String.valueOf(index)).string("]");
+                    builder.end();
+                    index++;
+                }
+                builder.end().end();
+
+                builder.end(); // block
+            }
+
+            builder.startElseBlock();
+            builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class));
+            builder.doubleQuote("Invalid create signature.");
+            builder.end().end();
+            builder.end(); // else block
+            return method;
+        }
+
+        private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized");
+            CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode");
+            CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types");
+            method.addParameter(nodeParam);
+            method.addParameter(arguments);
+            method.setVarArgs(true);
+
+            CodeTreeBuilder builder = method.createBuilder();
+            if (!node.needsRewrites(getContext())) {
+                builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
+            } else {
+                builder.startIf();
+                builder.string("types.length == 1");
+                builder.end();
+                builder.startBlock();
+
+                builder.startReturn().startCall("createSpecialized");
+                builder.string("thisNode");
+                builder.string("types[0]");
+                builder.end().end();
+
+                builder.end();
+                builder.startElseBlock();
+                builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class));
+                builder.doubleQuote("Invalid createSpecialized signature.");
+                builder.end().end();
+                builder.end();
+            }
+
+            return method;
+        }
+
+        private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) {
+            Types types = getContext().getEnvironment().getTypeUtils();
+            TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class));
+            TypeMirror returnType = types.getDeclaredType(nodeFactoryType, node.getNodeType());
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance");
+            if (visibility != null) {
+                method.getModifiers().add(visibility);
+            }
+            method.getModifiers().add(Modifier.STATIC);
+
+            String varName = instanceVarName(node);
+
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startIf();
+            builder.string(varName).string(" == null");
+            builder.end().startBlock();
+
+            builder.startStatement();
+            builder.string(varName);
+            builder.string(" = ");
+            builder.startNew(factoryClassName(node)).end();
+            builder.end();
+
+            builder.end();
+            builder.startReturn().string(varName).end();
+            return method;
+        }
+
+        private String instanceVarName(NodeData node) {
+            if (node.getParent() != null) {
+                return Utils.firstLetterLowerCase(factoryClassName(node)) + "Instance";
+            } else {
+                return "instance";
+            }
+        }
+
+        private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) {
+            String varName = instanceVarName(node);
+            CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName);
+            var.getModifiers().add(Modifier.PRIVATE);
+            var.getModifiers().add(Modifier.STATIC);
+            return var;
+        }
+
+        private ExecutableElement createGetFactories(NodeData node) {
+            List<NodeData> children = node.getNodeChildren();
+            if (node.needsFactory()) {
+                children.add(node);
+            }
+
+            List<TypeMirror> nodeTypesList = new ArrayList<>();
+            for (NodeData child : children) {
+                nodeTypesList.add(child.getTemplateType().asType());
+            }
+            TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()]));
+
+            Types types = getContext().getEnvironment().getTypeUtils();
+            TypeMirror factoryType = getContext().getType(NodeFactory.class);
+            TypeMirror baseType;
+            if (children.size() == 1) {
+                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
+            } else {
+                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
+            }
+            TypeMirror listType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType);
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories");
+
+            CodeTreeBuilder builder = method.createBuilder();
+            builder.startReturn();
+            builder.startStaticCall(getContext().getType(Arrays.class), "asList");
+
+            for (NodeData child : children) {
+                builder.startGroup();
+                NodeData childNode = child;
+                List<NodeData> factories = new ArrayList<>();
+                while (childNode.getParent() != null) {
+                    factories.add(childNode);
+                    childNode = childNode.getParent();
+                }
+                Collections.reverse(factories);
+                for (NodeData nodeData : factories) {
+                    builder.string(factoryClassName(nodeData)).string(".");
+                }
+                builder.string("getInstance()");
+                builder.end();
+            }
+            builder.end();
+            builder.end();
+            return method;
         }
 
         private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) {
+            List<ExecutableElement> constructors = findUserConstructors(node);
+            for (ExecutableElement constructor : constructors) {
+                clazz.add(createCreateMethod(node, createVisibility, constructor));
+            }
+        }
+
+        private List<ExecutableElement> findUserConstructors(NodeData node) {
+            List<ExecutableElement> constructors = new ArrayList<>();
             for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) {
                 if (constructor.getModifiers().contains(PRIVATE)) {
                     continue;
@@ -358,9 +776,9 @@
                 if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) {
                     continue;
                 }
-
-                clazz.add(createCreateMethod(node, createVisibility, constructor));
+                constructors.add(constructor);
             }
+            return constructors;
         }
 
         private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) {
@@ -436,17 +854,12 @@
                 SpecializationData specialization = node.getSpecializations()[i];
                 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end();
 
-                if (specialization.isGeneric()) {
-                    body.startIf().string("allowed").end().startBlock();
-                } else {
-                    body.startIf().string("allowed");
-                    emitGuards(getContext(), body, " && ", specialization, true, true);
-                    body.end().startBlock();
-                }
-                body.startReturn().startNew(nodeClassName(specialization));
-                body.string(THIS_NODE_LOCAL_VAR_NAME);
-                body.end().end();
-                body.end(); // block
+                CodeTreeBuilder guarded = new CodeTreeBuilder(body);
+                guarded.startReturn().startNew(nodeClassName(specialization));
+                guarded.string(THIS_NODE_LOCAL_VAR_NAME);
+                guarded.end().end();
+
+                body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null));
             }
             body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
 
@@ -490,24 +903,23 @@
         }
 
         private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) {
+            CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder);
+            emitInvokeDoMethod(invokeMethodBuilder, current, 0);
+            CodeTree invokeMethod = invokeMethodBuilder.getRoot();
+
             if (next != null) {
-                builder.startIf();
-                emitGuards(context, builder, "", current, false, true);
-                builder.end().startBlock();
+                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, null);
             }
 
-            emitInvokeDoMethod(builder, current, 0);
+            builder.tree(invokeMethod);
 
             if (next != null) {
                 builder.end();
-                builder.startElseBlock();
 
                 builder.startReturn().startCall(generatedGenericMethodName(next));
                 builder.string(THIS_NODE_LOCAL_VAR_NAME);
                 addValueParameterNames(builder, next, null, true);
                 builder.end().end();
-
-                builder.end();
             }
         }
 
@@ -518,7 +930,7 @@
 
             builder.startReturn();
             startCallOperationMethod(builder, specialization);
-            addValueParameterNamesWithCasts(context, builder, specialization);
+            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization);
             builder.end().end(); // start call operation
             builder.end(); // return
 
@@ -625,14 +1037,14 @@
                     builder.string("// ignore").newLine();
                 } else {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
+                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()")));
                     builder.end();
                 }
                 builder.end();
 
                 if (!returnVoid) {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("value")));
+                    builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value")));
                     builder.end();
                 }
             } else {
@@ -640,81 +1052,92 @@
                     builder.statement(primaryExecuteCall);
                 } else {
                     builder.startReturn();
-                    builder.tree(castPrimaryExecute(node, castedType, primaryExecuteCall));
+                    builder.tree(createExpectType(node, castedType, primaryExecuteCall));
                     builder.end();
                 }
             }
         }
 
-        private CodeTree castPrimaryExecute(NodeData node, ExecutableTypeData castedType, CodeTree value) {
-            if (castedType.getType().isVoid()) {
+        private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) {
+            if (castedType == null) {
                 return value;
-            }
-            if (castedType.getType().isGeneric()) {
+            } else if (castedType.getType().isVoid()) {
+                return value;
+            } else if (castedType.getType().isGeneric()) {
                 return value;
             }
 
             CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+            String targetMethodName;
             if (castedType.hasUnexpectedValue(getContext())) {
-                startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()));
+                targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType());
             } else {
-                startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()));
+                targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType());
             }
+            startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
+
             builder.tree(value);
             builder.end().end();
             return builder.getRoot();
         }
 
         private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) {
-            NodeData node = specialization.getNode();
-            TypeSystemData typeSystem = node.getTypeSystem();
-
-            for (NodeFieldData field : node.getFields()) {
-                if (field.getExecutionKind() == ExecutionKind.IGNORE) {
-                    continue;
-                }
+            if (specialization.isUninitialized()) {
+                builder.tree(createDeoptimize(builder));
+            }
 
-                ActualParameter parameterType = specialization.findParameter(field.getName());
+            builder.tree(createExecuteChildren(builder, specialization));
 
-                if (parameterType.getActualTypeData(typeSystem).isGeneric()) {
-                    buildGenericValueExecute(builder, specialization, field, null);
-                } else {
-                    buildSpecializedValueExecute(builder, specialization, field);
-                }
+            if (specialization.isUninitialized()) {
+                builder.tree(createSpecializeCall(builder, specialization));
             }
 
-            if (specialization.hasDynamicGuards()) {
-                builder.startIf();
-                emitGuards(getContext(), builder, "", specialization, false, false);
-                builder.end().startBlock();
+            CodeTree executeNode = createExecute(builder, specialization);
+
+            SpecializationData next = specialization.findNextSpecialization();
+            CodeTree returnSpecialized = null;
+            if (next != null) {
+                returnSpecialized = createReturnSpecializeAndExecute(builder, next, null);
             }
+            builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized));
+        }
+
+        private CodeTree createDeoptimize(CodeTreeBuilder parent) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            builder.startStatement();
+            builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end();
+            builder.end();
+            return builder.getRoot();
+        }
+
+        private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) {
+            NodeData node = specialization.getNode();
+
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            emitSpecializationListeners(builder, node);
+
+            builder.startStatement();
+            builder.startCall("replace");
+            if (node.needsRewrites(getContext())) {
+                builder.startCall(factoryClassName(node), "specialize");
+                builder.string("this");
+                builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
+                addValueParameterNames(builder, specialization, null, false);
+                builder.end(); // call replace, call specialize
+            } else {
+                builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
+            }
+            builder.end().end();
+            return builder.getRoot();
+        }
+
+        private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) {
+            NodeData node = specialization.getNode();
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (specialization.getExceptions().length > 0) {
                 builder.startTryBlock();
             }
 
-            if (specialization.isUninitialized()) {
-                for (TemplateMethod listener : node.getSpecializationListeners()) {
-                    builder.startStatement();
-                    startCallOperationMethod(builder, listener);
-                    addValueParameterNames(builder, listener, null, false);
-                    builder.end().end();
-                    builder.end(); // statement
-                }
-
-                builder.startStatement();
-                builder.startCall("replace");
-                if (node.needsRewrites(getContext())) {
-                    builder.startCall(factoryClassName(node), "specialize");
-                    builder.string("this");
-                    builder.typeLiteral(builder.getRoot().getEnclosingClass().asType());
-                    addValueParameterNames(builder, specialization, null, false);
-                    builder.end(); // call replace, call specialize
-                } else {
-                    builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
-                }
-                builder.end().end();
-            }
-
             if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) {
                 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null));
                 builder.string("this");
@@ -736,14 +1159,38 @@
             if (specialization.getExceptions().length > 0) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                    buildThrowSpecialize(builder, specialization, exception.getTransitionTo(), null);
+                    builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null));
                 }
                 builder.end();
             }
-            if (specialization.hasDynamicGuards()) {
-                builder.end().startElseBlock();
-                buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), null);
-                builder.end();
+            return builder.getRoot();
+        }
+
+        private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            for (NodeFieldData field : specialization.getNode().getFields()) {
+                if (field.getExecutionKind() == ExecutionKind.IGNORE) {
+                    continue;
+                }
+
+                ActualParameter parameterType = specialization.findParameter(field.getName());
+
+                if (parameterType.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) {
+                    buildGenericValueExecute(builder, specialization, field, null);
+                } else {
+                    buildSpecializedValueExecute(builder, specialization, field);
+                }
+            }
+            return builder.getRoot();
+        }
+
+        private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
+            for (TemplateMethod listener : node.getSpecializationListeners()) {
+                builder.startStatement();
+                startCallOperationMethod(builder, listener);
+                addValueParameterNames(builder, listener, null, false);
+                builder.end().end();
+                builder.end(); // statement
             }
         }
 
@@ -758,7 +1205,7 @@
                 builder.string(" ");
             }
 
-            builder.string(valueName(specialization, specParameter));
+            builder.string(valueName(specParameter));
             builder.string(" = ");
             ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), specParameter.getActualTypeData(node.getTypeSystem()));
             if (genericExecutableType == null) {
@@ -794,7 +1241,7 @@
             boolean shortCircuit = startShortCircuit(builder, specialization, field, null);
 
             if (!shortCircuit) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(specialization, param)).end();
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
             }
 
             ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
@@ -820,7 +1267,7 @@
                         execute = true;
                     }
                 }
-                buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), param.getSpecification());
+                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification()));
                 builder.end(); // catch block
             }
 
@@ -846,7 +1293,7 @@
                 }
             }
 
-            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = ");
+            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
 
             startCallOperationMethod(builder, shortCircuitData);
@@ -855,7 +1302,7 @@
 
             builder.end(); // statement
 
-            builder.declaration(parameter.getActualType(), valueName(specialization, parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
+            builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
             builder.startIf().string(shortCircuitParam.getSpecification().getName()).end();
             builder.startBlock();
 
@@ -868,50 +1315,38 @@
             }
         }
 
-        private void buildThrowSpecialize(CodeTreeBuilder builder, SpecializationData currentSpecialization, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) {
-            boolean canThrowUnexpected = Utils.canThrowType(builder.findMethod().getThrownTypes(), getContext().getTruffleTypes().getUnexpectedValueException());
-
-            CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder();
-            specializeCall.startCall("specialize");
+        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) {
+            CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
+            specializeCall.startCall("specializeAndExecute");
             specializeCall.string(nodeClassName(nextSpecialization) + ".class");
             addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true);
             specializeCall.end().end();
 
-            TypeData expectedType = currentSpecialization.getReturnType().getActualTypeData(currentSpecialization.getNode().getTypeSystem());
-            if (canThrowUnexpected) {
-                builder.startReturn();
-                startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType));
-                builder.tree(specializeCall.getRoot());
-                builder.end().end();
-                builder.end(); // return
-            } else {
-                builder.startReturn();
-                if (!expectedType.isVoid() && !expectedType.isGeneric()) {
-                    startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.asTypeMethodName(expectedType));
-                    builder.tree(specializeCall.getRoot());
-                    builder.end().end();
-                } else {
-                    builder.tree(specializeCall.getRoot());
-                }
-                builder.end();
-            }
-
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            builder.startReturn();
+            builder.tree(specializeCall.getRoot());
+            builder.end();
+            return builder.getRoot();
         }
 
         private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), specialization.getNode().getTypeSystem().getGenericType(), "specialize");
+            NodeData node = specialization.getNode();
+            TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
+            ExecutableTypeData returnExecutableType = node.findExecutableType(returnType);
+            boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext());
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
+            if (canThrowUnexpected) {
+                method.addThrownType(getUnexpectedValueException());
+            }
             addValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
             clazz.add(method);
 
             CodeTreeBuilder builder = method.createBuilder();
-            for (TemplateMethod listener : specialization.getNode().getSpecializationListeners()) {
-                builder.startStatement();
-                startCallOperationMethod(builder, listener);
-                addValueParameterNames(builder, listener, null, false);
-                builder.end().end(); // call operation
-                builder.end(); // statement
-            }
+
+            builder.tree(createDeoptimize(builder));
+            emitSpecializationListeners(builder, specialization.getNode());
 
             builder.startStatement();
             builder.startCall("replace");
@@ -922,20 +1357,24 @@
             builder.end(); // statement
 
             String generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization());
-
             ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName);
 
-            CodeTreeBuilder genericBuilder = CodeTreeBuilder.createBuilder();
-            genericBuilder.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
-            genericBuilder.string("this");
-            addValueParameterNames(genericBuilder, specialization.getNode().getGenericSpecialization(), null, true);
-            genericBuilder.end(); // call generated generic
+            CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
+            genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
+            genericExecute.string("this");
+            addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true);
+            genericExecute.end(); // call generated generic
+
+            CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
 
             if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
-                builder.declaration(generatedGeneric.getReturnType(), "genericResult", genericBuilder.getRoot());
-                builder.startReturn().string("null").end();
+                builder.statement(genericInvocation);
+
+                if (!Utils.isVoid(builder.findMethod().asType())) {
+                    builder.startReturn().defaultValue(returnType.getPrimitiveType()).end();
+                }
             } else {
-                builder.startReturn().tree(genericBuilder.getRoot()).end();
+                builder.startReturn().tree(genericInvocation).end();
             }
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Feb 26 11:55:00 2013 +0100
@@ -71,6 +71,17 @@
         return !noSpecialization;
     }
 
+    public List<NodeData> getNodeChildren() {
+        List<NodeData> children = new ArrayList<>();
+        for (NodeData child : getDeclaredChildren()) {
+            if (child.needsFactory()) {
+                children.add(child);
+            }
+            children.addAll(child.getNodeChildren());
+        }
+        return children;
+    }
+
     void setDeclaredChildren(List<NodeData> declaredChildren) {
         this.declaredChildren = declaredChildren;
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Feb 26 11:55:00 2013 +0100
@@ -52,6 +52,10 @@
         this.executionKind = executionKind;
     }
 
+    public boolean isShortCircuit() {
+        return executionKind == ExecutionKind.SHORT_CIRCUIT;
+    }
+
     public VariableElement getFieldElement() {
         return fieldElement;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Feb 26 11:55:00 2013 +0100
@@ -94,6 +94,7 @@
         if (rootNode != null) {
             rootNode.setDeclaredChildren(children);
         }
+
         return rootNode;
     }
 
@@ -118,20 +119,24 @@
             return null; // not a node
         }
 
+        if (type.getModifiers().contains(Modifier.PRIVATE)) {
+            return null; // not visible
+        }
+
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
         List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), type);
         Collections.reverse(typeHierarchy);
 
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            log.error(originalType, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName());
+            log.error(type, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName());
             return null;
         }
 
         TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value");
         final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
         if (typeSystem == null) {
-            log.error(originalType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
+            log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
             return null;
         }
 
@@ -146,8 +151,7 @@
 
         nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()]));
 
-        parsedNodes.put(Utils.getQualifiedName(type), nodeData); // node fields will resolve node
-        // types, to avoid endless loops
+        parsedNodes.put(Utils.getQualifiedName(type), nodeData);
 
         NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy);
         if (fields == null) {
@@ -179,7 +183,7 @@
         }
 
         if (specializations.size() > 1 && genericSpecialization == null) {
-            log.error(originalType, "Need a @%s method.", Generic.class.getSimpleName());
+            log.error(type, "Need a @%s method.", Generic.class.getSimpleName());
             return null;
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Feb 26 11:55:00 2013 +0100
@@ -124,15 +124,4 @@
         return false;
     }
 
-    public ActualParameter getPreviousParam(ActualParameter searchParam) {
-        ActualParameter prev = null;
-        for (ActualParameter param : getParameters()) {
-            if (param == searchParam) {
-                return prev;
-            }
-            prev = param;
-        }
-        return prev;
-    }
-
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Feb 26 11:55:00 2013 +0100
@@ -30,16 +30,25 @@
 
     private final ParameterSpec specification;
     private final TypeMirror actualType;
+    private TemplateMethod method;
 
     public ActualParameter(ParameterSpec specification, TypeMirror actualType) {
         this.specification = specification;
         this.actualType = actualType;
     }
 
+    void setMethod(TemplateMethod method) {
+        this.method = method;
+    }
+
     public ParameterSpec getSpecification() {
         return specification;
     }
 
+    public TemplateMethod getMethod() {
+        return method;
+    }
+
     public TypeMirror getActualType() {
         return actualType;
     }
@@ -47,4 +56,8 @@
     public TypeData getActualTypeData(TypeSystemData typeSystem) {
         return typeSystem.findTypeData(actualType);
     }
+
+    public ActualParameter getPreviousParameter() {
+        return method.getPreviousParam(this);
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Feb 26 11:55:00 2013 +0100
@@ -40,15 +40,16 @@
         this.markerAnnotation = markerAnnotation;
         this.returnType = returnType;
         this.parameters = parameters;
+
+        if (parameters != null) {
+            for (ActualParameter param : parameters) {
+                param.setMethod(this);
+            }
+        }
     }
 
     public TemplateMethod(TemplateMethod method) {
-        this.template = method.template;
-        this.specification = method.specification;
-        this.method = method.method;
-        this.markerAnnotation = method.markerAnnotation;
-        this.returnType = method.returnType;
-        this.parameters = method.parameters;
+        this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
     }
 
     public Template getTemplate() {
@@ -101,4 +102,15 @@
     public String toString() {
         return getClass().getSimpleName() + " [method = " + method + "]";
     }
+
+    public ActualParameter getPreviousParam(ActualParameter searchParam) {
+        ActualParameter prev = null;
+        for (ActualParameter param : getParameters()) {
+            if (param == searchParam) {
+                return prev;
+            }
+            prev = param;
+        }
+        return prev;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Tue Feb 26 11:55:00 2013 +0100
@@ -162,10 +162,7 @@
                 continue;
             }
 
-            TypeMirror boxedType = primitiveType;
-            if (boxedType.getKind().isPrimitive()) {
-                boxedType = processingEnv.getTypeUtils().boxedClass((PrimitiveType) boxedType).asType();
-            }
+            TypeMirror boxedType = Utils.boxType(context, primitiveType);
 
             if (Utils.typeEquals(boxedType, objectType)) {
                 log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain the generic type java.lang.Object.");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java	Tue Feb 26 11:55:00 2013 +0100
@@ -0,0 +1,52 @@
+/*
+ * 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.sl.test;
+
+import org.junit.*;
+
+// @formatter:off
+public class TernaryTest extends AbstractTest {
+
+    private static String[] INPUT = new String[] {
+"function main {  " +
+"  print #(1 < 2) ? 1 : 2;" +
+"  print #(2 < 1) ? 100000000000000 : 1;  ",
+"  print #(1 < 2) ? 100000000000000 : 1;  ",
+"  print #(2 < 1) ? \"wrong\" : \"true\";",
+"  print #(2 < 1) ? \"wrong\" : 1;",
+"}  ",
+    };
+
+    private static String[] OUTPUT = new String[] {
+        "1",
+        "1",
+        "100000000000000",
+        "true",
+        "1",
+    };
+
+    @Test
+    public void test() {
+        executeSL(INPUT, OUTPUT, true);
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Tue Feb 26 11:55:00 2013 +0100
@@ -127,4 +127,8 @@
         StatementNode write = WriteLocalNodeFactory.create(slot, value);
         return new ReturnNode(write);
     }
+
+    public TypedNode createTernary(TypedNode condition, TypedNode thenPart, TypedNode elsePart) {
+        return TernaryNodeFactory.create(condition, thenPart, elsePart);
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Tue Feb 26 11:55:00 2013 +0100
@@ -21,10 +21,9 @@
  * questions.
  */
 
-// The content of this file is automatically generated. DO NOT EDIT.
+ // The content of this file is automatically generated. DO NOT EDIT.
 
 package com.oracle.truffle.sl.parser;
-
 import java.util.*;
 
 import com.oracle.truffle.sl.*;
@@ -33,11 +32,11 @@
 // Checkstyle: stop
 // @formatter:off
 public class Parser {
-	public static final int _EOF = 0;
-	public static final int _identifier = 1;
-	public static final int _stringLiteral = 2;
-	public static final int _numericLiteral = 3;
-	public static final int maxT = 25;
+	public static final int _EOF = 0;
+	public static final int _identifier = 1;
+	public static final int _stringLiteral = 2;
+	public static final int _numericLiteral = 3;
+	public static final int maxT = 28;
 
     static final boolean T = true;
     static final boolean x = false;
@@ -50,7 +49,7 @@
     public final Scanner scanner;
     public final Errors errors;
     private final NodeFactory factory;
-
+    
     public Parser(Scanner scanner, NodeFactory factory) {
         this.scanner = scanner;
         this.factory = factory;
@@ -121,226 +120,255 @@
         }
     }
 
-	void SimpleLanguage() {
-		Function();
-		while (la.kind == 4) {
-			Function();
-		}
-	}
-
-	void Function() {
-		Expect(4);
-		factory.startFunction();
-		Expect(1);
-		String name = t.val;
-		StatementNode body = Block();
-		factory.createFunction(body, name);
-	}
-
-	StatementNode  Block() {
-		StatementNode  result;
-		List<StatementNode> statements = new ArrayList<>();
-		Expect(5);
-		while (StartOf(1)) {
-			StatementNode statement = Statement();
-			statements.add(statement);
-		}
-		Expect(6);
-		result = factory.createBlock(statements);
-		return result;
-	}
-
-	StatementNode  Statement() {
-		StatementNode  result;
-		result = null;
-		if (la.kind == 7) {
-			result = WhileStatement();
-		} else if (la.kind == 1) {
-			result = AssignmentStatement();
-		} else if (la.kind == 12) {
-			result = OutputStatement();
-		} else if (la.kind == 13) {
-			result = ReturnStatement();
-		} else SynErr(26);
-		return result;
-	}
-
-	StatementNode  WhileStatement() {
-		StatementNode  result;
-		Expect(7);
-		Expect(8);
-		ConditionNode condition = Expression();
-		Expect(9);
-		StatementNode body = Block();
-		result = factory.createWhile(condition, body);
-		return result;
-	}
-
-	StatementNode  AssignmentStatement() {
-		StatementNode  result;
-		Expect(1);
-		String name = t.val;
-		Expect(10);
-		TypedNode rvalue = Expression();
-		Expect(11);
-		result = factory.createAssignment(name, rvalue);
-		return result;
-	}
-
-	StatementNode  OutputStatement() {
-		StatementNode  result;
-		List<TypedNode> expressions = new ArrayList<>();
-		Expect(12);
-		while (StartOf(2)) {
-			TypedNode value = Expression();
-			expressions.add(value);
-		}
-		Expect(11);
-		result = factory.createPrint(expressions);
-		return result;
-	}
-
-	StatementNode  ReturnStatement() {
-		StatementNode  result;
-		Expect(13);
-		TypedNode value = Expression();
-		Expect(11);
-		result = factory.createReturn(value);
-		return result;
-	}
-
-	TypedNode  Expression() {
-		TypedNode  result;
-		result = ValueExpression();
-		if (StartOf(3)) {
-			switch (la.kind) {
-			case 14: {
-				Get();
-				break;
-			}
-			case 15: {
-				Get();
-				break;
-			}
-			case 16: {
-				Get();
-				break;
-			}
-			case 17: {
-				Get();
-				break;
-			}
-			case 18: {
-				Get();
-				break;
-			}
-			case 19: {
-				Get();
-				break;
-			}
-			}
-			String op = t.val;
-			TypedNode right = ValueExpression();
-			result = factory.createBinary(op, result, right);
-		}
-		return result;
-	}
-
-	TypedNode  ValueExpression() {
-		TypedNode  result;
-		result = Term();
-		while (la.kind == 20 || la.kind == 21) {
-			if (la.kind == 20) {
-				Get();
-			} else {
-				Get();
-			}
-			String op = t.val;
-			TypedNode right = Term();
-			result = factory.createBinary(op, result, right);
-		}
-		return result;
-	}
-
-	TypedNode  Term() {
-		TypedNode  result;
-		result = Factor();
-		while (la.kind == 22 || la.kind == 23) {
-			if (la.kind == 22) {
-				Get();
-			} else {
-				Get();
-			}
-			String op = t.val;
-			TypedNode right = Factor();
-			result = factory.createBinary(op, result, right);
-		}
-		return result;
-	}
-
-	TypedNode  Factor() {
-		TypedNode  result;
-		result = null;
-		if (la.kind == 24) {
-			result = TimeRef();
-		} else if (la.kind == 1) {
-			result = VariableRef();
-		} else if (la.kind == 2) {
-			result = StringLiteral();
-		} else if (la.kind == 3) {
-			result = NumericLiteral();
-		} else if (la.kind == 8) {
-			Get();
-			result = Expression();
-			Expect(9);
-		} else SynErr(27);
-		return result;
-	}
-
-	TypedNode  TimeRef() {
-		TypedNode  result;
-		Expect(24);
-		result = factory.createTime();
-		return result;
-	}
-
-	TypedNode  VariableRef() {
-		TypedNode  result;
-		Expect(1);
-		result = factory.createLocal(t.val);
-		return result;
-	}
-
-	TypedNode  StringLiteral() {
-		TypedNode  result;
-		Expect(2);
-		result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1));
-		return result;
-	}
-
-	TypedNode  NumericLiteral() {
-		TypedNode  result;
-		Expect(3);
-		result = factory.createNumericLiteral(t.val);
-		return result;
-	}
-
+	void SimpleLanguage() {
+		Function();
+		while (la.kind == 4) {
+			Function();
+		}
+	}
+
+	void Function() {
+		Expect(4);
+		factory.startFunction(); 
+		Expect(1);
+		String name = t.val; 
+		StatementNode body = Block();
+		factory.createFunction(body, name); 
+	}
+
+	StatementNode  Block() {
+		StatementNode  result;
+		List<StatementNode> statements = new ArrayList<>(); 
+		Expect(5);
+		while (StartOf(1)) {
+			StatementNode statement = Statement();
+			statements.add(statement); 
+		}
+		Expect(6);
+		result = factory.createBlock(statements); 
+		return result;
+	}
+
+	StatementNode  Statement() {
+		StatementNode  result;
+		result = null; 
+		if (la.kind == 7) {
+			result = WhileStatement();
+		} else if (la.kind == 1) {
+			result = AssignmentStatement();
+		} else if (la.kind == 12) {
+			result = OutputStatement();
+		} else if (la.kind == 13) {
+			result = ReturnStatement();
+		} else SynErr(29);
+		return result;
+	}
+
+	StatementNode  WhileStatement() {
+		StatementNode  result;
+		Expect(7);
+		Expect(8);
+		ConditionNode condition = Expression();
+		Expect(9);
+		StatementNode body = Block();
+		result = factory.createWhile(condition, body); 
+		return result;
+	}
+
+	StatementNode  AssignmentStatement() {
+		StatementNode  result;
+		Expect(1);
+		String name = t.val; 
+		Expect(10);
+		TypedNode rvalue = Expression();
+		Expect(11);
+		result = factory.createAssignment(name, rvalue); 
+		return result;
+	}
+
+	StatementNode  OutputStatement() {
+		StatementNode  result;
+		List<TypedNode> expressions = new ArrayList<>(); 
+		Expect(12);
+		while (StartOf(2)) {
+			TypedNode value = Expression();
+			expressions.add(value); 
+		}
+		Expect(11);
+		result = factory.createPrint(expressions); 
+		return result;
+	}
+
+	StatementNode  ReturnStatement() {
+		StatementNode  result;
+		Expect(13);
+		TypedNode value = Expression();
+		Expect(11);
+		result = factory.createReturn(value); 
+		return result;
+	}
+
+	TypedNode  Expression() {
+		TypedNode  result;
+		result = ValueExpression();
+		if (StartOf(3)) {
+			switch (la.kind) {
+			case 14: {
+				Get();
+				break;
+			}
+			case 15: {
+				Get();
+				break;
+			}
+			case 16: {
+				Get();
+				break;
+			}
+			case 17: {
+				Get();
+				break;
+			}
+			case 18: {
+				Get();
+				break;
+			}
+			case 19: {
+				Get();
+				break;
+			}
+			}
+			String op = t.val; 
+			TypedNode right = ValueExpression();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  ValueExpression() {
+		TypedNode  result;
+		result = Term();
+		while (la.kind == 20 || la.kind == 21) {
+			if (la.kind == 20) {
+				Get();
+			} else {
+				Get();
+			}
+			String op = t.val; 
+			TypedNode right = Term();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  Term() {
+		TypedNode  result;
+		result = Factor();
+		while (la.kind == 22 || la.kind == 23) {
+			if (la.kind == 22) {
+				Get();
+			} else {
+				Get();
+			}
+			String op = t.val; 
+			TypedNode right = Factor();
+			result = factory.createBinary(op, result, right); 
+		}
+		return result;
+	}
+
+	TypedNode  Factor() {
+		TypedNode  result;
+		result = null; 
+		switch (la.kind) {
+		case 27: {
+			result = TimeRef();
+			break;
+		}
+		case 1: {
+			result = VariableRef();
+			break;
+		}
+		case 2: {
+			result = StringLiteral();
+			break;
+		}
+		case 3: {
+			result = NumericLiteral();
+			break;
+		}
+		case 24: {
+			result = Ternary();
+			break;
+		}
+		case 8: {
+			Get();
+			result = Expression();
+			Expect(9);
+			break;
+		}
+		default: SynErr(30); break;
+		}
+		return result;
+	}
+
+	TypedNode  TimeRef() {
+		TypedNode  result;
+		Expect(27);
+		result = factory.createTime(); 
+		return result;
+	}
+
+	TypedNode  VariableRef() {
+		TypedNode  result;
+		Expect(1);
+		result = factory.createLocal(t.val); 
+		return result;
+	}
+
+	TypedNode  StringLiteral() {
+		TypedNode  result;
+		Expect(2);
+		result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); 
+		return result;
+	}
+
+	TypedNode  NumericLiteral() {
+		TypedNode  result;
+		Expect(3);
+		result = factory.createNumericLiteral(t.val); 
+		return result;
+	}
+
+	TypedNode  Ternary() {
+		TypedNode  result;
+		TypedNode condition, thenPart, elsePart; 
+		Expect(24);
+		condition = Expression();
+		Expect(25);
+		thenPart = Expression();
+		Expect(26);
+		elsePart = Expression();
+		result = factory.createTernary(condition, thenPart, elsePart); 
+		return result;
+	}
+
 
 
     public void Parse() {
         la = new Token();
         la.val = "";
         Get();
-		SimpleLanguage();
-		Expect(0);
+		SimpleLanguage();
+		Expect(0);
 
     }
 
     private static final boolean[][] set = {
-		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
-		{x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x},
-		{x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x},
-		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x}
+		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+		{x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+		{x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, x,x},
+		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x}
 
     };
 
@@ -388,35 +416,38 @@
 
     public void SynErr(int line, int col, int n) {
         String s;
-        switch (n) {
-			case 0: s = "EOF expected"; break;
-			case 1: s = "identifier expected"; break;
-			case 2: s = "stringLiteral expected"; break;
-			case 3: s = "numericLiteral expected"; break;
-			case 4: s = "\"function\" expected"; break;
-			case 5: s = "\"{\" expected"; break;
-			case 6: s = "\"}\" expected"; break;
-			case 7: s = "\"while\" expected"; break;
-			case 8: s = "\"(\" expected"; break;
-			case 9: s = "\")\" expected"; break;
-			case 10: s = "\"=\" expected"; break;
-			case 11: s = "\";\" expected"; break;
-			case 12: s = "\"print\" expected"; break;
-			case 13: s = "\"return\" expected"; break;
-			case 14: s = "\"<\" expected"; break;
-			case 15: s = "\">\" expected"; break;
-			case 16: s = "\"<=\" expected"; break;
-			case 17: s = "\">=\" expected"; break;
-			case 18: s = "\"==\" expected"; break;
-			case 19: s = "\"!=\" expected"; break;
-			case 20: s = "\"+\" expected"; break;
-			case 21: s = "\"-\" expected"; break;
-			case 22: s = "\"*\" expected"; break;
-			case 23: s = "\"/\" expected"; break;
-			case 24: s = "\"time\" expected"; break;
-			case 25: s = "??? expected"; break;
-			case 26: s = "invalid Statement"; break;
-			case 27: s = "invalid Factor"; break;
+        switch (n) {
+			case 0: s = "EOF expected"; break;
+			case 1: s = "identifier expected"; break;
+			case 2: s = "stringLiteral expected"; break;
+			case 3: s = "numericLiteral expected"; break;
+			case 4: s = "\"function\" expected"; break;
+			case 5: s = "\"{\" expected"; break;
+			case 6: s = "\"}\" expected"; break;
+			case 7: s = "\"while\" expected"; break;
+			case 8: s = "\"(\" expected"; break;
+			case 9: s = "\")\" expected"; break;
+			case 10: s = "\"=\" expected"; break;
+			case 11: s = "\";\" expected"; break;
+			case 12: s = "\"print\" expected"; break;
+			case 13: s = "\"return\" expected"; break;
+			case 14: s = "\"<\" expected"; break;
+			case 15: s = "\">\" expected"; break;
+			case 16: s = "\"<=\" expected"; break;
+			case 17: s = "\">=\" expected"; break;
+			case 18: s = "\"==\" expected"; break;
+			case 19: s = "\"!=\" expected"; break;
+			case 20: s = "\"+\" expected"; break;
+			case 21: s = "\"-\" expected"; break;
+			case 22: s = "\"*\" expected"; break;
+			case 23: s = "\"/\" expected"; break;
+			case 24: s = "\"#\" expected"; break;
+			case 25: s = "\"?\" expected"; break;
+			case 26: s = "\":\" expected"; break;
+			case 27: s = "\"time\" expected"; break;
+			case 28: s = "??? expected"; break;
+			case 29: s = "invalid Statement"; break;
+			case 30: s = "invalid Factor"; break;
             default:
                 s = "error " + n;
                 break;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Tue Feb 26 11:55:00 2013 +0100
@@ -311,8 +311,8 @@
 
     static final char EOL = '\n';
     static final int eofSym = 0;
-	static final int maxT = 25;
-	static final int noSym = 25;
+	static final int maxT = 28;
+	static final int noSym = 28;
 
 
     public Buffer buffer; // scanner buffer
@@ -339,27 +339,30 @@
 		for (int i = 65; i <= 90; ++i) start.set(i, 1);
 		for (int i = 97; i <= 122; ++i) start.set(i, 1);
 		for (int i = 49; i <= 57; ++i) start.set(i, 4);
-		start.set(34, 2);
-		start.set(48, 5);
-		start.set(123, 6);
-		start.set(125, 7);
-		start.set(40, 8);
-		start.set(41, 9);
-		start.set(61, 20);
-		start.set(59, 10);
-		start.set(60, 21);
-		start.set(62, 22);
-		start.set(33, 14);
-		start.set(43, 16);
-		start.set(45, 17);
-		start.set(42, 18);
-		start.set(47, 19);
+		start.set(34, 2); 
+		start.set(48, 5); 
+		start.set(123, 6); 
+		start.set(125, 7); 
+		start.set(40, 8); 
+		start.set(41, 9); 
+		start.set(61, 23); 
+		start.set(59, 10); 
+		start.set(60, 24); 
+		start.set(62, 25); 
+		start.set(33, 14); 
+		start.set(43, 16); 
+		start.set(45, 17); 
+		start.set(42, 18); 
+		start.set(47, 19); 
+		start.set(35, 20); 
+		start.set(63, 21); 
+		start.set(58, 22); 
 		start.set(Buffer.EOF, -1);
 		literals.put("function", new Integer(4));
 		literals.put("while", new Integer(7));
 		literals.put("print", new Integer(12));
 		literals.put("return", new Integer(13));
-		literals.put("time", new Integer(24));
+		literals.put("time", new Integer(27));
 
     }
 
@@ -425,7 +428,7 @@
             tval = newBuf;
         }
         if (ch != Buffer.EOF) {
-			tval[tlen++] = (char)ch;
+			tval[tlen++] = (char)ch; 
 
             NextCh();
         }
@@ -484,9 +487,9 @@
     }
 
     Token NextToken() {
-        while (ch == ' ' ||
+        while (ch == ' ' || 
 			ch >= 9 && ch <= 10 || ch == 13
-		) NextCh();
+        ) NextCh();
 		if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken();
         int recKind = noSym;
         int recEnd = pos;
@@ -515,60 +518,66 @@
                 } // NextCh already done
 				case 1:
 					recEnd = pos; recKind = 1;
-					if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;}
+					if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;}
 					else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
 				case 2:
-					if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;}
-					else if (ch == '"') {AddCh(); state = 3; break;}
+					if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;}
+					else if (ch == '"') {AddCh(); state = 3; break;}
 					else {state = 0; break;}
-				case 3:
+				case 3:
 					{t.kind = 2; break loop;}
 				case 4:
 					recEnd = pos; recKind = 3;
-					if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;}
+					if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;}
 					else {t.kind = 3; break loop;}
-				case 5:
+				case 5:
 					{t.kind = 3; break loop;}
-				case 6:
+				case 6:
 					{t.kind = 5; break loop;}
-				case 7:
+				case 7:
 					{t.kind = 6; break loop;}
-				case 8:
+				case 8:
 					{t.kind = 8; break loop;}
-				case 9:
+				case 9:
 					{t.kind = 9; break loop;}
-				case 10:
+				case 10:
 					{t.kind = 11; break loop;}
-				case 11:
+				case 11:
 					{t.kind = 16; break loop;}
-				case 12:
+				case 12:
 					{t.kind = 17; break loop;}
-				case 13:
+				case 13:
 					{t.kind = 18; break loop;}
 				case 14:
-					if (ch == '=') {AddCh(); state = 15; break;}
+					if (ch == '=') {AddCh(); state = 15; break;}
 					else {state = 0; break;}
-				case 15:
+				case 15:
 					{t.kind = 19; break loop;}
-				case 16:
+				case 16:
 					{t.kind = 20; break loop;}
-				case 17:
+				case 17:
 					{t.kind = 21; break loop;}
-				case 18:
+				case 18:
 					{t.kind = 22; break loop;}
-				case 19:
+				case 19:
 					{t.kind = 23; break loop;}
-				case 20:
+				case 20:
+					{t.kind = 24; break loop;}
+				case 21:
+					{t.kind = 25; break loop;}
+				case 22:
+					{t.kind = 26; break loop;}
+				case 23:
 					recEnd = pos; recKind = 10;
-					if (ch == '=') {AddCh(); state = 13; break;}
+					if (ch == '=') {AddCh(); state = 13; break;}
 					else {t.kind = 10; break loop;}
-				case 21:
+				case 24:
 					recEnd = pos; recKind = 14;
-					if (ch == '=') {AddCh(); state = 11; break;}
+					if (ch == '=') {AddCh(); state = 11; break;}
 					else {t.kind = 14; break loop;}
-				case 22:
+				case 25:
 					recEnd = pos; recKind = 15;
-					if (ch == '=') {AddCh(); state = 12; break;}
+					if (ch == '=') {AddCh(); state = 12; break;}
 					else {t.kind = 15; break loop;}
 
             }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Mon Feb 25 18:19:53 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Tue Feb 26 11:55:00 2013 +0100
@@ -131,11 +131,19 @@
 |
     NumericLiteral<out result>
 |
+	Ternary<out result>  
+|
     "(" Expression<out result> ")"
-)
+) 
 .
 
-TimeRef<out TypedNode result>
+Ternary<out TypedNode result>					(. TypedNode condition, thenPart, elsePart; .)
+=
+"#" Expression<out condition> "?" Expression<out thenPart> ":" Expression<out elsePart>
+												(. result = factory.createTernary(condition, thenPart, elsePart); .)
+.
+
+TimeRef<out TypedNode result> 
 =
 "time"                                          (. result = factory.createTime(); .)
 .