changeset 7849:268d3e74191e

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 19 Feb 2013 17:41:10 +0100
parents 698cd036a1ca (diff) 8959b331ef3e (current diff)
children 85891f9c2197
files src/share/vm/graal/graalVmIds.cpp src/share/vm/graal/graalVmIds.hpp
diffstat 15 files changed, 934 insertions(+), 505 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Tue Feb 19 17:41:10 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/ast/CodeExecutableElement.java	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Feb 19 17:41:10 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() {
@@ -358,6 +369,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 +390,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 +451,7 @@
     }
 
     public CodeTreeBuilder create() {
-        return new CodeTreeBuilder();
+        return new CodeTreeBuilder(null);
     }
 
     public CodeTreeBuilder type(TypeMirror type) {
@@ -496,7 +514,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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Feb 19 17:41:10 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();
     }
@@ -474,9 +480,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 +515,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 +571,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 +605,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 +631,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/node/NodeCodeGenerator.java	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Feb 19 17:41:10 2013 +0100
@@ -69,7 +69,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 +83,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 +93,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 +110,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 +127,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 +189,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 +206,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
@@ -436,17 +621,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 +670,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 +697,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 +804,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 +819,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 +926,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 +972,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 +1008,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 +1034,7 @@
                         execute = true;
                     }
                 }
-                buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), param.getSpecification());
+                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification()));
                 builder.end(); // catch block
             }
 
@@ -846,7 +1060,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 +1069,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 +1082,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 +1124,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/NodeFieldData.java	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Feb 19 17:41:10 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/SpecializationData.java	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Feb 19 17:41:10 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;
+    }
 }
--- /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 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Tue Feb 19 17:41:10 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	Tue Feb 19 16:03:11 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Tue Feb 19 17:41:10 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(); .)
 .