end_sub();
}
+void DumpTree::visit(TernaryExpression &ternary)
+{
+ append(format("Ternary: %s -> %s", (ternary.oper->token[0]=='?' ? "?:" : ternary.oper->token), format_type(ternary.type)));
+ begin_sub();
+ ternary.condition->visit(*this);
+ ternary.true_expr->visit(*this);
+ last_branch();
+ ternary.false_expr->visit(*this);
+ end_sub();
+}
+
void DumpTree::visit(FunctionCall &call)
{
string head = "Function call: ";
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(ExpressionStatement &);
virtual void visit(Import &);
resolve(assign, assign.left->type, true);
}
+void ExpressionResolver::visit(TernaryExpression &ternary)
+{
+ TraversingVisitor::visit(ternary);
+
+ BasicTypeDeclaration *basic_cond = dynamic_cast<BasicTypeDeclaration *>(ternary.condition->type);
+ if(!basic_cond || basic_cond->kind!=BasicTypeDeclaration::BOOL)
+ return;
+
+ TypeDeclaration *type = 0;
+ if(ternary.true_expr->type==ternary.false_expr->type)
+ type = ternary.true_expr->type;
+ else
+ {
+ BasicTypeDeclaration *basic_true = dynamic_cast<BasicTypeDeclaration *>(ternary.true_expr->type);
+ BasicTypeDeclaration *basic_false = dynamic_cast<BasicTypeDeclaration *>(ternary.false_expr->type);
+ Compatibility compat = get_compatibility(*basic_true, *basic_false);
+ if(compat==NOT_COMPATIBLE)
+ return;
+
+ type = (compat==LEFT_CONVERTIBLE ? basic_true : basic_false);
+
+ if(compat==LEFT_CONVERTIBLE)
+ convert_to(ternary.true_expr, *basic_false);
+ else if(compat==RIGHT_CONVERTIBLE)
+ convert_to(ternary.false_expr, *basic_true);
+ }
+
+ resolve(ternary, type, false);
+}
+
void ExpressionResolver::visit(FunctionCall &call)
{
TraversingVisitor::visit(call);
void visit(BinaryExpression &, bool);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(BasicTypeDeclaration &);
virtual void visit(VariableDeclaration &);
r_trivial = false;
}
+void ExpressionInliner::visit(TernaryExpression &ternary)
+{
+ visit_and_record(ternary.condition, ternary.oper, false);
+ visit_and_record(ternary.true_expr, ternary.oper, false);
+ visit_and_record(ternary.false_expr, ternary.oper, true);
+ r_oper = ternary.oper;
+ r_trivial = false;
+}
+
void ExpressionInliner::visit(FunctionCall &call)
{
TraversingVisitor::visit(call);
TraversingVisitor::visit(binary);
}
+void UnusedTypeRemover::visit(TernaryExpression &ternary)
+{
+ unused_nodes.erase(ternary.type);
+ TraversingVisitor::visit(ternary);
+}
+
void UnusedTypeRemover::visit(FunctionCall &call)
{
unused_nodes.erase(call.type);
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(VariableDeclaration &);
virtual void visit(Iteration &);
virtual void visit(Literal &);
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(BasicTypeDeclaration &);
virtual void visit(ImageTypeDeclaration &);
assign.right->visit(*this);
}
+void Formatter::visit(TernaryExpression &ternary)
+{
+ ternary.condition->visit(*this);
+ append(ternary.oper->token);
+ ternary.true_expr->visit(*this);
+ if(ternary.oper->token[0]=='?')
+ append(':');
+ ternary.false_expr->visit(*this);
+}
+
void Formatter::visit(FunctionCall &call)
{
append(format("%s(", call.name));
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(ExpressionStatement &);
virtual void visit(Import &);
oper = i;
bool lower_precedence = (oper && oper->type!=Operator::PREFIX && oper->precedence>=outer_precedence);
- if(token==";" || token==")" || token=="]" || token=="," || lower_precedence)
+ if(token==";" || token==")" || token=="]" || token=="," || token==":" || lower_precedence)
{
if(left)
return left;
}
else if(oper && oper->type==Operator::BINARY)
left = parse_binary(left, *oper);
+ else if(oper && oper->type==Operator::TERNARY)
+ left = parse_ternary(left, *oper);
else
throw parse_error(tokenizer.get_location(), token, "an operator");
left_var = 0;
return binary;
}
+RefPtr<TernaryExpression> Parser::parse_ternary(const RefPtr<Expression> &cond, const Operator &oper)
+{
+ RefPtr<TernaryExpression> ternary = create_node<TernaryExpression>();
+ ternary->condition = cond;
+ ternary->oper = &oper;
+ tokenizer.expect("?");
+ ternary->true_expr = parse_expression(&oper);
+ tokenizer.expect(":");
+ ternary->false_expr = parse_expression(&oper);
+ return ternary;
+}
+
RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
{
RefPtr<FunctionCall> call = create_node<FunctionCall>();
RefPtr<Expression> parse_expression(const Operator * = 0);
RefPtr<Literal> parse_literal();
RefPtr<BinaryExpression> parse_binary(const RefPtr<Expression> &, const Operator &);
+ RefPtr<TernaryExpression> parse_ternary(const RefPtr<Expression> &, const Operator &);
RefPtr<FunctionCall> parse_function_call(const VariableReference &);
RefPtr<TypeDeclaration> parse_type_declaration();
RefPtr<BasicTypeDeclaration> parse_basic_type_declaration();
{ "&&", 12, BINARY, ASSOCIATIVE },
{ "^^", 13, BINARY, ASSOCIATIVE },
{ "||", 14, BINARY, ASSOCIATIVE },
- { "?", 15, BINARY, RIGHT_TO_LEFT },
- { ":", 15, BINARY, RIGHT_TO_LEFT },
+ { "?", 15, TERNARY, RIGHT_TO_LEFT },
+ { ":", 15, TERNARY, RIGHT_TO_LEFT },
{ "=", 16, BINARY, RIGHT_TO_LEFT },
{ "+=", 16, BINARY, RIGHT_TO_LEFT },
{ "-=", 16, BINARY, RIGHT_TO_LEFT },
}
+void TernaryExpression::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
FunctionCall::FunctionCall():
constructor(false),
declaration(0)
NO_OPERATOR,
BINARY,
PREFIX,
- POSTFIX
+ POSTFIX,
+ TERNARY
};
enum Associativity
virtual void visit(NodeVisitor &);
};
+struct TernaryExpression: Expression
+{
+ NodePtr<Expression> condition;
+ NodePtr<Expression> true_expr;
+ NodePtr<Expression> false_expr;
+
+ virtual TernaryExpression *clone() const { return new TernaryExpression(*this); }
+ virtual void visit(NodeVisitor &);
+};
+
struct FunctionCall: Expression
{
std::string name;
TraversingVisitor::visit(assign);
}
+void ExpressionValidator::visit(TernaryExpression &ternary)
+{
+ if(ternary.condition->type)
+ {
+ BasicTypeDeclaration *basic_cond = dynamic_cast<BasicTypeDeclaration *>(ternary.condition->type);
+ if(!basic_cond || basic_cond->kind!=BasicTypeDeclaration::BOOL)
+ error(ternary, "Ternary operator condition is not a boolean");
+ else if(!ternary.type && ternary.true_expr->type && ternary.false_expr->type)
+ error(ternary, format("Ternary operator has incompatible types '%s' and '%s'",
+ ternary.true_expr->type->name, ternary.false_expr->type->name));
+ }
+ TraversingVisitor::visit(ternary);
+}
+
void ExpressionValidator::visit(VariableDeclaration &var)
{
if(var.init_expression && var.init_expression->type && var.type_declaration && var.init_expression->type!=var.type_declaration)
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(VariableDeclaration &);
};
visit(assign.right);
}
+void TraversingVisitor::visit(TernaryExpression &ternary)
+{
+ visit(ternary.condition);
+ visit(ternary.true_expr);
+ visit(ternary.false_expr);
+}
+
void TraversingVisitor::visit(FunctionCall &call)
{
for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
virtual void visit(UnaryExpression &) { }
virtual void visit(BinaryExpression &) { }
virtual void visit(Assignment &) { }
+ virtual void visit(TernaryExpression &) { }
virtual void visit(FunctionCall &) { }
virtual void visit(ExpressionStatement &) { }
virtual void visit(Import &) { }
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
+ virtual void visit(TernaryExpression &);
virtual void visit(FunctionCall &);
virtual void visit(ExpressionStatement &);
virtual void visit(InterfaceLayout &);
--- /dev/null
+uniform Colors
+{
+ vec4 color;
+ float gray;
+};
+uniform sampler2D mask;
+uniform Transform
+{
+ mat4 mvp;
+} transform;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 position;
+layout(location=1) in vec2 texcoord;
+void main()
+{
+ passthrough;
+ gl_Position = transform.mvp*position;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec4 frag_color;
+void main()
+{
+ frag_color = texture(mask, texcoord).r > 0.5 ? color : gray;
+}
+
+/* Expected error:
+<test>:25: Ternary operator has incompatible types 'vec4' and 'float'
+*/
--- /dev/null
+uniform Colors
+{
+ vec4 color1;
+ vec4 color2;
+};
+uniform sampler2D mask;
+uniform Transform
+{
+ mat4 mvp;
+} transform;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 position;
+layout(location=1) in vec2 texcoord;
+void main()
+{
+ passthrough;
+ gl_Position = transform.mvp*position;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec4 frag_color;
+void main()
+{
+ frag_color = texture(mask, texcoord).r > 0.5 ? color1 : color2;
+}
+
+/* Expected output: vertex
+uniform Transform
+{
+ mat4 mvp;
+} transform;
+layout(location=0) in vec4 position;
+layout(location=1) in vec2 texcoord;
+out vec2 _vs_out_texcoord;
+void main()
+{
+ _vs_out_texcoord = texcoord;
+ gl_Position = transform.mvp*position;
+}
+*/
+
+/* Expected output: fragment
+uniform Colors
+{
+ vec4 color1;
+ vec4 color2;
+};
+uniform sampler2D mask;
+layout(location=0) out vec4 frag_color;
+in vec2 _vs_out_texcoord;
+void main()
+{
+ frag_color = texture(mask, _vs_out_texcoord).r>0.5?color1:color2;
+}
+*/