]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/validate.cpp
Resolve and validate the parameters of constructors in GLSL
[libs/gl.git] / source / glsl / validate.cpp
index 91d1de991515dc74dbb359d0385a0429ef855803..b8710509e8d32fe424062f6c6558976ceab6da35 100644 (file)
@@ -2,6 +2,7 @@
 #include <cstring>
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
+#include <msp/strings/utils.h>
 #include "validate.h"
 
 using namespace std;
@@ -215,7 +216,7 @@ void ReferenceValidator::visit(VariableReference &var)
 {
        if(!var.declaration)
                error(var, format("Use of undeclared variable '%s'", var.name));
-       else if(stage->type!=Stage::VERTEX && var.declaration->interface=="in" && !var.declaration->linked_declaration)
+       else if(stage->type!=Stage::VERTEX && var.declaration->interface=="in" && var.name.compare(0, 3, "gl_") && !var.declaration->linked_declaration)
                error(var, format("Use of unlinked input variable '%s'", var.name));
 }
 
@@ -236,6 +237,38 @@ void ReferenceValidator::visit(InterfaceBlockReference &iface)
                error(iface, format("Use of unlinked input block '%s'", iface.name));
 }
 
+void ReferenceValidator::visit(FunctionCall &call)
+{
+       if((!call.constructor && !call.declaration) || (call.constructor && !call.type))
+       {
+               bool have_declaration = call.constructor;
+               if(!call.constructor)
+               {
+                       map<string, FunctionDeclaration *>::iterator i = stage->functions.lower_bound(call.name);
+                       have_declaration = (i!=stage->functions.end() && i->second->name==call.name);
+               }
+
+               if(have_declaration)
+               {
+                       bool valid_types = true;
+                       string signature;
+                       for(NodeArray<Expression>::const_iterator j=call.arguments.begin(); (valid_types && j!=call.arguments.end()); ++j)
+                       {
+                               if((*j)->type)
+                                       append(signature, ", ", (*j)->type->name);
+                               else
+                                       valid_types = false;
+                       }
+
+                       if(valid_types)
+                               error(call, format("No matching %s found for '%s(%s)'", (call.constructor ? "constructor" : "overload"), call.name, signature));
+               }
+               else
+                       error(call, format("Call to undeclared function '%s'", call.name));
+       }
+       TraversingVisitor::visit(call);
+}
+
 void ReferenceValidator::visit(VariableDeclaration &var)
 {
        if(!var.type_declaration)
@@ -311,8 +344,14 @@ void ExpressionValidator::visit(UnaryExpression &unary)
 void ExpressionValidator::visit(BinaryExpression &binary)
 {
        if(!binary.type && binary.left->type && binary.right->type)
-               error(binary, format("No matching operator '%s' found for '%s' and '%s'",
-                       binary.oper->token, binary.left->type->name, binary.right->type->name));
+       {
+               if(binary.oper->token[0]=='[')
+                       error(binary, format("Can't index element of '%s' with '%s'",
+                               binary.left->type->name, binary.right->type->name));
+               else
+                       error(binary, format("No matching operator '%s' found for '%s' and '%s'",
+                               binary.oper->token, binary.left->type->name, binary.right->type->name));
+       }
        TraversingVisitor::visit(binary);
 }
 
@@ -338,6 +377,20 @@ void ExpressionValidator::visit(Assignment &assign)
        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)