diff options
Diffstat (limited to 'libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx')
| -rw-r--r-- | libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx | 245 | 
1 files changed, 245 insertions, 0 deletions
| diff --git a/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx b/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx new file mode 100644 index 0000000..26ad16c --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx @@ -0,0 +1,245 @@ +// file      : xsd-frontend/transformations/enum-synthesis.cxx +// copyright : Copyright (c) 2006-2014 Code Synthesis Tools CC +// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <set> + +#include <xsd-frontend/semantic-graph.hxx> +#include <xsd-frontend/traversal.hxx> + +#include <xsd-frontend/transformations/enum-synthesis.hxx> + +namespace XSDFrontend +{ +  namespace +  { +    typedef std::set<String> Enumerators; + +    struct Enumerator: Traversal::Enumerator +    { +      Enumerator (SemanticGraph::Schema& s, +                  SemanticGraph::Enumeration& e, +                  Enumerators& enumerators) +          : schema_ (s), enum_ (e), enumerators_ (enumerators) +      { +      } + +      virtual void +      traverse (Type& e) +      { +        String const& name (e.name ()); + +        if (enumerators_.find (name) == enumerators_.end ()) +        { +          enumerators_.insert (name); + +          // Clone the enumerator and add it to enum_. +          // +          Type& c (schema_.new_node<Type> (e.file (), e.line (), e.column ())); + +          schema_.new_edge<SemanticGraph::Names> (enum_, c, name); +          schema_.new_edge<SemanticGraph::Belongs> (c, enum_); + +          if (e.annotated_p ()) +            schema_.new_edge<SemanticGraph::Annotates> (e.annotation (), c); +        } +      } + +    private: +      SemanticGraph::Schema& schema_; +      SemanticGraph::Enumeration& enum_; +      Enumerators& enumerators_; +    }; + +    // +    // +    struct Union: Traversal::Union +    { +      Union (SemanticGraph::Schema& schema) +          : schema_ (schema) +      { +      } + +      virtual void +      traverse (Type& u) +      { +        using SemanticGraph::Enumeration; + +        SemanticGraph::Context& uc (u.context ()); + +        if (uc.count ("xsd-frontend-enum-synthesis-processed")) +          return; + +        uc.set ("xsd-frontend-enum-synthesis-processed", true); + +        // First see if this union is suitable for synthesis. +        // +        SemanticGraph::Type* base (0); + +        for (Type::ArgumentedIterator i (u.argumented_begin ()); +             i != u.argumented_end (); ++i) +        { +          if (i->type ().is_a<SemanticGraph::Union> ()) +          { +            // See if we can synthesize an enum for this union. This +            // call can change the value i->type() returns. +            // +            dispatch (i->type ()); +          } + +          SemanticGraph::Type& t (i->type ()); + +          if (!t.is_a<Enumeration> ()) +            return; + +          // Make sure all the enums have a common base. +          // +          if (base == 0) +            base = &t; +          else +          { +            // Traverse the inheritance hierarchy until we fine a +            // common base. +            // +            while (base != 0) +            { +              SemanticGraph::Type* b (&t); + +              for (; b != base && b->inherits_p (); +                   b = &b->inherits ().base ()) ; + +              if (base == b) +                break; + +              // Could not find any match on this level. Go one step +              // lower and try again. +              // +              base = base->inherits_p () ? &base->inherits ().base () : 0; +            } + +            if (base == 0) +              return; // No common base. +          } +        } + +        if (base == 0) +          return; // Empty union. + +        // So this union is suitable for synthesis. Base variable points +        // to the "most-derived" common base type. +        // +        Enumeration& e (schema_.new_node<Enumeration> ( +                          u.file (), u.line (), u.column ())); + +        schema_.new_edge<SemanticGraph::Restricts> (e, *base); + +        // Copy enumerators from the member enums. +        // +        { +          Enumerators set; +          Traversal::Enumeration en; +          Traversal::Names names; +          Enumerator er (schema_, e, set); +          en >> names >> er; + +          for (Type::ArgumentedIterator i (u.argumented_begin ()); +               i != u.argumented_end (); ++i) +          { +            en.dispatch (i->type ()); +          } +        } + +        // Reset edges pointing to union to point to enum. +        // +        if (u.annotated_p ()) +        { +          schema_.reset_right_node (u.annotated (), e); +          schema_.add_edge_right (e, u.annotated ()); +        } + +        schema_.reset_right_node (u.named (), e); +        schema_.add_edge_right (e, u.named ()); + +        for (Type::ClassifiesIterator i (u.classifies_begin ()), +               end (u.classifies_end ()); i != end; ++i) +        { +          schema_.reset_right_node (*i, e); +          schema_.add_edge_right (e, *i); +        } + +        for (Type::BegetsIterator i (u.begets_begin ()), +               end (u.begets_end ()); i != end; ++i) +        { +          schema_.reset_right_node (*i, e); +          schema_.add_edge_right (e, *i); +        } + +        for (Type::ArgumentsIterator i (u.arguments_begin ()), +               end (u.arguments_end ()); i != end; ++i) +        { +          schema_.reset_left_node (*i, e); +          schema_.add_edge_left (e, *i); +        } + +        // Remove Arguments edges pointing to the union. +        // +        while (u.argumented_begin () != u.argumented_end ()) +        { +          SemanticGraph::Arguments& a (*u.argumented_begin ()); +          schema_.delete_edge (a.type (), a.specialization (), a); +        } + +        // Copy context and delete the union node. +        // +        e.context ().swap (uc); +        schema_.delete_node (u); +      } + +    private: +      SemanticGraph::Schema& schema_; +    }; + +    // Go into implied/included/imported schemas while making sure +    // we don't process the same stuff more than once. +    // +    struct Uses: Traversal::Uses +    { +      virtual void +      traverse (Type& u) +      { +        SemanticGraph::Schema& s (u.schema ()); + +        if (!s.context ().count ("xsd-frontend-enum-synthesis-seen")) +        { +          s.context ().set ("xsd-frontend-enum-synthesis-seen", true); +          Traversal::Uses::traverse (u); +        } +      } +    }; +  } + +  namespace Transformations +  { +    void EnumSynthesis:: +    transform (SemanticGraph::Schema& s, SemanticGraph::Path const&) +    { +      Traversal::Schema schema; +      Uses uses; + +      schema >> uses >> schema; + +      Traversal::Names schema_names; +      Traversal::Namespace ns; +      Traversal::Names ns_names; +      Union u (s); + +      schema >> schema_names >> ns >> ns_names >> u; + +      // Some twisted schemas do recusive inclusions. +      // +      s.context ().set ("xsd-frontend-enum-synthesis-seen", true); + +      schema.dispatch (s); +    } +  } +} | 
