+ visit(iter.loop_expression);
+}
+
+
+template<typename T>
+T ConstantFolder::evaluate_logical(char oper, T left, T right)
+{
+ switch(oper)
+ {
+ case '&': return left&right;
+ case '|': return left|right;
+ case '^': return left^right;
+ default: return T();
+ }
+}
+
+template<typename T>
+bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
+{
+ switch(oper[0]|oper[1])
+ {
+ case '<': return left<right;
+ case '<'|'=': return left<=right;
+ case '>': return left>right;
+ case '>'|'=': return left>=right;
+ default: return false;
+ }
+}
+
+template<typename T>
+T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
+{
+ switch(oper)
+ {
+ case '+': return left+right;
+ case '-': return left-right;
+ case '*': return left*right;
+ case '/': return left/right;
+ default: return T();
+ }
+}
+
+template<typename T>
+T ConstantFolder::evaluate_int_special_op(char oper, T left, T right)
+{
+ switch(oper)
+ {
+ case '%': return left%right;
+ case '<': return left<<right;
+ case '>': return left>>right;
+ default: return T();
+ }
+}
+
+template<typename T>
+void ConstantFolder::convert_to_result(const Variant &value)
+{
+ if(value.check_type<bool>())
+ set_result(static_cast<T>(value.value<bool>()));
+ else if(value.check_type<int>())
+ set_result(static_cast<T>(value.value<int>()));
+ else if(value.check_type<unsigned>())
+ set_result(static_cast<T>(value.value<unsigned>()));
+ else if(value.check_type<float>())
+ set_result(static_cast<T>(value.value<float>()));
+}
+
+void ConstantFolder::set_result(const Variant &value, bool literal)
+{
+ r_constant_value = value;
+ r_constant = true;
+ r_literal = literal;
+}
+
+void ConstantFolder::visit(RefPtr<Expression> &expr)
+{
+ r_constant_value = Variant();
+ r_constant = false;
+ r_literal = false;
+ r_uses_iter_var = false;
+ expr->visit(*this);
+ /* Don't replace literals since they'd only be replaced with an identical
+ literal. Also skip anything that uses an iteration variable, but pass on
+ the result so the Iteration visiting function can handle it. */
+ if(!r_constant || r_literal || r_uses_iter_var)
+ return;
+
+ RefPtr<Literal> literal = new Literal;
+ if(r_constant_value.check_type<bool>())
+ literal->token = (r_constant_value.value<bool>() ? "true" : "false");
+ else if(r_constant_value.check_type<int>())
+ literal->token = lexical_cast<string>(r_constant_value.value<int>());
+ else if(r_constant_value.check_type<unsigned>())
+ literal->token = lexical_cast<string>(r_constant_value.value<unsigned>())+"u";
+ else if(r_constant_value.check_type<float>())
+ {
+ literal->token = lexical_cast<string>(r_constant_value.value<float>());
+ if(isnumrc(literal->token))
+ literal->token += ".0";
+ }
+ else
+ {
+ r_constant = false;
+ return;
+ }
+ literal->value = r_constant_value;
+ expr = literal;
+}
+
+void ConstantFolder::visit(Literal &literal)
+{
+ set_result(literal.value, true);
+}
+
+void ConstantFolder::visit(VariableReference &var)
+{
+ /* If an iteration variable is initialized with a constant value, return
+ that value here for the purpose of evaluating the loop condition for the
+ first iteration. */
+ if(var.declaration==iteration_var)
+ {
+ set_result(iter_init_value);
+ r_uses_iter_var = true;
+ }
+}
+
+void ConstantFolder::visit(MemberAccess &memacc)
+{
+ TraversingVisitor::visit(memacc);
+ r_constant = false;
+}
+
+void ConstantFolder::visit(Swizzle &swizzle)
+{
+ TraversingVisitor::visit(swizzle);
+ r_constant = false;
+}
+
+void ConstantFolder::visit(UnaryExpression &unary)
+{
+ TraversingVisitor::visit(unary);
+ bool can_fold = r_constant;
+ r_constant = false;
+ if(!can_fold)
+ return;
+
+ char oper = unary.oper->token[0];
+ char oper2 = unary.oper->token[1];
+ if(oper=='!')
+ {
+ if(r_constant_value.check_type<bool>())
+ set_result(!r_constant_value.value<bool>());
+ }
+ else if(oper=='~')
+ {
+ if(r_constant_value.check_type<int>())
+ set_result(~r_constant_value.value<int>());
+ else if(r_constant_value.check_type<unsigned>())
+ set_result(~r_constant_value.value<unsigned>());
+ }
+ else if(oper=='-' && !oper2)
+ {
+ if(r_constant_value.check_type<int>())
+ set_result(-r_constant_value.value<int>());
+ else if(r_constant_value.check_type<unsigned>())
+ set_result(-r_constant_value.value<unsigned>());
+ else if(r_constant_value.check_type<float>())
+ set_result(-r_constant_value.value<float>());
+ }
+}
+
+void ConstantFolder::visit(BinaryExpression &binary)
+{
+ visit(binary.left);
+ bool left_constant = r_constant;
+ bool left_iter_var = r_uses_iter_var;
+ Variant left_value = r_constant_value;
+ visit(binary.right);
+ if(left_iter_var)
+ r_uses_iter_var = true;
+
+ bool can_fold = (left_constant && r_constant);
+ r_constant = false;
+ if(!can_fold)
+ return;
+
+ // Currently only expressions with both sides of equal types are handled.
+ if(!left_value.check_same_type(r_constant_value))
+ return;
+
+ char oper = binary.oper->token[0];
+ char oper2 = binary.oper->token[1];
+ if(oper=='&' || oper=='|' || oper=='^')
+ {
+ if(oper2==oper && left_value.check_type<bool>())
+ set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
+ else if(!oper2 && left_value.check_type<int>())
+ set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
+ else if(!oper2 && left_value.check_type<unsigned>())
+ set_result(evaluate_logical(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
+ }
+ else if((oper=='<' || oper=='>') && oper2!=oper)
+ {
+ if(left_value.check_type<int>())
+ set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
+ else if(left_value.check_type<unsigned>())
+ set_result(evaluate_relation(binary.oper->token, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
+ else if(left_value.check_type<float>())
+ set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
+ }
+ else if((oper=='=' || oper=='!') && oper2=='=')
+ {
+ if(left_value.check_type<int>())
+ set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
+ else if(left_value.check_type<unsigned>())
+ set_result((left_value.value<unsigned>()==r_constant_value.value<unsigned>()) == (oper=='='));
+ else if(left_value.check_type<float>())
+ set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
+ }
+ else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
+ {
+ if(left_value.check_type<int>())
+ set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
+ else if(left_value.check_type<unsigned>())
+ set_result(evaluate_arithmetic(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
+ else if(left_value.check_type<float>())
+ set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
+ }
+ else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
+ {
+ if(left_value.check_type<int>())
+ set_result(evaluate_int_special_op(oper, left_value.value<int>(), r_constant_value.value<int>()));
+ else if(left_value.check_type<unsigned>())
+ set_result(evaluate_int_special_op(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
+ }
+}
+
+void ConstantFolder::visit(Assignment &assign)
+{
+ TraversingVisitor::visit(assign);
+ r_constant = false;