namespace GL {
namespace SL {
+unsigned TypeComparer::next_tag = 1;
+
+TypeComparer::TypeComparer():
+ first(0),
+ second(0),
+ first_tag(0),
+ r_result(false)
+{ }
+
+void TypeComparer::compare(Node &node1, Node &node2)
+{
+ if(&node1==&node2)
+ r_result = true;
+ else
+ {
+ second = &node2;
+ node1.visit(*this);
+ }
+}
+
+template<typename T>
+T *TypeComparer::multi_visit(T &node)
+{
+ static unsigned tag = next_tag++;
+
+ if(second)
+ {
+ Node *s = second;
+ first = &node;
+ first_tag = tag;
+ second = 0;
+ s->visit(*this);
+ }
+ else if(!first || tag!=first_tag)
+ r_result = false;
+ else
+ {
+ T *f = static_cast<T *>(first);
+ first = 0;
+ return f;
+ }
+
+ return 0;
+}
+
+void TypeComparer::visit(BasicTypeDeclaration &basic)
+{
+ if(BasicTypeDeclaration *basic1 = multi_visit(basic))
+ {
+ if(basic1->kind!=basic.kind || basic1->size!=basic.size)
+ r_result = false;
+ else if(basic1->base_type && basic.base_type)
+ compare(*basic1->base_type, *basic.base_type);
+ else
+ r_result = (!basic1->base_type && !basic.base_type);
+ }
+}
+
+void TypeComparer::visit(ImageTypeDeclaration &image)
+{
+ if(ImageTypeDeclaration *image1 = multi_visit(image))
+ {
+ if(image1->dimensions!=image.dimensions || image1->array!=image.array)
+ r_result = false;
+ else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow)
+ r_result = false;
+ else if(image1->base_type && image.base_type)
+ compare(*image1->base_type, *image.base_type);
+ else
+ r_result = (!image1->base_type && !image.base_type);
+ }
+}
+
+void TypeComparer::visit(StructDeclaration &strct)
+{
+ if(StructDeclaration *strct1 = multi_visit(strct))
+ {
+ if(strct1->members.body.size()!=strct.members.body.size())
+ r_result = false;
+ else
+ {
+ r_result = true;
+ NodeList<Statement>::const_iterator i = strct1->members.body.begin();
+ NodeList<Statement>::const_iterator j = strct.members.body.begin();
+ for(; (r_result && i!=strct1->members.body.end()); ++i, ++j)
+ compare(**i, **j);
+ }
+ }
+}
+
+void TypeComparer::visit(VariableDeclaration &var)
+{
+ if(VariableDeclaration *var1 = multi_visit(var))
+ {
+ if(var1->name!=var.name || var1->array!=var.array)
+ r_result = false;
+ else if(!var1->type_declaration || !var.type_declaration)
+ r_result = false;
+ else
+ {
+ // TODO Compare array sizes
+ if(var1->type_declaration!=var.type_declaration)
+ compare(*var1->type_declaration, *var.type_declaration);
+ // TODO Compare layout qualifiers for interface block members
+ }
+ }
+}
+
+
LocationCounter::LocationCounter():
r_count(0)
{ }
namespace GL {
namespace SL {
+/** Compares two types for equality. Struct types are compared recursively. */
+class TypeComparer: private NodeVisitor
+{
+private:
+ Node *first;
+ Node *second;
+ unsigned first_tag;
+ bool r_result;
+
+ static unsigned next_tag;
+
+public:
+ TypeComparer();
+
+ bool apply(TypeDeclaration &t1, TypeDeclaration &t2) { compare(t1, t2); return r_result; }
+
+private:
+ void compare(Node &, Node &);
+ template<typename T>
+ T *multi_visit(T &);
+ virtual void visit(BasicTypeDeclaration &);
+ virtual void visit(ImageTypeDeclaration &);
+ virtual void visit(StructDeclaration &);
+ virtual void visit(VariableDeclaration &);
+};
+
/** Determines the number of interface locations required by a variable. */
class LocationCounter: private NodeVisitor
{
}
}
-bool is_same_type(const TypeDeclaration &type1, const TypeDeclaration &type2)
-{
- if(const BasicTypeDeclaration *basic1 = dynamic_cast<const BasicTypeDeclaration *>(&type1))
- {
- const BasicTypeDeclaration *basic2 = dynamic_cast<const BasicTypeDeclaration *>(&type2);
- if(!basic2)
- return false;
-
- if(basic1->kind!=basic2->kind || basic1->size!=basic2->size)
- return false;
-
- if(basic1->base_type && basic2->base_type)
- return is_same_type(*basic1->base_type, *basic2->base_type);
- else
- return (!basic1->base_type && !basic2->base_type);
- }
- else if(const ImageTypeDeclaration *image1 = dynamic_cast<const ImageTypeDeclaration *>(&type1))
- {
- const ImageTypeDeclaration *image2 = dynamic_cast<const ImageTypeDeclaration *>(&type2);
- if(!image2)
- return false;
-
- if(image1->dimensions!=image2->dimensions || image1->array!=image2->array)
- return false;
- if(image1->sampled!=image2->sampled || image1->shadow!=image2->shadow)
- return false;
-
- if(image1->base_type && image2->base_type)
- return is_same_type(*image1->base_type, *image2->base_type);
- else
- return (!image1->base_type && !image2->base_type);
- }
- else if(const StructDeclaration *strct1 = dynamic_cast<const StructDeclaration *>(&type1))
- {
- const StructDeclaration *strct2 = dynamic_cast<const StructDeclaration *>(&type2);
- if(!strct2)
- return false;
-
- NodeList<Statement>::const_iterator i = strct1->members.body.begin();
- NodeList<Statement>::const_iterator j = strct2->members.body.begin();
- for(; (i!=strct1->members.body.end() && j!=strct2->members.body.end()); ++i, ++j)
- {
- const VariableDeclaration *var1 = dynamic_cast<const VariableDeclaration *>(i->get());
- const VariableDeclaration *var2 = dynamic_cast<const VariableDeclaration *>(j->get());
- if(!var1 || !var1->type_declaration || !var2 || !var2->type_declaration)
- return false;
- if(!is_same_type(*var1->type_declaration, *var2->type_declaration))
- return false;
- if(var1->name!=var2->name || var1->array!=var2->array)
- return false;
- // TODO Compare array sizes
- // TODO Compare layout qualifiers for interface block members
- }
-
- return (i==strct1->members.body.end() && j==strct2->members.body.end());
- }
- else
- return false;
-}
-
int get_layout_value(const Layout &layout, const string &name, int def_value)
{
for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
std::string get_unused_variable_name(const Block &, const std::string &);
-bool is_same_type(const TypeDeclaration &, const TypeDeclaration &);
int get_layout_value(const Layout &, const std::string &, int = -1);
void add_to_chain(Assignment::Target &, Assignment::Target::ChainType, unsigned);
}
if(var.type_declaration && var.linked_declaration->type_declaration)
{
- const TypeDeclaration *type = var.type_declaration;
+ TypeDeclaration *type = var.type_declaration;
if(stage->type==Stage::GEOMETRY)
{
if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(type))
if(basic->kind==BasicTypeDeclaration::ARRAY && basic->base_type)
type = basic->base_type;
}
- if(!is_same_type(*type, *var.linked_declaration->type_declaration))
+ if(!TypeComparer().apply(*type, *var.linked_declaration->type_declaration))
{
error(var, format("Mismatched type '%s' for 'in %s'", type->name, var.name));
add_info(*var.linked_declaration, format("Linked to 'out %s' with type '%s'",
error(*uni.node, format("Mismatched binding %d for uniform '%s'", uni.bind_point, uni.name));
add_info(*i->second->node, format("Previously declared here with binding %d", i->second->bind_point));
}
- if(uni.type && i->second->type && !is_same_type(*uni.type, *i->second->type))
+ if(uni.type && i->second->type && !TypeComparer().apply(*uni.type, *i->second->type))
{
string type_name = (dynamic_cast<const StructDeclaration *>(uni.type) ?
"structure" : format("type '%s'", uni.type->name));