Commits

Michael Ludwig  committed 7e3d62d

Complete impl. of DoWhileLoop, Constant, Assignment, BinaryExpression, and ArrayAccess. BinaryExpression and ArrayAccess properly identify resulting types and support matrix/vector operations.

  • Participants
  • Parent commits f907925

Comments (0)

Files changed (5)

File ferox-renderer/ferox-renderer-api/src/main/java/com/ferox/resource/shader/simple_grammar/ArrayAccess.java

 import com.ferox.resource.shader.Environment;
 import com.ferox.resource.shader.Expression;
 import com.ferox.resource.shader.PrimitiveType;
-import com.ferox.resource.shader.ShaderAccumulator;
 import com.ferox.resource.shader.Type;
 
 public class ArrayAccess extends AbstractLValue {
 
     @Override
     public Type getType(Environment env) {
+        Type type = array.getType(env);
+        if (type.equals(PrimitiveType.BVEC2) || type.equals(PrimitiveType.BVEC3) || type.equals(PrimitiveType.BVEC4)) {
+            return PrimitiveType.BOOL;
+        } else if (type.equals(PrimitiveType.IVEC2) || type.equals(PrimitiveType.IVEC3) || type.equals(PrimitiveType.IVEC4)) {
+            return PrimitiveType.INT;
+        } else if (type.equals(PrimitiveType.VEC2) || type.equals(PrimitiveType.VEC3) || type.equals(PrimitiveType.VEC4)) {
+            return PrimitiveType.FLOAT;
+        } else if (type.equals(PrimitiveType.MAT2)) {
+            return PrimitiveType.VEC2;
+        } else if (type.equals(PrimitiveType.MAT3)) {
+            return PrimitiveType.VEC3;
+        } else if (type.equals(PrimitiveType.MAT4)) {
+            return PrimitiveType.VEC4;
+        }
+        // assume it's an array
         return ((ArrayType) array.getType(env)).getComponentType();
     }
 
     @Override
     public Environment validate(Environment environment) {
         environment = array.validate(index.validate(environment));
-        if (!(array.getType(environment) instanceof ArrayType)) {
+        Type type = array.getType(environment);
+
+        if (type instanceof PrimitiveType) {
+            switch ((PrimitiveType) type) {
+            case BVEC2:
+            case BVEC3:
+            case BVEC4:
+            case IVEC2:
+            case IVEC3:
+            case IVEC4:
+            case VEC2:
+            case VEC3:
+            case VEC4:
+            case MAT2:
+            case MAT3:
+            case MAT4:
+                // array-accessible primitive types
+                break;
+            default:
+                throw new IllegalStateException("Primitive type does not support array access");
+            }
+        } else if (!(array.getType(environment) instanceof ArrayType)) {
             throw new IllegalStateException("Expression does not evaluate to an array type");
-        } else if (!index.getType(environment).equals(PrimitiveType.INT)) {
+        }
+
+        if (!index.getType(environment).equals(PrimitiveType.INT)) {
             throw new IllegalStateException("Index expression does not evaluate to an integer type");
         }
+        if (array.containsDeclaration() || index.containsDeclaration()) {
+            throw new IllegalStateException("Array and index expressions cannot contain variable declarations");
+        }
         return environment;
     }
 
     @Override
-    public void emit(ShaderAccumulator accumulator) {
-        // TODO Auto-generated method stub
+    public String emitExpression() {
+        if (array.getPrecedence() < getPrecedence()) {
+            return "(" + array.emitExpression() + ")[" + index.emitExpression() + "]";
+        } else {
+            return array.emitExpression() + "[" + index.emitExpression() + "]";
+        }
+    }
 
+    @Override
+    public int getPrecedence() {
+        return Precedence.POSTFIX_EXPRESSIONS.ordinal();
     }
 }

File ferox-renderer/ferox-renderer-api/src/main/java/com/ferox/resource/shader/simple_grammar/Assignment.java

 import com.ferox.resource.shader.Environment;
 import com.ferox.resource.shader.Expression;
 import com.ferox.resource.shader.LValue;
-import com.ferox.resource.shader.ShaderAccumulator;
-import com.ferox.resource.shader.Statement;
+import com.ferox.resource.shader.Type;
 
-public class Assignment implements Statement, RightAssociative {
+public class Assignment extends AbstractExpression {
     private final LValue lvalue;
     private final Expression rvalue;
 
         if (!lvalue.getType(environment).equals(rvalue.getType(environment))) {
             throw new IllegalStateException("Value does not have same type as variable");
         }
+        if (rvalue.containsDeclaration()) {
+            throw new IllegalStateException("Value expression cannot contain a declaration");
+        }
         return environment;
     }
 
     @Override
-    public void emit(ShaderAccumulator accumulator) {
-        // TODO Auto-generated method stub
+    public Type getType(Environment env) {
+        return lvalue.getType(env);
+    }
 
+    @Override
+    public String emitExpression() {
+        // we do not need to contain either expression in parentheses because
+        // the assignment expression has the lowest precedence
+        return lvalue.emitExpression() + " = " + rvalue.emitExpression();
+    }
+
+    @Override
+    public boolean containsDeclaration() {
+        return lvalue.containsDeclaration();
+    }
+
+    @Override
+    public int getPrecedence() {
+        return Precedence.ASSIGNMENT_EXPRESSIONS.ordinal();
     }
 }

File ferox-renderer/ferox-renderer-api/src/main/java/com/ferox/resource/shader/simple_grammar/BinaryExpression.java

 package com.ferox.resource.shader.simple_grammar;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import com.ferox.resource.shader.Environment;
 import com.ferox.resource.shader.Expression;
-import com.ferox.resource.shader.ShaderAccumulator;
+import com.ferox.resource.shader.PrimitiveType;
 import com.ferox.resource.shader.Type;
 
-public class BinaryExpression extends AbstractExpression implements LeftAssociative {
+public class BinaryExpression extends AbstractExpression {
     public static enum BinaryOperator {
-        MULTIPLY,
-        DIVIDE,
-        MODULO,
-        ADD,
-        SUBTRACT,
-        LEFT_SHIFT,
-        RIGHT_SHIFT,
-        LESS_THAN,
-        GREATER_THAN,
-        LESS_THAN_OR_EQUAL,
-        GREATER_THAN_OR_EQUAL,
-        EQUAL,
-        NOT_EQUAL,
-        LOGICAL_AND,
-        LOGICAL_XOR,
-        LOGICAL_OR
-        // FIXME insert bitwise AND, XOR, and OR
+        MULTIPLY("*"),
+        DIVIDE("/"),
+        ADD("+"),
+        SUBTRACT("-"),
+        MODULO("%"),
+        LEFT_SHIFT("<<"),
+        RIGHT_SHIFT(">>"),
+        LESS_THAN("<"),
+        GREATER_THAN(">"),
+        LESS_THAN_OR_EQUAL("<="),
+        GREATER_THAN_OR_EQUAL(">="),
+        EQUAL("=="),
+        NOT_EQUAL("!="),
+        LOGICAL_AND("&&"),
+        LOGICAL_XOR("^"),
+        LOGICAL_OR("||");
+        // FIXME add bitwise AND, XOR, and OR
+
+        private BinaryOperator(String symbol) {
+            this.symbol = symbol;
+        }
+
+        private String symbol;
     }
 
     private final Expression left;
 
     @Override
     public Type getType(Environment env) {
-        // TODO Auto-generated method stub
-        return null;
+        return get((PrimitiveType) left.getType(env), operator,
+                   (PrimitiveType) right.getType(env));
     }
 
     @Override
     public Environment validate(Environment environment) {
-        // TODO Auto-generated method stub
+        environment = right.validate(left.validate(environment));
+
+        Type rightType = right.getType(environment);
+        Type leftType = left.getType(environment);
+
+        if (!(rightType instanceof PrimitiveType) || !(leftType instanceof PrimitiveType)) {
+            throw new IllegalStateException("Binary expressions only operate on primitive types");
+        }
+        if (get((PrimitiveType) leftType, operator, (PrimitiveType) rightType) == null) {
+            throw new IllegalStateException("Binary operator not supported with left and right expressions");
+        }
+
+        return environment;
+    }
+
+    @Override
+    public String emitExpression() {
+        StringBuilder sb = new StringBuilder();
+        if (left.getPrecedence() < getPrecedence()) {
+            sb.append('(');
+            sb.append(left.emitExpression());
+            sb.append(')');
+        } else {
+            sb.append(left.emitExpression());
+        }
+
+        sb.append(' ');
+        sb.append(operator.symbol);
+        sb.append(' ');
+
+        if (right.getPrecedence() < getPrecedence()) {
+            sb.append('(');
+            sb.append(right.emitExpression());
+            sb.append(')');
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    public int getPrecedence() {
+        switch (operator) {
+        case ADD:
+        case SUBTRACT:
+            return Precedence.ADDITIVE_EXPRESSIONS.ordinal();
+        case MULTIPLY:
+        case DIVIDE:
+        case MODULO:
+            return Precedence.MULTIPLICATIVE_EXPRESSIONS.ordinal();
+        case EQUAL:
+        case NOT_EQUAL:
+            return Precedence.EQUALITY_EXPERSSIONS.ordinal();
+        case GREATER_THAN:
+        case GREATER_THAN_OR_EQUAL:
+        case LESS_THAN:
+        case LESS_THAN_OR_EQUAL:
+            return Precedence.RELATIONAL_EXPRESSIONS.ordinal();
+        case LEFT_SHIFT:
+        case RIGHT_SHIFT:
+            return Precedence.SHIFT_EXPRESSIONS.ordinal();
+        case LOGICAL_AND:
+            return Precedence.LOGICAL_AND_EXPRESSIONS.ordinal();
+        case LOGICAL_OR:
+            return Precedence.LOGICAL_OR_EXPRESSIONS.ordinal();
+        case LOGICAL_XOR:
+            return Precedence.LOGICAL_XOR_EXPRESSIONS.ordinal();
+        default:
+            throw new UnsupportedOperationException("Unmapped binary operator, no precedence available");
+        }
+    }
+
+    private static final Map<BinaryOperator, Map<PrimitiveType, Map<PrimitiveType, PrimitiveType>>> operatorMap = new HashMap<BinaryExpression.BinaryOperator, Map<PrimitiveType, Map<PrimitiveType, PrimitiveType>>>();
+
+    private static void add(PrimitiveType leftType, BinaryOperator op,
+                            PrimitiveType rightType, PrimitiveType resultType) {
+        Map<PrimitiveType, Map<PrimitiveType, PrimitiveType>> typeMap = operatorMap.get(op);
+        if (typeMap == null) {
+            typeMap = new HashMap<PrimitiveType, Map<PrimitiveType, PrimitiveType>>();
+            operatorMap.put(op, typeMap);
+        }
+
+        Map<PrimitiveType, PrimitiveType> resMap = typeMap.get(leftType);
+        if (resMap == null) {
+            resMap = new HashMap<PrimitiveType, PrimitiveType>();
+            typeMap.put(leftType, resMap);
+        }
+
+        resMap.put(rightType, resultType);
+    }
+
+    private static PrimitiveType get(PrimitiveType leftType, BinaryOperator op,
+                                     PrimitiveType rightType) {
+        Map<PrimitiveType, Map<PrimitiveType, PrimitiveType>> typeMap = operatorMap.get(op);
+        if (typeMap != null) {
+            Map<PrimitiveType, PrimitiveType> resMap = typeMap.get(leftType);
+            if (resMap != null) {
+                return resMap.get(rightType);
+            }
+
+            // for simplicity in operator definition, consider them commutative
+            resMap = typeMap.get(rightType);
+            if (resMap != null) {
+                return resMap.get(leftType);
+            }
+        }
+
         return null;
     }
 
-    @Override
-    public void emit(ShaderAccumulator accumulator) {
-        // TODO Auto-generated method stub
+    static {
+        // float to float operations
+        add(PrimitiveType.FLOAT, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.FLOAT);
+        add(PrimitiveType.FLOAT, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.FLOAT);
+        add(PrimitiveType.FLOAT, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.FLOAT);
+        add(PrimitiveType.FLOAT, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.FLOAT);
 
+        add(PrimitiveType.FLOAT, BinaryOperator.LESS_THAN, PrimitiveType.FLOAT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.FLOAT, BinaryOperator.LESS_THAN_OR_EQUAL, PrimitiveType.FLOAT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.FLOAT, BinaryOperator.GREATER_THAN, PrimitiveType.FLOAT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.FLOAT, BinaryOperator.GREATER_THAN_OR_EQUAL,
+            PrimitiveType.FLOAT, PrimitiveType.BOOL);
+        add(PrimitiveType.FLOAT, BinaryOperator.EQUAL, PrimitiveType.FLOAT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.FLOAT, BinaryOperator.NOT_EQUAL, PrimitiveType.FLOAT,
+            PrimitiveType.BOOL);
+
+        // int to int operations
+        add(PrimitiveType.INT, BinaryOperator.MULTIPLY, PrimitiveType.INT,
+            PrimitiveType.INT);
+        add(PrimitiveType.INT, BinaryOperator.DIVIDE, PrimitiveType.INT,
+            PrimitiveType.INT);
+        add(PrimitiveType.INT, BinaryOperator.ADD, PrimitiveType.INT, PrimitiveType.INT);
+        add(PrimitiveType.INT, BinaryOperator.SUBTRACT, PrimitiveType.INT,
+            PrimitiveType.INT);
+
+        add(PrimitiveType.INT, BinaryOperator.MODULO, PrimitiveType.INT,
+            PrimitiveType.INT);
+        add(PrimitiveType.INT, BinaryOperator.LEFT_SHIFT, PrimitiveType.INT,
+            PrimitiveType.INT);
+        add(PrimitiveType.INT, BinaryOperator.RIGHT_SHIFT, PrimitiveType.INT,
+            PrimitiveType.INT);
+
+        add(PrimitiveType.INT, BinaryOperator.LESS_THAN, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.INT, BinaryOperator.LESS_THAN_OR_EQUAL, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.INT, BinaryOperator.GREATER_THAN, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.INT, BinaryOperator.GREATER_THAN_OR_EQUAL, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.INT, BinaryOperator.EQUAL, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.INT, BinaryOperator.NOT_EQUAL, PrimitiveType.INT,
+            PrimitiveType.BOOL);
+
+        // boolean operations
+        add(PrimitiveType.BOOL, BinaryOperator.LOGICAL_AND, PrimitiveType.BOOL,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BOOL, BinaryOperator.LOGICAL_OR, PrimitiveType.BOOL,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BOOL, BinaryOperator.LOGICAL_XOR, PrimitiveType.BOOL,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BOOL, BinaryOperator.EQUAL, PrimitiveType.BOOL,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BOOL, BinaryOperator.NOT_EQUAL, PrimitiveType.BOOL,
+            PrimitiveType.BOOL);
+
+        // vec2 operations
+        add(PrimitiveType.VEC2, BinaryOperator.MULTIPLY, PrimitiveType.VEC2,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.DIVIDE, PrimitiveType.VEC2,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.ADD, PrimitiveType.VEC2,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.SUBTRACT, PrimitiveType.VEC2,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.MULTIPLY, PrimitiveType.IVEC2,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.DIVIDE, PrimitiveType.IVEC2,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.ADD, PrimitiveType.IVEC2,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.SUBTRACT, PrimitiveType.IVEC2,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_AND, PrimitiveType.BVEC2,
+            PrimitiveType.BVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_OR, PrimitiveType.BVEC2,
+            PrimitiveType.BVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_XOR, PrimitiveType.BVEC2,
+            PrimitiveType.BVEC2);
+
+        add(PrimitiveType.VEC2, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.VEC2, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.VEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.MULTIPLY, PrimitiveType.INT,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.DIVIDE, PrimitiveType.INT,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.ADD, PrimitiveType.INT,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.IVEC2, BinaryOperator.SUBTRACT, PrimitiveType.INT,
+            PrimitiveType.IVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_AND, PrimitiveType.BOOL,
+            PrimitiveType.BVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_OR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC2);
+        add(PrimitiveType.BVEC2, BinaryOperator.LOGICAL_XOR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC2);
+
+        add(PrimitiveType.VEC2, BinaryOperator.EQUAL, PrimitiveType.VEC2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.VEC2, BinaryOperator.NOT_EQUAL, PrimitiveType.VEC2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC2, BinaryOperator.EQUAL, PrimitiveType.IVEC2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC2, BinaryOperator.NOT_EQUAL, PrimitiveType.IVEC2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC2, BinaryOperator.EQUAL, PrimitiveType.BVEC2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC2, BinaryOperator.NOT_EQUAL, PrimitiveType.BVEC2,
+            PrimitiveType.BOOL);
+
+        // vec3 operations
+        add(PrimitiveType.VEC3, BinaryOperator.MULTIPLY, PrimitiveType.VEC3,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.DIVIDE, PrimitiveType.VEC3,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.ADD, PrimitiveType.VEC3,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.SUBTRACT, PrimitiveType.VEC3,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.MULTIPLY, PrimitiveType.IVEC3,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.DIVIDE, PrimitiveType.IVEC3,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.ADD, PrimitiveType.IVEC3,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.SUBTRACT, PrimitiveType.IVEC3,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_AND, PrimitiveType.BVEC3,
+            PrimitiveType.BVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_OR, PrimitiveType.BVEC3,
+            PrimitiveType.BVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_XOR, PrimitiveType.BVEC3,
+            PrimitiveType.BVEC3);
+
+        add(PrimitiveType.VEC3, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.VEC3, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.VEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.MULTIPLY, PrimitiveType.INT,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.DIVIDE, PrimitiveType.INT,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.ADD, PrimitiveType.INT,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.IVEC3, BinaryOperator.SUBTRACT, PrimitiveType.INT,
+            PrimitiveType.IVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_AND, PrimitiveType.BOOL,
+            PrimitiveType.BVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_OR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC3);
+        add(PrimitiveType.BVEC3, BinaryOperator.LOGICAL_XOR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC3);
+
+        add(PrimitiveType.VEC3, BinaryOperator.EQUAL, PrimitiveType.VEC3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.VEC3, BinaryOperator.NOT_EQUAL, PrimitiveType.VEC3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC3, BinaryOperator.EQUAL, PrimitiveType.IVEC3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC3, BinaryOperator.NOT_EQUAL, PrimitiveType.IVEC3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC3, BinaryOperator.EQUAL, PrimitiveType.BVEC3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC3, BinaryOperator.NOT_EQUAL, PrimitiveType.BVEC3,
+            PrimitiveType.BOOL);
+
+        // vec4 operations
+        add(PrimitiveType.VEC4, BinaryOperator.MULTIPLY, PrimitiveType.VEC4,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.DIVIDE, PrimitiveType.VEC4,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.ADD, PrimitiveType.VEC4,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.SUBTRACT, PrimitiveType.VEC4,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.MULTIPLY, PrimitiveType.IVEC4,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.DIVIDE, PrimitiveType.IVEC4,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.ADD, PrimitiveType.IVEC4,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.SUBTRACT, PrimitiveType.IVEC4,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_AND, PrimitiveType.BVEC4,
+            PrimitiveType.BVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_OR, PrimitiveType.BVEC4,
+            PrimitiveType.BVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_XOR, PrimitiveType.BVEC4,
+            PrimitiveType.BVEC4);
+
+        add(PrimitiveType.VEC4, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.VEC4, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.VEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.MULTIPLY, PrimitiveType.INT,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.DIVIDE, PrimitiveType.INT,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.ADD, PrimitiveType.INT,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.IVEC4, BinaryOperator.SUBTRACT, PrimitiveType.INT,
+            PrimitiveType.IVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_AND, PrimitiveType.BOOL,
+            PrimitiveType.BVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_OR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC4);
+        add(PrimitiveType.BVEC4, BinaryOperator.LOGICAL_XOR, PrimitiveType.BOOL,
+            PrimitiveType.BVEC4);
+
+        add(PrimitiveType.VEC4, BinaryOperator.EQUAL, PrimitiveType.VEC4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.VEC4, BinaryOperator.NOT_EQUAL, PrimitiveType.VEC4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC4, BinaryOperator.EQUAL, PrimitiveType.IVEC4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.IVEC4, BinaryOperator.NOT_EQUAL, PrimitiveType.IVEC4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC4, BinaryOperator.EQUAL, PrimitiveType.BVEC4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.BVEC4, BinaryOperator.NOT_EQUAL, PrimitiveType.BVEC4,
+            PrimitiveType.BOOL);
+
+        // mat2 operations
+        add(PrimitiveType.MAT2, BinaryOperator.MULTIPLY, PrimitiveType.MAT2,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.DIVIDE, PrimitiveType.MAT2,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.ADD, PrimitiveType.MAT2,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.SUBTRACT, PrimitiveType.MAT2,
+            PrimitiveType.MAT2);
+
+        add(PrimitiveType.MAT2, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.MAT2);
+        add(PrimitiveType.MAT2, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.MAT2);
+
+        add(PrimitiveType.MAT2, BinaryOperator.MULTIPLY, PrimitiveType.VEC2,
+            PrimitiveType.VEC2);
+
+        add(PrimitiveType.MAT2, BinaryOperator.EQUAL, PrimitiveType.MAT2,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.MAT2, BinaryOperator.NOT_EQUAL, PrimitiveType.MAT2,
+            PrimitiveType.BOOL);
+
+        // mat3 operations
+        add(PrimitiveType.MAT3, BinaryOperator.MULTIPLY, PrimitiveType.MAT3,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.DIVIDE, PrimitiveType.MAT3,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.ADD, PrimitiveType.MAT3,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.SUBTRACT, PrimitiveType.MAT3,
+            PrimitiveType.MAT3);
+
+        add(PrimitiveType.MAT3, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.MAT3);
+        add(PrimitiveType.MAT3, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.MAT3);
+
+        add(PrimitiveType.MAT3, BinaryOperator.MULTIPLY, PrimitiveType.VEC3,
+            PrimitiveType.VEC3);
+
+        add(PrimitiveType.MAT3, BinaryOperator.EQUAL, PrimitiveType.MAT3,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.MAT3, BinaryOperator.NOT_EQUAL, PrimitiveType.MAT3,
+            PrimitiveType.BOOL);
+
+        // mat4 operations
+        add(PrimitiveType.MAT4, BinaryOperator.MULTIPLY, PrimitiveType.MAT4,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.DIVIDE, PrimitiveType.MAT4,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.ADD, PrimitiveType.MAT4,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.SUBTRACT, PrimitiveType.MAT4,
+            PrimitiveType.MAT4);
+
+        add(PrimitiveType.MAT4, BinaryOperator.MULTIPLY, PrimitiveType.FLOAT,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.DIVIDE, PrimitiveType.FLOAT,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.ADD, PrimitiveType.FLOAT,
+            PrimitiveType.MAT4);
+        add(PrimitiveType.MAT4, BinaryOperator.SUBTRACT, PrimitiveType.FLOAT,
+            PrimitiveType.MAT4);
+
+        add(PrimitiveType.MAT4, BinaryOperator.MULTIPLY, PrimitiveType.VEC4,
+            PrimitiveType.VEC4);
+
+        add(PrimitiveType.MAT4, BinaryOperator.EQUAL, PrimitiveType.MAT4,
+            PrimitiveType.BOOL);
+        add(PrimitiveType.MAT4, BinaryOperator.NOT_EQUAL, PrimitiveType.MAT4,
+            PrimitiveType.BOOL);
     }
 }

File ferox-renderer/ferox-renderer-api/src/main/java/com/ferox/resource/shader/simple_grammar/Constant.java

 
 import com.ferox.resource.shader.Environment;
 import com.ferox.resource.shader.PrimitiveType;
-import com.ferox.resource.shader.ShaderAccumulator;
 import com.ferox.resource.shader.Type;
 
 public class Constant extends AbstractExpression {
 
     @Override
     public Environment validate(Environment environment) {
+        // constants are always valid
         return environment;
     }
 
     @Override
-    public void emit(ShaderAccumulator accumulator) {
-        // TODO Auto-generated method stub
+    public String emitExpression() {
+        return value.toString();
+    }
 
+    @Override
+    public int getPrecedence() {
+        return Precedence.PRIMARY_EXPRESSIONS.ordinal();
     }
 }

File ferox-renderer/ferox-renderer-api/src/main/java/com/ferox/resource/shader/simple_grammar/DoWhileLoop.java

 import com.ferox.resource.shader.DoWhileBuilder;
 import com.ferox.resource.shader.Environment;
 import com.ferox.resource.shader.Expression;
+import com.ferox.resource.shader.PrimitiveType;
 import com.ferox.resource.shader.ShaderAccumulator;
 import com.ferox.resource.shader.Statement;
 
 
     @Override
     public Environment validate(Environment environment) {
-        // TODO Auto-generated method stub
-        return null;
+        environment = condition.validate(environment);
+        if (!condition.getType(environment).equals(PrimitiveType.BOOL)) {
+            throw new IllegalStateException("Loop condition must evaluate to a boolean");
+        }
+        if (condition.containsDeclaration()) {
+            throw new IllegalStateException("Do-while loops do not support declarations in condition expression");
+        }
+
+        // validate loop body
+        Environment scoped = environment.newScope();
+        for (int i = 0; i < body.length; i++) {
+            scoped = body[i].validate(scoped);
+        }
+
+        return environment;
     }
 
     @Override
     public void emit(ShaderAccumulator accumulator) {
-        // TODO Auto-generated method stub
-
+        accumulator.addLine("do {");
+        accumulator.pushIndent();
+        for (int i = 0; i < body.length; i++) {
+            body[i].emit(accumulator);
+        }
+        accumulator.popIndent();
+        accumulator.addLine("} while (" + condition.emitExpression() + ");");
     }
 
     public static class Builder implements DoWhileBuilder {