From: Mikko Rasa Date: Tue, 6 Apr 2021 22:42:49 +0000 (+0300) Subject: Rewrite type comparisons as a visitor X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=c701c8787cb19fbb6dc5b0bfae1a94e2b07dd549 Rewrite type comparisons as a visitor --- diff --git a/source/glsl/reflect.cpp b/source/glsl/reflect.cpp index 151735ab..93d64e5f 100644 --- a/source/glsl/reflect.cpp +++ b/source/glsl/reflect.cpp @@ -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 +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(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::const_iterator i = strct1->members.body.begin(); + NodeList::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) { } diff --git a/source/glsl/reflect.h b/source/glsl/reflect.h index 162ed9c0..9520feb6 100644 --- a/source/glsl/reflect.h +++ b/source/glsl/reflect.h @@ -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 + 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 { diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index b2247632..947b310e 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -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(&type1)) - { - const BasicTypeDeclaration *basic2 = dynamic_cast(&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(&type1)) - { - const ImageTypeDeclaration *image2 = dynamic_cast(&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(&type1)) - { - const StructDeclaration *strct2 = dynamic_cast(&type2); - if(!strct2) - return false; - - NodeList::const_iterator i = strct1->members.body.begin(); - NodeList::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(i->get()); - const VariableDeclaration *var2 = dynamic_cast(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::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index 2a9dcf84..f22ef1ec 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -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); diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index cb866b4b..4a5ffe84 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -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(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(uni.type) ? "structure" : format("type '%s'", uni.type->name));