From 5e527213a2430bb3018e5eebd909aef294edf9b5 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 18 Dec 2020 18:48:46 +0300 Subject: Switch to build2 --- xsd/xsd/processing/cardinality/processor.cxx | 407 ++++++++++++++++++++++ xsd/xsd/processing/cardinality/processor.hxx | 28 ++ xsd/xsd/processing/inheritance/processor.cxx | 492 +++++++++++++++++++++++++++ xsd/xsd/processing/inheritance/processor.hxx | 28 ++ 4 files changed, 955 insertions(+) create mode 100644 xsd/xsd/processing/cardinality/processor.cxx create mode 100644 xsd/xsd/processing/cardinality/processor.hxx create mode 100644 xsd/xsd/processing/inheritance/processor.cxx create mode 100644 xsd/xsd/processing/inheritance/processor.hxx (limited to 'xsd/xsd/processing') diff --git a/xsd/xsd/processing/cardinality/processor.cxx b/xsd/xsd/processing/cardinality/processor.cxx new file mode 100644 index 0000000..c8c5dc5 --- /dev/null +++ b/xsd/xsd/processing/cardinality/processor.cxx @@ -0,0 +1,407 @@ +// file : xsd/processing/cardinality/processor.cxx +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include +#include + +#include + +#include + +using namespace std; + +namespace Processing +{ + namespace SemanticGraph = XSDFrontend::SemanticGraph; + namespace Traversal = XSDFrontend::Traversal; + + namespace Cardinality + { + namespace + { + // + // + struct ElementInfo + { + ElementInfo () + : min (0), max (0), e_ (0) + { + } + + ElementInfo (SemanticGraph::Element& e) + : min (1), max (1), e_ (&e) + { + } + + ElementInfo (SemanticGraph::Element& e, size_t min_, size_t max_) + : min (min_), max (max_), e_ (&e) + { + } + + SemanticGraph::Element& + element () + { + assert (e_ != 0); + return *e_; + } + + public: + size_t min, max; + + private: + SemanticGraph::Element* e_; + }; + + typedef map ElementInfoMap; + + // + // + struct AnyInfo + { + AnyInfo () + : min (0), max (0), a_ (0) + { + } + + AnyInfo (SemanticGraph::Any& a) + : min (1), max (1), a_ (&a) + { + } + + AnyInfo (SemanticGraph::Any& a, size_t min_, size_t max_) + : min (min_), max (max_), a_ (&a) + { + } + + SemanticGraph::Any& + any () + { + assert (a_ != 0); + return *a_; + } + + public: + size_t min, max; + + private: + SemanticGraph::Any* a_; + }; + + typedef map AnyInfoMap; + + // + // + struct Particle: Traversal::All, + Traversal::Choice, + Traversal::Sequence, + Traversal::Element, + Traversal::Any + { + virtual void + traverse (SemanticGraph::All& a) + { + traverse_sequence (a); + } + + virtual void + traverse (SemanticGraph::Choice& c) + { + using SemanticGraph::Compositor; + + // Go over all particles we contain and add them to the map. + // + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + Particle t; + t.dispatch (ci->particle ()); + + // Handle elements. + // + if (ci == c.contains_begin ()) + el_map = t.el_map; // First arm. + else + { + // For elements that are in the map but not in this + // arm of choice, we need to set min to 0 while for + // those that are we need to choose minimum between + // the two for min and maximum for max. + // + for (ElementInfoMap::iterator i (el_map.begin ()); + i != el_map.end (); ++i) + { + String const& name (i->first); + ElementInfo& ei (i->second); + + ElementInfoMap::iterator j (t.el_map.find (name)); + + if (j == t.el_map.end ()) + ei.min = 0; + else + { + ei.min = j->second.min < ei.min ? j->second.min : ei.min; + + // Unbounded is encoded as 0. + // + if (j->second.max == 0 || ei.max == 0) + ei.max = 0; + else + ei.max = j->second.max > ei.max ? j->second.max : ei.max; + } + } + + // Now elements that are in this arm of choice but are + // not in the map, we need to add to the map and set their + // min to 0. + // + for (ElementInfoMap::iterator i (t.el_map.begin ()); + i != t.el_map.end (); ++i) + { + String const& name (i->first); + ElementInfo& ei (i->second); + + ElementInfoMap::iterator j (el_map.find (name)); + + if (j == el_map.end ()) + el_map[name] = ElementInfo (ei.element (), 0, ei.max); + } + } + + // Handle wildcards. Since each wildcard is treated as unique, + // we need to copy them from each arm of choice and set min to + // 0. + // + for (AnyInfoMap::iterator i (t.any_map.begin ()); + i != t.any_map.end (); ++i) + { + String const& name (i->first); + AnyInfo& ai (i->second); + + assert (any_map.find (name) == any_map.end ()); + + any_map[name] = AnyInfo (ai.any (), 0, ai.max); + } + } + + // Choice's min and max. + // + size_t cmin (c.min ()), cmax (c.max ()); + + // Iterate over elements and wildcards in the maps and multiply + // their cardinality by cmin and cmax. + // + for (ElementInfoMap::iterator i (el_map.begin ()); + i != el_map.end (); ++i) + { + i->second.min *= cmin; + i->second.max *= cmax; + } + + for (AnyInfoMap::iterator i (any_map.begin ()); + i != any_map.end (); ++i) + { + i->second.min *= cmin; // Not really necessary since min == 0. + i->second.max *= cmax; + } + } + + virtual void + traverse (SemanticGraph::Sequence& s) + { + traverse_sequence (s); + } + + void + traverse_sequence (SemanticGraph::Compositor& c) + { + using SemanticGraph::Compositor; + + // Sequence's min and max. + // + size_t smin (c.min ()), smax (c.max ()); + + // Go over all particles we contain and add them to the map. + // + for (Compositor::ContainsIterator ci (c.contains_begin ()); + ci != c.contains_end (); ++ci) + { + Particle t; + t.dispatch (ci->particle ()); + + // Handle elements. + // + for (ElementInfoMap::iterator i (t.el_map.begin ()); + i != t.el_map.end (); ++i) + { + String const& name (i->first); + ElementInfo& ei (i->second); + size_t min (ei.min * smin); + size_t max (ei.max * smax); + ElementInfoMap::iterator j (el_map.find (name)); + + if (j != el_map.end ()) + { + // Add i's cardinality to j + // + j->second.min += min; + j->second.max = (j->second.max == 0 || max == 0) ? + 0 : (j->second.max + max); + } + else + el_map[name] = ElementInfo (ei.element (), min, max); + } + + // Handle wildcards. + // + for (AnyInfoMap::iterator i (t.any_map.begin ()); + i != t.any_map.end (); ++i) + { + String const& name (i->first); + AnyInfo& ai (i->second); + size_t min (ai.min * smin); + size_t max (ai.max * smax); + + assert (any_map.find (name) == any_map.end ()); + + any_map[name] = AnyInfo (ai.any (), min, max); + } + } + } + + virtual void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::ContainsParticle& cp (e.contained_particle ()); + + String name (e.qualified_p () + ? e.namespace_ ().name () + L" " + e.name () + : e.name ()); + + el_map[name] = ElementInfo (e, cp.min (), cp.max ()); + } + + virtual void + traverse (SemanticGraph::Any& a) + { + SemanticGraph::ContainsParticle& cp (a.contained_particle ()); + + any_map[a.name ()] = AnyInfo (a, cp.min (), cp.max ()); + } + + public: + AnyInfoMap any_map; + ElementInfoMap el_map; + }; + + + // + // + struct Complex: Traversal::Complex + { + virtual void + traverse (Type& c) + { + if (c.contains_compositor_p ()) + { + Particle t; + t.dispatch (c.contains_compositor ().compositor ()); + + for (ElementInfoMap::iterator i (t.el_map.begin ()); + i != t.el_map.end (); ++i) + { + ElementInfo& ei (i->second); + SemanticGraph::Context& ctx (ei.element ().context ()); + + ctx.set ("min", ei.min); + ctx.set ("max", ei.max); + } + + for (AnyInfoMap::iterator i (t.any_map.begin ()); + i != t.any_map.end (); ++i) + { + AnyInfo& ai (i->second); + SemanticGraph::Context& ctx (ai.any ().context ()); + + ctx.set ("min", ai.min); + ctx.set ("max", ai.max); + } + } + + // Traverse attributes and anonymous types (via elements). + // + Complex::names (c); + } + }; + + + // + // + struct Attribute: Traversal::Attribute + { + virtual void + traverse (Type& a) + { + SemanticGraph::Context& ctx (a.context ()); + + ctx.set ("min", size_t (a.optional_p () ? 0 : 1)); + ctx.set ("max", size_t (1)); + } + }; + + // 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 ("processing-cardinality-seen")) + { + s.context ().set ("processing-cardinality-seen", true); + Traversal::Uses::traverse (u); + } + } + }; + } + + void Processor:: + process (SemanticGraph::Schema& tu, 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; + AnonymousBase anonymous (complex_type); + + ns_names >> complex_type; + ns_names >> anonymous; + + Attribute attribute; + Traversal::Names names; + + complex_type >> names; + + names >> attribute; + names >> anonymous; + + // Some twisted schemas do recusive inclusions. + // + tu.context ().set ("processing-cardinality-seen", true); + + schema.dispatch (tu); + } + } +} diff --git a/xsd/xsd/processing/cardinality/processor.hxx b/xsd/xsd/processing/cardinality/processor.hxx new file mode 100644 index 0000000..93a85fb --- /dev/null +++ b/xsd/xsd/processing/cardinality/processor.hxx @@ -0,0 +1,28 @@ +// file : xsd/processing/cardinality/processor.hxx +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX +#define XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX + +#include // Path +#include + +#include + +namespace Processing +{ + namespace Cardinality + { + class Processor + { + public: + struct Failed {}; + + void + process (XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX diff --git a/xsd/xsd/processing/inheritance/processor.cxx b/xsd/xsd/processing/inheritance/processor.cxx new file mode 100644 index 0000000..6c0e40e --- /dev/null +++ b/xsd/xsd/processing/inheritance/processor.cxx @@ -0,0 +1,492 @@ +// file : xsd/processing/inheritance/processor.cxx +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include + +#include + +#include +#include + +using namespace std; + +namespace Processing +{ + namespace SemanticGraph = XSDFrontend::SemanticGraph; + namespace Traversal = XSDFrontend::Traversal; + + namespace Inheritance + { + namespace + { + struct Dep + { + Dep (SemanticGraph::Type& t, + SemanticGraph::Member* m = 0, + String const& xpath = L"") + : type (t), member (m), member_xpath (xpath) + { + } + + SemanticGraph::Type& type; + SemanticGraph::Member* member; // Member if type is anonymous. + String member_xpath; + }; + + inline bool + operator< (Dep const& a, Dep const& b) + { + return &a.type < &b.type; + } + + typedef set DepSet; + typedef set TypeSet; + + String + xpath (SemanticGraph::Nameable& n) + { + if (dynamic_cast (&n) != 0) + return L""; // There is a bug if you see this. + + if (n.named_p ()) + { + SemanticGraph::Scope& scope (n.scope ()); + + if (dynamic_cast (&scope) != 0) + return n.name (); + + return xpath (scope) + L"/" + n.name (); + } + else + { + return L"(anonymous type for " + + n.context ().get ("instance-name") + L")"; + } + } + + + // Calculate the list of dependencies for this complex + // type. + // + struct ComplexType: Traversal::Complex, + Traversal::Member + { + ComplexType (DepSet& dep_set) + : dep_set_ (dep_set), last_ (0) + { + *this >> names_ >> *this; + } + + virtual void + traverse (SemanticGraph::Complex& c) + { + using SemanticGraph::Complex; + + if (c.inherits_p ()) + dep_set_.insert (Dep (c.inherits ().base (), last_, last_xpath_)); + + types_seen_.insert (&c); + + // Go after anonymous types. + // + names (c); + } + + virtual void + traverse (SemanticGraph::Member& m) + { + SemanticGraph::Type& t (m.type ()); + + if (!t.named_p () && types_seen_.find (&t) == types_seen_.end ()) + { + SemanticGraph::Context& ctx (t.context ()); + + last_xpath_ = xpath (m); + + String prev_xpath; + + if (ctx.count ("instance-name")) + prev_xpath = ctx.get ("instance-name"); + + ctx.set ("instance-name", last_xpath_); + + last_ = &m; + dispatch (t); + + if (prev_xpath) + ctx.set ("instance-name", prev_xpath); + else + ctx.remove ("instance-name"); + } + } + + private: + DepSet& dep_set_; + TypeSet types_seen_; + + SemanticGraph::Member* last_; + String last_xpath_; + + Traversal::Names names_; + }; + + + // + // + template + struct NodeArgs + { + NodeArgs (N& node, A arg) + : node_ (node), arg_ (arg) + { + } + + operator N& () const + { + return node_; + } + + template + void + add_edge_left (E& e) + { + node_.add_edge_left (e, arg_); + } + + template + void + add_edge_right (E& e) + { + node_.add_edge_right (e, arg_); + } + + private: + N& node_; + A arg_; + }; + + + // + // + struct Global: Traversal::Type, + Traversal::Complex, + Traversal::Element + { + Global (SemanticGraph::Schema& root, + SemanticGraph::Schema& schema, + bool& failed) + : root_ (root), schema_ (schema), failed_ (failed) + { + } + + virtual void + traverse (SemanticGraph::Type& t) + { + if (t.named_p ()) + types_seen_.insert (&t); + } + + virtual void + traverse (SemanticGraph::Complex& c) + { + check_dep (c, c); + types_seen_.insert (&c); + }; + + virtual void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + if (!t.named_p ()) + { + t.context ().set ("instance-name", xpath (e)); + check_dep (e, t); + t.context ().remove ("instance-name"); + } + }; + + private: + void + check_dep (SemanticGraph::Nameable& global, + SemanticGraph::Type& type) + { + using SemanticGraph::Type; + using SemanticGraph::Scope; + using SemanticGraph::Names; + using SemanticGraph::Schema; + + DepSet prereqs; + + // Calculate our prerequisistes. + // + { + ComplexType complex (prereqs); + complex.dispatch (type); + } + + for (DepSet::const_iterator i (prereqs.begin ()); + i != prereqs.end (); ++i) + { + Dep const& dep (*i); + Type& t (dep.type); + + // Ignore IDREF templates. + // + if (!t.named_p () && + (t.is_a () || + t.is_a ())) + continue; + + // We won't be able to generate compilable code in case of a + // dependency on ourselves (e.g., a member element with + // anonymous type that inherits from us). + // + if (&t == &type) + { + assert (dep.member != 0); + + SemanticGraph::Member& m (*dep.member); + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << " error: nested anonymous type for '" + << dep.member_xpath << "' cyclicly inherits from '" + << t.name () << "'" << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << " error: unable to generate valid code for such " + << "cyclic inheritance" << endl; + + wcerr << m.file () << ":" << m.line () << ":" << m.column () + << " info: '" << m.name () << "' element is declared here" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: consider explicitly naming this type " + << "or remove the --preserve-anonymous option" + << endl; + + failed_ = true; + continue; + } + + if (types_seen_.find (&t) == types_seen_.end ()) + { + Scope& scope (t.scope ()); + Schema& schema (dynamic_cast (scope.scope ())); + + // Don't worry about types that are in included/imported + // schemas. + // + if (&schema != &schema_ && !sources_p (schema_, schema)) + continue; + + if (t.context ().count ("seen")) + { + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << " error: nested anonymous type in '" << t.name () + << "' or '" << type.name () << "' inherits from one of " + << "these types and makes them mutually dependant" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << " error: unable to generate valid code for such " + << "cyclic dependency" << endl; + + wcerr << type.file () << ":" << type.line () << ":" + << type.column () << " info: '" << type.name () + << "' type is defined here" + << endl; + + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": info: consider explicitly naming the anonymous " + << "type or remove the --preserve-anonymous option" + << endl; + + failed_ = true; + continue; + } + + //wcerr << "type '" << t.name () << "' needs to be moved " << + // "before " << (global.is_a () ? "type" : "element") << + // " '" << global.name () << "'" << endl; + + + // Delete current Names edge. + // + String name (t.name ()); + { + Names& n (t.named ()); + root_.delete_edge (scope, t, n); + } + + // Insert a new Names edge before global. + // + { + // t.scope () and global.scope () can be different in + // case of the chameleon inclusion. + // + Scope& scope (global.scope ()); + + // Convert to the insert-after call. + // + Scope::NamesIterator i (scope.find (global.named ())); + + if (i == scope.names_begin ()) + i = scope.names_end (); + else + --i; + + NodeArgs na (scope, i); + root_.new_edge (na, t, name); + } + + // Recursively process the moved type. + // + global.context ().set ("seen", true); + dispatch (t); + global.context ().remove ("seen"); + } + } + } + + private: + // Return true if root sources s. + // + bool + sources_p (SemanticGraph::Schema& root, SemanticGraph::Schema& s) + { + using SemanticGraph::Schema; + using SemanticGraph::Sources; + + for (Schema::UsesIterator i (root.uses_begin ()); + i != root.uses_end (); ++i) + { + if (i->is_a ()) + { + if (&i->schema () == &s || sources_p (i->schema (), s)) + return true; + } + } + + return false; + } + + private: + SemanticGraph::Schema& root_; + SemanticGraph::Schema& schema_; + TypeSet types_seen_; + bool& failed_; + }; + + + // Sources traverser that goes into each schema only once. + // + struct Sources: Traversal::Sources + { + virtual void + traverse (SemanticGraph::Sources& s) + { + if (schemas_.insert (&s.schema ()).second) + Traversal::Sources::traverse (s); + } + + private: + set schemas_; + }; + + // Go into included/imported schemas while making sure we don't + // process the same stuff more than once. + // + struct Uses: Traversal::Includes, Traversal::Imports + { + Uses (SemanticGraph::Schema& root, bool& failed) + : root_ (root), failed_ (failed) + { + } + + virtual void + traverse (SemanticGraph::Includes& i) + { + traverse (i.schema ()); + } + + virtual void + traverse (SemanticGraph::Imports& i) + { + traverse (i.schema ()); + } + + private: + void + traverse (SemanticGraph::Schema& s) + { + if (!s.context ().count ("processing-inheritance-seen")) + { + Traversal::Schema schema; + Sources sources; + + schema >> sources >> schema; + schema >> *this; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + Global global (root_, s, failed_); + + ns_names >> global; + + s.context ().set ("processing-inheritance-seen", true); + schema.dispatch (s); + } + } + + private: + SemanticGraph::Schema& root_; + bool& failed_; + }; + } + + void Processor:: + process (SemanticGraph::Schema& tu, SemanticGraph::Path const&) + { + bool failed (false); + + // We need to process include/imported schemas since other + // parts of the process, for example, name processors can + // rely on the order of types in the schema. + // + Traversal::Schema schema; + Sources sources; + Uses uses (tu, failed); + + schema >> sources >> schema; + schema >> uses; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + + schema >> schema_names >> ns >> ns_names; + + Global global (tu, tu, failed); + + ns_names >> global; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("processing-inheritance-seen", true); + + schema.dispatch (tu); + + if (failed) + throw Failed (); + } + } +} diff --git a/xsd/xsd/processing/inheritance/processor.hxx b/xsd/xsd/processing/inheritance/processor.hxx new file mode 100644 index 0000000..2a70e02 --- /dev/null +++ b/xsd/xsd/processing/inheritance/processor.hxx @@ -0,0 +1,28 @@ +// file : xsd/processing/inheritance/processor.hxx +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_PROCESSING_INHERITANCE_PROCESSOR_HXX +#define XSD_PROCESSING_INHERITANCE_PROCESSOR_HXX + +#include // Path +#include + +#include + +namespace Processing +{ + namespace Inheritance + { + class Processor + { + public: + struct Failed {}; + + void + process (XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const& file); + }; + } +} + +#endif // XSD_PROCESSING_INHERITANCE_PROCESSOR_HXX -- cgit v1.1