From a15cf65c44d5c224169c32ef5495b68c758134b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 18 May 2014 16:08:14 +0200 Subject: Imported Upstream version 3.3.0.2 --- .../xsd-frontend/transformations/anonymous.cxx | 739 +++++++++++++++++++++ .../xsd-frontend/transformations/anonymous.hxx | 60 ++ .../transformations/enum-synthesis.cxx | 249 +++++++ .../transformations/enum-synthesis.hxx | 33 + .../xsd-frontend/transformations/restriction.cxx | 582 ++++++++++++++++ .../xsd-frontend/transformations/restriction.hxx | 39 ++ .../transformations/schema-per-type.cxx | 453 +++++++++++++ .../transformations/schema-per-type.hxx | 61 ++ .../xsd-frontend/transformations/simplifier.cxx | 167 +++++ .../xsd-frontend/transformations/simplifier.hxx | 33 + 10 files changed, 2416 insertions(+) create mode 100644 libxsd-frontend/xsd-frontend/transformations/anonymous.cxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/anonymous.hxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/enum-synthesis.hxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/restriction.cxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/restriction.hxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/schema-per-type.cxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/schema-per-type.hxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/simplifier.cxx create mode 100644 libxsd-frontend/xsd-frontend/transformations/simplifier.hxx (limited to 'libxsd-frontend/xsd-frontend/transformations') diff --git a/libxsd-frontend/xsd-frontend/transformations/anonymous.cxx b/libxsd-frontend/xsd-frontend/transformations/anonymous.cxx new file mode 100644 index 0000000..118fd5d --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/anonymous.cxx @@ -0,0 +1,739 @@ +// file : xsd-frontend/transformations/anonymous.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include + +using std::wcerr; +using std::endl; + +namespace XSDFrontend +{ + using namespace Cult; + + typedef WideString String; + + namespace + { + using Transformations::AnonymousNameTranslator; + + class Context + { + public: + Context (SemanticGraph::Schema& schema_, + SemanticGraph::Path const& file, + AnonymousNameTranslator& trans_, + Boolean du) + : schema_path_ (file), + ns_ (0), + failed_ (false), + trans (trans_), + detect_unstable (du), + schema (schema_), + schema_path (schema_path_), + ns (ns_), + failed (failed_) + { + + } + + protected: + Context (Context& c) + : trans (c.trans), + detect_unstable (c.detect_unstable), + schema (c.schema), + schema_path (c.schema_path), + ns (c.ns), + failed (c.failed) + { + } + + public: + struct UnstableConflict + { + UnstableConflict (SemanticGraph::Type& type) + : type_ (type) + { + } + + SemanticGraph::Type& + type () const + { + return type_; + } + + private: + SemanticGraph::Type& type_; + }; + + Boolean + conflict (String const& name) + { + using SemanticGraph::Type; + using SemanticGraph::Schema; + + if (Type* t1 = find (schema, name)) + { + // Check if this is a stable conflict. A conflict is unstable + // if a conflicting type is visible from the root schema but + // is not visible from the schema where the conflicting + // element is defined. + // + if (detect_unstable) + { + Schema& s (dynamic_cast (ns->scope ())); + + Type* t2 (find (s, name)); + + if (t1 != t2) + throw UnstableConflict (*t1); + } + + return true; + } + + return false; + } + + SemanticGraph::Type* + find (SemanticGraph::Schema& schema, String const& name) + { + using SemanticGraph::Type; + using SemanticGraph::Scope; + using SemanticGraph::Namespace; + + String ns_name (ns->name ()); + + // Get all namespaces across include/import hierarchy with + // our namespace name. + // + Scope::NamesIteratorPair nip (schema.find (ns_name)); + + for (; nip.first != nip.second; ++nip.first) + { + Namespace& ns (dynamic_cast (nip.first->named ())); + + Scope::NamesIteratorPair types (ns.find (name)); + + for (; types.first != types.second; ++types.first) + { + if (Type* t = dynamic_cast (&types.first->named ())) + { + return t; + } + } + } + + return 0; + } + + public: + SemanticGraph::Path + path (SemanticGraph::Nameable& n) + { + using SemanticGraph::Scope; + using SemanticGraph::Schema; + using SemanticGraph::Uses; + + Schema* schema (0); + + for (Scope* s (dynamic_cast (&n) + ? dynamic_cast (&n) : &n.scope ());; + s = &s->scope ()) + { + if ((schema = dynamic_cast (s))) + break; + } + + if (!schema->used_p ()) + return schema_path; + + Uses& u (*schema->used_begin ()); + return u.path (); + } + + public: + String + xpath (SemanticGraph::Nameable& n) + { + if (dynamic_cast (&n) != 0) + return L""; // There is a bug if you see this. + + assert (n.named_p ()); + + SemanticGraph::Scope& scope (n.scope ()); + + if (dynamic_cast (&scope) != 0) + return n.name (); + + return xpath (scope) + L"/" + n.name (); + } + + private: + SemanticGraph::Path const schema_path_; + SemanticGraph::Namespace* ns_; + Boolean failed_; + + public: + AnonymousNameTranslator& trans; + Boolean detect_unstable; + + public: + SemanticGraph::Schema& schema; + SemanticGraph::Path const& schema_path; + SemanticGraph::Namespace*& ns; + Boolean& failed; + }; + + + // 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-anonymous-seen")) + { + s.context ().set ("xsd-frontend-anonymous-seen", true); + Traversal::Uses::traverse (u); + } + } + }; + + // Keep track which namespace we are in. + // + struct Namespace: Traversal::Namespace + { + Namespace (SemanticGraph::Namespace*& ns) + : ns_ (ns) + { + } + + Void + pre (SemanticGraph::Namespace& ns) + { + ns_ = &ns; + } + + Void + post (SemanticGraph::Namespace&) + { + ns_ = 0; + } + + private: + SemanticGraph::Namespace*& ns_; + }; + + // + // + struct Type: Traversal::List, + Traversal::Union, + Traversal::Complex, + protected virtual Context + { + Type (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::List& l) + { + SemanticGraph::Type& t (l.argumented ().type ()); + + //@@ This IDREF stuff is really ugly! + // + if (!t.named_p () && + !t.is_a () && + !t.is_a ()) + { + try + { + // Run the name through the translation service. + // + SemanticGraph::Path file (path (l)); + String file_str; + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + try + { + file_str = file.string (); + } + catch (SemanticGraph::InvalidPath const&) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_str = file.native_file_string (); +#else + file_str = file.string (); +#endif + } + + String name ( + trans.translate ( + file_str, ns->name (), l.name () + L"_item", xpath (l))); + + // Make sure the name is unique. + // + UnsignedLong n (1); + String escaped (name); + + while (conflict (escaped)) + { + std::wostringstream os; + os << n++; + escaped = name + os.str (); + } + + t.context ().set ("anonymous", true); + schema.new_edge (*ns, t, escaped); + } + catch (UnstableConflict const& ex) + { + SemanticGraph::Type& t (ex.type ()); + + wcerr << l.file () << ":" << l.line () << ":" << l.column () + << ": error: list type name '" << xpath (l) << "' " + << "creates an unstable conflict when used as a base " + << "for the item type name" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: conflicting type is defined here" << endl; + + wcerr << l.file () << ":" << l.line () << ":" << l.column () + << ": info: " + << "use --anonymous-regex to resolve this conflict" + << endl; + + wcerr << l.file () << ":" << l.line () << ":" << l.column () + << ": info: " + << "and don't forget to pass the same option when " + << "translating '" << l.file ().leaf () << "' and all " + << "the schemas that refer to it" << endl; + + failed = true; + } + } + } + + virtual Void + traverse (SemanticGraph::Union& u) + { + String file_str; + + for (SemanticGraph::Union::ArgumentedIterator i ( + u.argumented_begin ()); i != u.argumented_end (); ++i) + { + SemanticGraph::Type& t (i->type ()); + + if (!t.named_p () && + !t.is_a () && + !t.is_a ()) + { + try + { + // Run the name through the translation service. + // + + if (!file_str) + { + SemanticGraph::Path file (path (u)); + + // Try to use the portable representation of the path. If + // that fails, fall back to the native representation. + // + try + { + file_str = file.string (); + } + catch (SemanticGraph::InvalidPath const&) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_str = file.native_file_string (); +#else + file_str = file.string (); +#endif + } + } + + String name ( + trans.translate ( + file_str, ns->name (), u.name () + L"_member", xpath (u))); + + // Make sure the name is unique. + // + UnsignedLong n (1); + String escaped (name); + + while (conflict (escaped)) + { + std::wostringstream os; + os << n++; + escaped = name + os.str (); + } + + t.context ().set ("anonymous", true); + schema.new_edge (*ns, t, escaped); + } + catch (UnstableConflict const& ex) + { + SemanticGraph::Type& t (ex.type ()); + + wcerr << u.file () << ":" << u.line () << ":" << u.column () + << ": error: union type name '" << xpath (u) << "' " + << "creates an unstable conflict when used as a base " + << "for the member type name" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: conflicting type is defined here" << endl; + + wcerr << u.file () << ":" << u.line () << ":" << u.column () + << ": info: " + << "use --anonymous-regex to resolve this conflict" + << endl; + + wcerr << u.file () << ":" << u.line () << ":" << u.column () + << ": info: " + << "and don't forget to pass the same option when " + << "translating '" << u.file ().leaf () << "' and all " + << "the schemas that refer to it" << endl; + + failed = true; + } + } + } + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (!c.inherits_p ()) + return; + + SemanticGraph::Type& t (c.inherits ().base ()); + + //@@ This IDREF stuff is really ugly! + // + if (!t.named_p () && + !t.is_a () && + !t.is_a ()) + { + try + { + // Run the name through the translation service. + // + SemanticGraph::Path file (path (c)); + String file_str; + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + try + { + file_str = file.string (); + } + catch (SemanticGraph::InvalidPath const&) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_str = file.native_file_string (); +#else + file_str = file.string (); +#endif + } + + String name ( + trans.translate ( + file_str, ns->name (), c.name () + L"_base", xpath (c))); + + // Make sure the name is unique. + // + UnsignedLong n (1); + String escaped (name); + + while (conflict (escaped)) + { + std::wostringstream os; + os << n++; + escaped = name + os.str (); + } + + t.context ().set ("anonymous", true); + schema.new_edge (*ns, t, escaped); + } + catch (UnstableConflict const& ex) + { + SemanticGraph::Type& t (ex.type ()); + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": error: simple type name '" << xpath (c) << "' " + << "creates an unstable conflict when used as a base " + << "for the base type name" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: conflicting type is defined here" << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: " + << "use --anonymous-regex to resolve this conflict" + << endl; + + wcerr << c.file () << ":" << c.line () << ":" << c.column () + << ": info: " + << "and don't forget to pass the same option when " + << "translating '" << c.file ().leaf () << "' and all " + << "the schemas that refer to it" << endl; + + failed = true; + } + } + } + }; + + + // + // + struct Member: Traversal::Element, + Traversal::Attribute, + protected virtual Context + { + Member (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + //@@ This IDREF stuff is really ugly! + // + if (!t.named_p () && + !t.is_a () && + !t.is_a ()) + { + try + { + traverse_ (e); + } + catch (UnstableConflict const& ex) + { + SemanticGraph::Type& t (ex.type ()); + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: element name '" << xpath (e) << "' " + << "creates an unstable conflict when used as a type name" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: conflicting type is defined here" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: " + << "use --anonymous-regex to resolve this conflict" + << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: " + << "and don't forget to pass the same option when " + << "translating '" << e.file ().leaf () << "' and all " + << "the schemas that refer to it" << endl; + + failed = true; + } + } + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + SemanticGraph::Type& t (a.type ()); + + //@@ This IDREF stuff us really ugly! + // + if (!t.named_p () && + !t.is_a () && + !t.is_a ()) + { + try + { + traverse_ (a); + } + catch (UnstableConflict const& ex) + { + SemanticGraph::Type& t (ex.type ()); + + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": error: attribute name '" << xpath (a) << "' " + << "creates an unstable conflict when used as a type name" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: conflicting type is defined here" << endl; + + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": info: " + << "use --anonymous-regex to resolve this conflict" + << endl; + + wcerr << a.file () << ":" << a.line () << ":" << a.column () + << ": info: " + << "and don't forget to pass the same option when " + << "translating '" << a.file ().leaf () << "' and all " + << "the schemas that refer to it" << endl; + + failed = true; + } + } + } + + Void + traverse_ (SemanticGraph::Member& m) + { + using SemanticGraph::Type; + + Type& t (m.type ()); + + // Normally this will be the member which also "defined" the type. + // However, in some cases of cyclic schema inclusion, this does + // not happen. As a result we need an extra check that will make + // sure we create the Names edge in the same Schema node as the + // one which contains the member which initially defined this + // type. See the cyclic-inclusion test for an example. + // + + // Find the first member that this type classifies. + // + for (Type::ClassifiesIterator i (t.classifies_begin ()); + i != t.classifies_end (); ++i) + { + SemanticGraph::Instance& inst (i->instance ()); + + if (inst.is_a ()) + { + // If it is the same member as the one we are traversing, + // then continue. + // + if (&inst == &m) + break; + else + return; + } + } + + // Run the name through the translation service. + // + SemanticGraph::Path file (path (m)); + String file_str; + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + try + { + file_str = file.string (); + } + catch (SemanticGraph::InvalidPath const&) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_str = file.native_file_string (); +#else + file_str = file.string (); +#endif + } + + String name ( + trans.translate (file_str, ns->name (), m.name (), xpath (m))); + + // Make sure the name is unique. + // + UnsignedLong n (1); + String escaped (name); + + while (conflict (escaped)) + { + std::wostringstream os; + os << n++; + escaped = name + os.str (); + } + + t.context ().set ("anonymous", true); + schema.new_edge (*ns, t, escaped); + } + }; + } + + namespace Transformations + { + Anonymous:: + Anonymous (AnonymousNameTranslator& trans) + : trans_ (trans) + { + } + + Void Anonymous:: + transform (SemanticGraph::Schema& s, + SemanticGraph::Path const& f, + Boolean duc) + { + Context ctx (s, f, trans_, duc); + + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Namespace ns (ctx.ns); + Traversal::Names ns_names_member; + Traversal::Names ns_names_type; + + schema >> schema_names >> ns; + ns >> ns_names_member; + ns >> ns_names_type; + + Type type (ctx); + ns_names_type >> type; + + Traversal::Scope scope; // Goes to both types and groups. + Member member (ctx); + + ns_names_member >> scope; + ns_names_member >> member; + + Traversal::Names names; + + scope >> names >> member; + + // Some twisted schemas do recusive inclusions. + // + s.context ().set ("xsd-frontend-anonymous-seen", true); + + schema.dispatch (s); + + if (ctx.failed) + throw Failed (); + } + + AnonymousNameTranslator:: + ~AnonymousNameTranslator () + { + } + } +} diff --git a/libxsd-frontend/xsd-frontend/transformations/anonymous.hxx b/libxsd-frontend/xsd-frontend/transformations/anonymous.hxx new file mode 100644 index 0000000..2409822 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/anonymous.hxx @@ -0,0 +1,60 @@ +// file : xsd-frontend/transformations/anonymous.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_FRONTEND_TRANSFORMATIONS_ANONYMOUS_HXX +#define XSD_FRONTEND_TRANSFORMATIONS_ANONYMOUS_HXX + +#include + +#include // Path +#include + +namespace XSDFrontend +{ + namespace Transformations + { + using namespace Cult::Types; + + class AnonymousNameTranslator + { + public: + virtual + ~AnonymousNameTranslator (); + + // The file argument is empty for the currect translation + // unit. + // + virtual WideString + translate (WideString const& file, + WideString const& ns, + WideString const& name, + WideString const& xpath) = 0; + }; + + // This transformation morphs anonymous types into named ones + // with the names derived from the enclosing attributes and + // elements. If the detect_unstable_conflicts argument is true + // then the transformation detects and reports unstable conflicts + // in name assignment. + // + class Anonymous + { + public: + struct Failed {}; + + Anonymous (AnonymousNameTranslator&); + + Void + transform (SemanticGraph::Schema&, + SemanticGraph::Path const&, + Boolean detect_unstable_conflicts); + + private: + AnonymousNameTranslator& trans_; + }; + } +} + +#endif // XSD_FRONTEND_TRANSFORMATIONS_ANONYMOUS_HXX 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..e10b9d3 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.cxx @@ -0,0 +1,249 @@ +// file : xsd-frontend/transformations/enum-synthesis.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +namespace XSDFrontend +{ + using namespace Cult; + typedef WideString String; + + namespace + { + typedef Cult::Containers::Set 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 (e.file (), e.line (), e.column ())); + + schema_.new_edge (enum_, c, name); + schema_.new_edge (c, enum_); + + if (e.annotated_p ()) + schema_.new_edge (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 ()) + { + // 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 ()) + 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 ( + u.file (), u.line (), u.column ())); + + schema_.new_edge (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); + } + } +} diff --git a/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.hxx b/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.hxx new file mode 100644 index 0000000..e3c38c7 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/enum-synthesis.hxx @@ -0,0 +1,33 @@ +// file : xsd-frontend/transformations/enum-synthesis.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_FRONTEND_TRANSFORMATIONS_ENUM_SYNTHESIS_HXX +#define XSD_FRONTEND_TRANSFORMATIONS_ENUM_SYNTHESIS_HXX + +#include + +#include // Path +#include + +namespace XSDFrontend +{ + namespace Transformations + { + using namespace Cult::Types; + + // This transformation replaces unions of one or more enumerations + // with the same base with an equivalent synthesized enumeration. + // This transformation assumes that there are no anonymous types. + // + class EnumSynthesis + { + public: + Void + transform (SemanticGraph::Schema&, SemanticGraph::Path const&); + }; + } +} + +#endif // XSD_FRONTEND_TRANSFORMATIONS_ENUM_SYNTHESIS_HXX diff --git a/libxsd-frontend/xsd-frontend/transformations/restriction.cxx b/libxsd-frontend/xsd-frontend/transformations/restriction.cxx new file mode 100644 index 0000000..c58d98f --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/restriction.cxx @@ -0,0 +1,582 @@ +// file : xsd-frontend/transformations/restriction.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +#include + +using std::wcerr; +using std::endl; + +namespace XSDFrontend +{ + using namespace Cult; + + typedef WideString String; + typedef Transformations::Restriction::Failed Failed; + typedef Containers::Vector BaseList; + + namespace + { + // + // + struct Complex: Traversal::Complex + { + Complex (SemanticGraph::Schema& schema) + : schema_ (schema) + { + } + + virtual Void + traverse (Type& c) + { + using namespace SemanticGraph; + using SemanticGraph::Complex; + + if (c.context ().count ("xsd-frontend-restriction-seen")) + return; + + c.context ().set ("xsd-frontend-restriction-seen", true); + + // The base content model can be spread over several types + // in the inheritance-by-extension hierarchy. + // + BaseList base_model; + + // Since attribute wildcards don't have names, we will have + // to rely on their relative position to find association. + // + BaseList base_list; + + // Current implementation of semantic graph uses the same Restricts + // edge for both simple type/content restriction and complex content + // restriction. Here we are interested in the complex content only. + // + // + if (c.inherits_p () && + c.inherits ().is_a () && + !c.inherits ().base ().is_a ()) + { + // Go down our inheritance hierarchy until the end or the previous + // restriction. + // + Complex* base (&c); + + while ((base = dynamic_cast (&base->inherits ().base ()))) + { + traverse (*base); // Make sure our base is processed. + + // Handle attributes. + // + merge_attributes (c, *base); + + base_list.push_back (base); + + // Collect types that have complex content. + // + if (base->contains_compositor_p ()) + base_model.push_back (base); + + if (!base->inherits_p () || base->inherits ().is_a ()) + break; + } + + // Handle attribute wildcards. + // + handle_any_attributes (c, base_list); + + // Handle complex content (not for the faint of heart). + // + if (c.contains_compositor_p ()) + { + // Traverse both restricted content model and base content + // model (in base_model) while looking for matches. + // + Compositor& root (c.contains_compositor ().compositor ()); + + if (base_model.size () == 1) + handle (root, + base_model[0]->contains_compositor ().compositor ()); + else + { + Compositor::ContainsIterator i (root.contains_begin ()); + BaseList::ReverseIterator j (base_model.rbegin ()); + + for (; i != root.contains_end (); ++i, ++j) + { + Particle& p (i->particle ()); + + if (!p.is_a ()) + { + wcerr << p.file () << ":" << p.line () << ":" << p.column () + << ": error: expected compositor instead of particle" + << endl; + throw Failed (); + } + + for (; j != base_model.rend (); ++j) + { + if (match (p, (*j)->contains_compositor ().compositor ())) + { + handle (p, (*j)->contains_compositor ().compositor ()); + break; + } + } + + if (j == base_model.rend ()) + break; + } + + if (i != root.contains_end ()) + { + Particle& p (i->particle ()); + + wcerr << p.file () << ":" << p.line () << ":" << p.column () + << ": error: unable to match restricted compositor" + << endl; + throw Failed (); + } + } + } + } + + // Traverse anonymous types (via elements & attributes). + // + Traversal::Complex::names (c); + } + + private: + Void + handle (SemanticGraph::Particle& r, SemanticGraph::Particle& b) + { + using namespace SemanticGraph; + + if (r.is_a ()) + { + Compositor& rc (dynamic_cast (r)); + Compositor& bc (dynamic_cast (b)); + + Compositor::ContainsIterator i (rc.contains_begin ()); + Compositor::ContainsIterator j (bc.contains_begin ()); + + for (; i != rc.contains_end (); ++i, ++j) + { + for (; j != bc.contains_end (); ++j) + { + Particle& rp (i->particle ()); + Particle& bp (j->particle ()); + + if (typeid (rp) != typeid (bp)) + continue; + + if (match (rp, bp)) + { + handle (rp, bp); + break; + } + } + + if (j == bc.contains_end ()) + break; + } + + if (i != rc.contains_end ()) + { + Particle& p (i->particle ()); + + wcerr << p.file () << ":" << p.line () << ":" << p.column () + << ": error: unable to match restricted particle" + << endl; + throw Failed (); + } + + rc.context ().set ("xsd-frontend-restriction-correspondence", &bc); + } + else if (r.is_a ()) + { + // Element + // + r.context ().set ("xsd-frontend-restriction-correspondence", + dynamic_cast (&b)); + } + else + { + // Wildcard + // + r.context ().set ("xsd-frontend-restriction-correspondence", + dynamic_cast (&b)); + } + } + + Boolean + match (SemanticGraph::Particle& r, SemanticGraph::Particle& b) + { + using namespace SemanticGraph; + + if (typeid (r) != typeid (b)) + return false; + + if (r.is_a ()) + { + Compositor& rc (dynamic_cast (r)); + Compositor& bc (dynamic_cast (b)); + + Compositor::ContainsIterator i (rc.contains_begin ()); + + if (i == rc.contains_end ()) + return true; + + Particle& rp (i->particle ()); + + for (Compositor::ContainsIterator j (bc.contains_begin ()); + j != bc.contains_end (); ++j) + { + Particle& bp (j->particle ()); + + if (typeid (rp) != typeid (bp)) + continue; + + if (match (rp, bp)) + return true; + } + } + else if (r.is_a ()) + { + Element& re (dynamic_cast (r)); + Element& be (dynamic_cast (b)); + + if (re.qualified_p ()) + { + if (be.qualified_p () && + re.name () == be.name () && + re.namespace_ ().name () == be.namespace_ ().name ()) + return true; + } + else + { + if (!be.qualified_p () && re.name () == be.name ()) + return true; + } + + // @@ Need to take into account substitution groups. + // + } + else + { + // Wildcard. + // + + // @@ To handle this properly we will need to analyze + // namespaces. + // + return true; + } + + return false; + } + + Void + merge_attributes (SemanticGraph::Complex& c, + SemanticGraph::Complex& base) + { + using namespace SemanticGraph; + + for (Scope::NamesIterator i (base.names_begin ()), + e (base.names_end ()); i != e; ++i) + { + Attribute* prot (dynamic_cast (&i->named ())); + + if (prot == 0) + continue; + + Name name (prot->name ()); + Scope::NamesIteratorPair r (c.find (name)); + + Attribute* a (0); + + for (; r.first != r.second; ++r.first) + { + a = dynamic_cast (&r.first->named ()); + + if (a == 0) + continue; + + if (prot->qualified_p ()) + { + if (a->qualified_p () && + prot->namespace_ ().name () == a->namespace_ ().name ()) + { + break; + } + } + else + { + if (!a->qualified_p ()) + break; + } + + a = 0; + } + + if (a == 0) + { + a = &schema_.new_node (prot->file (), + prot->line (), + prot->column (), + prot->optional_p (), + prot->global_p (), + prot->qualified_p ()); + + schema_.new_edge (c, *a, name); + + // Transfer namespace. + // + if (prot->qualified_p ()) + { + schema_.new_edge (*a, prot->namespace_ ()); + } + + // Default and fixed values if any. + // + if (prot->fixed_p ()) + a->fixed (prot->value ()); + else if (prot->default_p ()) + a->default_ (prot->value ()); + + // Belongs edge. + // + schema_.new_edge (*a, prot->type ()); + + // Transfer annotation. + // + if (prot->annotated_p ()) + schema_.new_edge (prot->annotation (), *a); + } + + a->context ().set ("xsd-frontend-restriction-correspondence", prot); + } + } + + Void + handle_any_attributes (SemanticGraph::Complex& c, BaseList& bl) + { + using namespace SemanticGraph; + + BaseList::ReverseIterator bi (bl.rbegin ()), be (bl.rend ()); + Scope::NamesIterator si; + + if (bi != be) + si = (*bi)->names_begin (); + + for (Scope::NamesIterator i (c.names_begin ()), + e (c.names_end ()); i != e; ++i) + { + AnyAttribute* a (dynamic_cast (&i->named ())); + + if (a == 0) + continue; + + AnyAttribute* p (0); + + while (bi != be) + { + for (; si != (*bi)->names_end (); ++si) + { + p = dynamic_cast (&si->named ()); + + if (p != 0) + { + ++si; + break; + } + } + + if (p != 0) + break; + + // Didn't find anything in this base. Move on to the next. + // + ++bi; + + if (bi != be) + si = (*bi)->names_begin (); + } + + if (p != 0) + { + a->context ().set ("xsd-frontend-restriction-correspondence", p); + } + else + { + wcerr << a->file () << ":" << a->line () << ":" << a->column () + << ": error: unable to find matching wildcard in base type" + << endl; + throw Failed (); + } + } + } + + private: + SemanticGraph::Schema& schema_; + }; + + // + // + struct Anonymous : Traversal::Element, + Traversal::Attribute + { + Anonymous (Traversal::NodeDispatcherBase& d1) + : complex_ (&d1, 0) + { + *this >> belongs_ >> complex_; + } + + Anonymous (Traversal::NodeDispatcherBase& d1, + Traversal::NodeDispatcherBase& d2) + : complex_ (&d1, &d2) + { + *this >> belongs_ >> complex_; + } + + // Hooks. + // + public: + virtual void + member_pre (SemanticGraph::Member&) + { + } + + virtual void + member_post (SemanticGraph::Member&) + { + } + + public: + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + if (!t.named_p () && !t.context ().count ("seen")) + { + t.context ().set ("seen", true); + + member_pre (e); + + Element::belongs (e, belongs_); + + member_post (e); + + t.context ().remove ("seen"); + } + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + SemanticGraph::Type& t (a.type ()); + + if (!t.named_p () && !t.context ().count ("seen")) + { + t.context ().set ("seen", true); + + member_pre (a); + + Attribute::belongs (a, belongs_); + + member_post (a); + + t.context ().remove ("seen"); + } + } + + private: + struct Complex : Traversal::Complex + { + Complex (Traversal::NodeDispatcherBase* d1, + Traversal::NodeDispatcherBase* d2) + : d1_ (d1), d2_ (d2) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (d1_) + d1_->dispatch (c); + + if (d2_) + d2_->dispatch (c); + } + + private: + Traversal::NodeDispatcherBase* d1_; + Traversal::NodeDispatcherBase* d2_; + + } complex_; + + Traversal::Belongs belongs_; + }; + + + // 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-restriction-seen")) + { + s.context ().set ("xsd-frontend-restriction-seen", true); + Traversal::Uses::traverse (u); + } + } + }; + } + + namespace Transformations + { + Void Restriction:: + 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; + + schema >> schema_names >> ns >> ns_names; + + Complex complex_type (s); + Anonymous anonymous (complex_type); + + ns_names >> complex_type; + ns_names >> anonymous; + + Traversal::Names names; + + complex_type >> names >> anonymous; + + // Some twisted schemas do recusive inclusions. + // + s.context ().set ("xsd-frontend-restriction-seen", true); + + schema.dispatch (s); + } + } +} diff --git a/libxsd-frontend/xsd-frontend/transformations/restriction.hxx b/libxsd-frontend/xsd-frontend/transformations/restriction.hxx new file mode 100644 index 0000000..7c3282e --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/restriction.hxx @@ -0,0 +1,39 @@ +// file : xsd-frontend/transformations/restriction.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_FRONTEND_TRANSFORMATIONS_RESTRICTION_HXX +#define XSD_FRONTEND_TRANSFORMATIONS_RESTRICTION_HXX + +#include + +#include // Path +#include + +namespace XSDFrontend +{ + namespace Transformations + { + using namespace Cult::Types; + + // This transformation performs two major tasks. It transfers omitted + // attribute declarations from the base to derived-by-restriction type + // and establishes correspondence between particles and compositors by + // adding the "xsd-frontend-restriction-correspondence" key-value pair + // in the context that contains a pointer to the corresponding particle + // or compositor in the base. Note that restriction of anyType is + // a special case and is not handled by this transformation. + // + class Restriction + { + public: + struct Failed {}; + + Void + transform (SemanticGraph::Schema&, SemanticGraph::Path const&); + }; + } +} + +#endif // XSD_FRONTEND_TRANSFORMATIONS_RESTRICTION_HXX diff --git a/libxsd-frontend/xsd-frontend/transformations/schema-per-type.cxx b/libxsd-frontend/xsd-frontend/transformations/schema-per-type.cxx new file mode 100644 index 0000000..9ac8445 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/schema-per-type.cxx @@ -0,0 +1,453 @@ +// file : xsd-frontend/transformations/schema-per-type.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include // strcasecmp + +using std::wcerr; +using std::endl; + +namespace XSDFrontend +{ + using namespace Cult; + + typedef WideString String; + typedef Transformations::SchemaPerType::Failed Failed; + + typedef Containers::Vector Schemas; + typedef Containers::Map TypeSchemaMap; + + // Compare file paths case-insensitively. + // + struct FileComparator + { + Boolean + operator() (NarrowString const& x, NarrowString const& y) const + { + return strcasecmp (x.c_str (), y.c_str ()) < 0; + } + }; + + typedef Containers::Set FileSet; + + namespace + { + // Go into included and imported schemas while making sure + // we don't process the same stuff more than once. + // + struct Uses: Traversal::Includes, + Traversal::Imports, + Traversal::Implies + { + Uses (Schemas& schemas, SemanticGraph::Schema*& xsd) + : schemas_ (schemas), xsd_ (xsd) + { + xsd_ = 0; + } + + virtual Void + traverse (SemanticGraph::Includes& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("xsd-frontend-schema-per-type-seen")) + { + schemas_.push_back (&s); + s.context ().set ("xsd-frontend-schema-per-type-seen", true); + Traversal::Includes::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Imports& i) + { + SemanticGraph::Schema& s (i.schema ()); + + if (!s.context ().count ("xsd-frontend-schema-per-type-seen")) + { + schemas_.push_back (&s); + s.context ().set ("xsd-frontend-schema-per-type-seen", true); + Traversal::Imports::traverse (i); + } + } + + virtual Void + traverse (SemanticGraph::Implies& i) + { + if (xsd_ == 0) + xsd_ = &i.schema (); + } + + private: + Schemas& schemas_; + SemanticGraph::Schema*& xsd_; + }; + + Void + process_schema (SemanticGraph::Schema& s, + SemanticGraph::Schema& root, + SemanticGraph::Schema& xsd, + TypeSchemaMap& tsm, + FileSet& file_set, + Transformations::SchemaPerTypeTranslator& trans) + { + using namespace SemanticGraph; + + Path xsd_path ("XMLSchema.xsd"); + Namespace& ns (dynamic_cast (s.names_begin ()->named ())); + + // We should be careful with iterator caching since we are going to + // remove some of the nodes. + // + for (Scope::NamesIterator i (ns.names_begin ()); i != ns.names_end ();) + { + Nameable& n (i->named ()); + + if (n.is_a ()) + { + String name (n.name ()); + + // Remove from the namespace. + // + Scope::NamesIterator tmp (i++); + root.delete_edge (ns, n, *tmp); + + // Add a new schema node. + // + Path path; + String tn (trans.translate_type (ns.name (), name)); + String wbase (tn ? tn : name); + + try + { + NarrowString base (wbase.to_narrow ()); + + // Escape directory separators unless they came from the + // translator. + // + if (!tn) + { + for (NarrowString::Iterator i (base.begin ()), e (base.end ()); + i != e; ++i) + { + if (*i == '/' || *i == '\\') + *i = '_'; + } + } + + // Make sure it is unique. + // + NarrowString file_name (base); + + for (UnsignedLong i (1); + file_set.find (file_name) != file_set.end (); + ++i) + { + std::ostringstream os; + os << i; + file_name = base + os.str (); + } + + file_set.insert (file_name); + file_name += ".xsd"; + + try + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + path = Path (file_name); +#else + path = Path (file_name.c_str()); +#endif + } + catch (InvalidPath const&) + { + wcerr << "error: '" << file_name.c_str () << "' is not a valid " + << "filesystem path" << endl; + + wcerr << "info: use type to file name translation mechanism " + << "to resolve this" << endl; + + throw Failed (); + } + } + catch (String::NonRepresentable const&) + { + wcerr << "error: '" << wbase << "' cannot be represented as a " + << "narrow string" << endl; + + wcerr << "info: use type to file name translation mechanism " + << "to resolve this" << endl; + + throw Failed (); + } + + Schema& ts (root.new_node (path, 1, 1)); + root.new_edge (ts, xsd, xsd_path); + + Namespace& tns (root.new_node (path, 1, 1)); + root.new_edge (ts, tns, ns.name ()); + root.new_edge (tns, n, name); + + // Add include to the original schema and enter into the + // type-schema map. + // + root.new_edge (s, ts, path); + tsm[&dynamic_cast (n)] = &ts; + } + else + ++i; + } + } + + struct Type: Traversal::List, + Traversal::Complex, + Traversal::Member + { + Type (SemanticGraph::Schema& schema, + SemanticGraph::Schema& root, + Char const* by_value_key, + TypeSchemaMap& tsm) + : schema_ (schema), + root_ (root), + by_value_key_ (by_value_key), + tsm_ (tsm) + { + *this >> names_ >> *this; + } + + virtual Void + traverse (SemanticGraph::List& l) + { + // Treat item type as base type since it is impossible + // to create recursive constructs using list. + // + SemanticGraph::Type& t (l.argumented ().type ()); + set_dep (t, false); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.inherits_p ()) + set_dep (c.inherits ().base (), false); + + Traversal::Complex::names (c); + } + + virtual Void + traverse (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + Boolean weak ( + by_value_key_ == 0 || + !t.context ().count (by_value_key_) || + !t.context ().get (by_value_key_)); + + set_dep (t, weak); + } + + private: + Void + set_dep (SemanticGraph::Type& t, Boolean weak) + { + using namespace SemanticGraph; + + TypeSchemaMap::Iterator i (tsm_.find (&t)); + + // If a type is not present in the map then it must be + // a built-in type. + // + if (i == tsm_.end ()) + return; + + // Check if we already saw this type. Theoretically, it could + // be that we need to upgrade the type of include from weak to + // strong. But because inheritance is handled first, the type + // in the set will already be with the right type. + // + if (type_set_.find (&t) != type_set_.end ()) + return; + + type_set_.insert (&t); + + Schema& s (*i->second); + Path path (s.used_begin ()->path ()); + SemanticGraph::Uses* u; + + if (s.names_begin ()->name () == schema_.names_begin ()->name ()) + u = &root_.new_edge (schema_, s, path); + else + u = &root_.new_edge (schema_, s, path); + + if (weak) + u->context().set ("weak", true); + } + + private: + SemanticGraph::Schema& schema_; + SemanticGraph::Schema& root_; + Char const* by_value_key_; + TypeSchemaMap& tsm_; + Containers::Set type_set_; + + Traversal::Names names_; + }; + } + + namespace Transformations + { + SchemaPerType:: + SchemaPerType (SchemaPerTypeTranslator& trans, Char const* by_value_key) + : by_value_key_ (by_value_key), trans_ (trans) + { + } + + Schemas SchemaPerType:: + transform (SemanticGraph::Schema& root) + { + // Collect initial schema nodes. + // + Schemas schemas; + SemanticGraph::Schema* xsd; + + { + Traversal::Schema schema; + Uses uses (schemas, xsd); + + schema >> uses >> schema; + + // Some twisted schemas do recusive inclusions. + // + root.context ().set ("xsd-frontend-schema-per-type-seen", true); + + schema.dispatch (root); + } + + // wcerr << schemas.size () << " initial schema nodes" << endl; + + // Add the schema file names to the file set. + // + FileSet file_set; + + for (Schemas::Iterator i (schemas.begin ()); i != schemas.end (); ++i) + { + SemanticGraph::Path const& path ( + (*i)->context ().get ("absolute-path")); + + // Translate the schema file name. + // + NarrowString abs_path; + +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + try + { + abs_path = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + abs_path = path.native_file_string (); + } +#else + // The new ABI does not have a fallback native representation + abs_path = path.string (); +#endif + + NarrowString tf (trans_.translate_schema (abs_path)); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + NarrowString file (tf ? tf : path.leaf ()); +#else + NarrowString file (tf ? tf : path.filename ().string()); +#endif + + Size p (file.rfind ('.')); + NarrowString ext ( + p != NarrowString::npos ? NarrowString (file, p) : ""); + + NarrowString base ( + p != NarrowString::npos ? NarrowString (file, 0, p) : file); + + // Make sure it is unique. + // + NarrowString new_name (base); + + for (UnsignedLong n (1); + file_set.find (new_name) != file_set.end (); + ++n) + { + std::ostringstream os; + os << n; + new_name = base + os.str (); + } + + file_set.insert (new_name); + new_name += ext; + + try + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + (*i)->context ().set ("renamed", SemanticGraph::Path (new_name)); +#else + (*i)->context ().set ("renamed", SemanticGraph::Path (new_name.c_str())); +#endif + } + catch (SemanticGraph::InvalidPath const&) + { + wcerr << "error: '" << new_name.c_str () << "' is not a valid " + << "filesystem path" << endl; + + wcerr << "info: use schema file name translation mechanism " + << "to resolve this" << endl; + + throw Failed (); + } + } + + // Process each schema node. + // + TypeSchemaMap tsm; + + for (Schemas::Iterator i (schemas.begin ()); i != schemas.end (); ++i) + { + process_schema (**i, root, *xsd, tsm, file_set, trans_); + } + + // wcerr << tsm.size () << " type schema nodes" << endl; + + // Establish include/import dependencies. While at it add the + // new schemas to the list which we will return. + // + for (TypeSchemaMap::Iterator i (tsm.begin ()); i != tsm.end (); ++i) + { + SemanticGraph::Schema& s (*i->second); + Type t (s, root, by_value_key_, tsm); + t.dispatch (*i->first); + schemas.push_back (&s); + } + + return schemas; + } + + SchemaPerTypeTranslator:: + ~SchemaPerTypeTranslator () + { + } + } +} diff --git a/libxsd-frontend/xsd-frontend/transformations/schema-per-type.hxx b/libxsd-frontend/xsd-frontend/transformations/schema-per-type.hxx new file mode 100644 index 0000000..89b6d83 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/schema-per-type.hxx @@ -0,0 +1,61 @@ +// file : xsd-frontend/transformations/schema-per-type.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_FRONTEND_TRANSFORMATIONS_SCHEMA_PER_TYPE_HXX +#define XSD_FRONTEND_TRANSFORMATIONS_SCHEMA_PER_TYPE_HXX + +#include +#include + +#include // Path +#include + +namespace XSDFrontend +{ + namespace Transformations + { + using namespace Cult::Types; + + class SchemaPerTypeTranslator + { + public: + virtual + ~SchemaPerTypeTranslator (); + + // The following two functions should return empty string if + // there is no match. + // + virtual WideString + translate_type (WideString const& ns, WideString const& name) = 0; + + virtual NarrowString + translate_schema (NarrowString const& abs_path) = 0; + }; + + // This transformation restructures the semantic graph to have + // each type definition in a seperate schema file. + // + class SchemaPerType + { + public: + struct Failed {}; + + // If a type of an element or attribute has a context entry + // with the by_value_key key and it is true, then the schema + // for this type is included "strongly". + // + SchemaPerType (SchemaPerTypeTranslator&, Char const* by_value_key = 0); + + Cult::Containers::Vector + transform (SemanticGraph::Schema&); + + private: + Char const* by_value_key_; + SchemaPerTypeTranslator& trans_; + }; + } +} + +#endif // XSD_FRONTEND_TRANSFORMATIONS_SCHEMA_PER_TYPE_HXX diff --git a/libxsd-frontend/xsd-frontend/transformations/simplifier.cxx b/libxsd-frontend/xsd-frontend/transformations/simplifier.cxx new file mode 100644 index 0000000..2ccaed2 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/simplifier.cxx @@ -0,0 +1,167 @@ +// file : xsd-frontend/transformations/simplifier.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +namespace XSDFrontend +{ + using namespace Cult; + + namespace + { + struct Compositor: Traversal::All, + Traversal::Choice, + Traversal::Sequence + { + Compositor (SemanticGraph::Schema& root) + : root_ (root) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // The all compositor cannot contain compositors. + // + if (a.contains_begin () == a.contains_end ()) + remove (a); + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + // Do the depth-first traversal so that we take into account + // the potential removal of nested compositors. + // + using SemanticGraph::Compositor; + + for (Compositor::ContainsIterator i (c.contains_begin ()); + i != c.contains_end ();) + { + edge_traverser ().dispatch (*i++); + } + + Choice::contains (c); + + if (c.contains_begin () == c.contains_end ()) + remove (c); + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + // Do the depth-first traversal so that we take into account + // the potential removal of nested compositors. + // + using SemanticGraph::Compositor; + + for (Compositor::ContainsIterator i (s.contains_begin ()); + i != s.contains_end ();) + { + edge_traverser ().dispatch (*i++); + } + + if (s.contains_begin () == s.contains_end ()) + remove (s); + } + + private: + virtual Void + remove (SemanticGraph::Compositor& c) + { + using SemanticGraph::Node; + using SemanticGraph::Choice; + using SemanticGraph::Complex; + using SemanticGraph::Compositor; + + if (c.contained_particle_p ()) + { + Compositor& com (c.contained_particle ().compositor ()); + + // Empty compositors in choice are important. + // + if (!com.is_a ()) + root_.delete_edge (com, c, c.contained_particle ()); + } + else + { + Complex& con ( + dynamic_cast (c.contained_compositor ().container ())); + root_.delete_edge (con, c, c.contained_compositor ()); + } + } + + private: + SemanticGraph::Schema& root_; + }; + + // + // + struct Type: Traversal::Complex + { + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.contains_compositor_p ()) + Complex::contains_compositor (c); + } + }; + + // 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-simplifier-seen")) + { + s.context ().set ("xsd-frontend-simplifier-seen", true); + Traversal::Uses::traverse (u); + } + } + }; + } + + namespace Transformations + { + Void Simplifier:: + 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; + Type type; + + schema >> schema_names >> ns >> ns_names >> type; + + Compositor compositor (s); + Traversal::ContainsCompositor contains_compositor; + Traversal::ContainsParticle contains_particle; + + type >> contains_compositor >> compositor; + compositor >> contains_particle >> compositor; + + // Some twisted schemas do recusive inclusions. + // + s.context ().set ("xsd-frontend-simplifier-seen", true); + + schema.dispatch (s); + } + } +} diff --git a/libxsd-frontend/xsd-frontend/transformations/simplifier.hxx b/libxsd-frontend/xsd-frontend/transformations/simplifier.hxx new file mode 100644 index 0000000..676c166 --- /dev/null +++ b/libxsd-frontend/xsd-frontend/transformations/simplifier.hxx @@ -0,0 +1,33 @@ +// file : xsd-frontend/transformations/simplifier.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_FRONTEND_TRANSFORMATIONS_SIMPLIFIER_HXX +#define XSD_FRONTEND_TRANSFORMATIONS_SIMPLIFIER_HXX + +#include + +#include // Path +#include + +namespace XSDFrontend +{ + namespace Transformations + { + using namespace Cult::Types; + + // This transformation performs various schema simplifications + // (e.g., removing empty compositors, etc). This transformation + // assumes that there are no anonymous types. + // + class Simplifier + { + public: + Void + transform (SemanticGraph::Schema&, SemanticGraph::Path const&); + }; + } +} + +#endif // XSD_FRONTEND_TRANSFORMATIONS_SIMPLIFIER_HXX -- cgit v1.2.3