]> git.tdb.fi Git - libs/gl.git/commitdiff
Rewrite type comparisons as a visitor
authorMikko Rasa <tdb@tdb.fi>
Tue, 6 Apr 2021 22:42:49 +0000 (01:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 6 Apr 2021 23:03:13 +0000 (02:03 +0300)
source/glsl/reflect.cpp
source/glsl/reflect.h
source/glsl/syntax.cpp
source/glsl/syntax.h
source/glsl/validate.cpp

index 151735ab18f3790d51b94bbf61da68726ce56a39..93d64e5fdb62aac1087d080efb37a0687fd99901 100644 (file)
@@ -6,6 +6,115 @@ namespace Msp {
 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)
 { }
index 162ed9c0b8bcf4ddb01daf17724e4308138decd0..9520feb6a924c797ee50b7e8a062dbd7b1f74795 100644 (file)
@@ -7,6 +7,32 @@ namespace Msp {
 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
 {
index b224763248f26aa20f2d7e537ccbc6aa224acdb7..947b310ef5e528e026dd53dcbd642de96f4923b3 100644 (file)
@@ -487,66 +487,6 @@ string get_unused_variable_name(const Block &block, const string &base)
        }
 }
 
-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)
index 2a9dcf84869261298d404248c3fd138de41fc498..f22ef1ec1a9700744edd08f89d119e06a97d490d 100644 (file)
@@ -557,7 +557,6 @@ struct Module
 
 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);
 
index cb866b4ba215562c10fff9255bd1867b51ff6f00..4a5ffe841801b064c04c7ea68d6d91eb53ea1c59 100644 (file)
@@ -690,14 +690,14 @@ void StageInterfaceValidator::visit(VariableDeclaration &var)
                }
                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'",
@@ -750,7 +750,7 @@ void GlobalInterfaceValidator::check_uniform(const Uniform &uni)
                        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));