]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/validate.cpp
Rename InterfaceBlock::name to block_name for clarity
[libs/gl.git] / source / glsl / validate.cpp
index ea2e956d023f1e02d66b44b7771186542076dd28..99e2dfe86c954d31a5a8e734a78b92a9ea3bc283 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;
@@ -144,20 +145,20 @@ void DeclarationValidator::visit(VariableDeclaration &var)
 
 void DeclarationValidator::visit(InterfaceBlock &iface)
 {
-       string key = iface.interface+iface.name;
+       string key = iface.interface+iface.block_name;
        map<string, InterfaceBlock *>::const_iterator i = interface_blocks.find(key);
        if(i!=interface_blocks.end())
-               multiple_definition(format("interface block '%s %s'", iface.interface, iface.name), iface, *i->second);
+               multiple_definition(format("interface block '%s %s'", iface.interface, iface.block_name), iface, *i->second);
        else
                interface_blocks.insert(make_pair(key, &iface));
 
-       if(Statement *previous = find_definition(iface.name))
+       if(Statement *previous = find_definition(iface.block_name))
        {
                if(!dynamic_cast<InterfaceBlock *>(previous))
-                       multiple_definition(format("'%s'", iface.name), iface, *previous);
+                       multiple_definition(format("'%s'", iface.block_name), iface, *previous);
        }
        else
-               record_definition(iface.name, iface);
+               record_definition(iface.block_name, iface);
 
        if(!iface.instance_name.empty())
                check_definition(iface.instance_name, iface);
@@ -173,17 +174,28 @@ void DeclarationValidator::visit(InterfaceBlock &iface)
 
 void DeclarationValidator::visit(FunctionDeclaration &func)
 {
+       string key = func.name+func.signature;
+       map<string, FunctionDeclaration *>::const_iterator i = overloaded_functions.find(key);
+       if(i==overloaded_functions.end())
+               overloaded_functions.insert(make_pair(key, &func));
+       else if(func.return_type_declaration && i->second->return_type_declaration!=func.return_type_declaration)
+       {
+               error(func, format("Conflicting return type '%s' for function '%s'", func.return_type_declaration->name, func.name));
+               if(i->second->return_type_declaration)
+                       add_info(*i->second, format("Previously declared as returning '%s'", i->second->return_type_declaration->name));
+       }
+
        if(Statement *previous = find_definition(func.name))
        {
-               FunctionDeclaration *prev_func = dynamic_cast<FunctionDeclaration *>(previous);
-               if(prev_func && prev_func->definition==&func)
-                       declarations[current_block][func.name] = &func;
-               else
+               if(!dynamic_cast<FunctionDeclaration *>(previous))
                        multiple_definition(format("'%s'", func.name), func, *previous);
        }
        else
                record_definition(func.name, func);
 
+       if(func.definition==&func)
+               check_definition(func.name+func.signature, func);
+
        TraversingVisitor::visit(func);
 }
 
@@ -204,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));
 }
 
@@ -225,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)
@@ -235,7 +279,7 @@ void ReferenceValidator::visit(VariableDeclaration &var)
 void ReferenceValidator::visit(InterfaceBlock &iface)
 {
        if(!iface.struct_declaration)
-               error(iface, format("Interface block '%s %s' lacks a struct declaration", iface.interface, iface.name));
+               error(iface, format("Interface block '%s %s' lacks a struct declaration", iface.interface, iface.block_name));
        TraversingVisitor::visit(iface);
 }
 
@@ -300,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);
 }
 
@@ -327,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)