summaryrefslogtreecommitdiff
path: root/xsd/xsd/processing/cardinality
diff options
context:
space:
mode:
Diffstat (limited to 'xsd/xsd/processing/cardinality')
-rw-r--r--xsd/xsd/processing/cardinality/processor.cxx407
-rw-r--r--xsd/xsd/processing/cardinality/processor.hxx28
2 files changed, 435 insertions, 0 deletions
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 <map>
+
+#include <libxsd-frontend/semantic-graph.hxx>
+#include <libxsd-frontend/traversal.hxx>
+
+#include <xsd/elements.hxx>
+
+#include <xsd/processing/cardinality/processor.hxx>
+
+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<String, ElementInfo> 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<String, AnyInfo> 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 <libxsd-frontend/semantic-graph/elements.hxx> // Path
+#include <libxsd-frontend/semantic-graph/schema.hxx>
+
+#include <xsd/types.hxx>
+
+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