#include <cstring>
#include <msp/core/raii.h>
#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
#include "validate.h"
using namespace std;
}
-DeclarationValidator::DeclarationValidator():
+IdentifierValidator::IdentifierValidator():
anonymous_block(false)
{ }
-void DeclarationValidator::multiple_definition(const string &name, Statement &statement, Statement &previous)
+void IdentifierValidator::multiple_definition(const string &name, Statement &statement, Statement &previous)
{
error(statement, format("Multiple definition of %s", name));
add_info(previous, "Previous definition is here");
}
-Statement *DeclarationValidator::find_definition(const string &name)
+Statement *IdentifierValidator::find_definition(const string &name)
{
BlockDeclarationMap *decls = &declarations[current_block];
BlockDeclarationMap::const_iterator i = decls->find(name);
return (i!=decls->end() ? i->second : 0);
}
-void DeclarationValidator::check_definition(const string &name, Statement &statement)
+void IdentifierValidator::check_definition(const string &name, Statement &statement)
{
if(Statement *previous = find_definition(name))
multiple_definition(format("'%s'", name), statement, *previous);
record_definition(name, statement);
}
-void DeclarationValidator::record_definition(const string &name, Statement &statement)
+void IdentifierValidator::record_definition(const string &name, Statement &statement)
{
declarations[current_block].insert(make_pair(name, &statement));
if(anonymous_block)
declarations[current_block->parent].insert(make_pair(name, &statement));
}
-void DeclarationValidator::visit(TypeDeclaration &type)
+void IdentifierValidator::visit(TypeDeclaration &type)
{
check_definition(type.name, type);
}
-void DeclarationValidator::visit(StructDeclaration &strct)
+void IdentifierValidator::visit(StructDeclaration &strct)
{
check_definition(strct.name, strct);
TraversingVisitor::visit(strct);
}
-void DeclarationValidator::visit(VariableDeclaration &var)
+void IdentifierValidator::visit(VariableDeclaration &var)
{
check_definition(var.name, var);
TraversingVisitor::visit(var);
}
-void DeclarationValidator::visit(InterfaceBlock &iface)
+void IdentifierValidator::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);
}
}
-void DeclarationValidator::visit(FunctionDeclaration &func)
+void IdentifierValidator::visit(FunctionDeclaration &func)
{
string key = func.name+func.signature;
map<string, FunctionDeclaration *>::const_iterator i = overloaded_functions.find(key);
{
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));
}
void ReferenceValidator::visit(FunctionCall &call)
{
- if(!call.declaration && !call.constructor)
- error(call, format("Call to undeclared function '%s'", call.name));
+ 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(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);
}
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);
}
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)