+#include <msp/core/raii.h>
+#include <msp/strings/format.h>
+#include "validate.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+Validator::Validator():
+ stage(0)
+{ }
+
+void Validator::diagnose(Statement *statement, Diagnostic::Severity severity, const string &message)
+{
+ Diagnostic diag;
+ diag.severity = severity;
+ if(statement)
+ {
+ diag.source = statement->source;
+ diag.line = statement->line;
+ }
+ diag.message = message;
+ stage->diagnostics.push_back(diag);
+}
+
+
+DeclarationValidator::DeclarationValidator():
+ anonymous_block(false)
+{ }
+
+Statement *DeclarationValidator::find_definition(const string &name)
+{
+ BlockDeclarationMap *decls = &declarations[current_block];
+ BlockDeclarationMap::const_iterator i = decls->find(name);
+ if(i==decls->end() && anonymous_block)
+ {
+ decls = &declarations[current_block->parent];
+ i = decls->find(name);
+ }
+ return (i!=decls->end() ? i->second : 0);
+}
+
+void DeclarationValidator::check_definition(const string &name, Statement &statement)
+{
+ if(Statement *previous = find_definition(name))
+ {
+ error(&statement, format("Multiple definition of '%s'", name));
+ diagnose(previous, Diagnostic::INFO, "Previous definition is here");
+ return;
+ }
+
+ declarations[current_block][name] = &statement;
+ if(anonymous_block)
+ declarations[current_block->parent][name] = &statement;
+}
+
+void DeclarationValidator::visit(VariableDeclaration &var)
+{
+ check_definition(var.name, var);
+ TraversingVisitor::visit(var);
+}
+
+void DeclarationValidator::visit(InterfaceBlock &iface)
+{
+ check_definition(iface.name, iface);
+ if(!iface.instance_name.empty())
+ check_definition(iface.instance_name, iface);
+ SetFlag set_anon(anonymous_block, iface.instance_name.empty());
+ TraversingVisitor::visit(iface);
+}
+
+void DeclarationValidator::visit(FunctionDeclaration &func)
+{
+ if(func.definition==&func)
+ check_definition(func.name, func);
+ TraversingVisitor::visit(func);
+}
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp