aboutsummaryrefslogtreecommitdiff
path: root/xsde/cxx/parser/element-validation-source.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xsde/cxx/parser/element-validation-source.cxx')
-rw-r--r--xsde/cxx/parser/element-validation-source.cxx2120
1 files changed, 2120 insertions, 0 deletions
diff --git a/xsde/cxx/parser/element-validation-source.cxx b/xsde/cxx/parser/element-validation-source.cxx
new file mode 100644
index 0000000..e5d3589
--- /dev/null
+++ b/xsde/cxx/parser/element-validation-source.cxx
@@ -0,0 +1,2120 @@
+// file : xsde/cxx/parser/element-validation-source.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <cxx/parser/element-validation-source.hxx>
+
+#include <xsd-frontend/semantic-graph.hxx>
+#include <xsd-frontend/traversal.hxx>
+
+#include <cult/containers/vector.hxx>
+
+namespace CXX
+{
+ namespace Parser
+ {
+ namespace
+ {
+ typedef Cult::Containers::Vector<SemanticGraph::Particle*> Particles;
+
+ // Find particle that can be absent.
+ //
+ struct OptionalParticleTest: Traversal::Choice
+ {
+ OptionalParticleTest (SemanticGraph::Particle*& result)
+ : is_optional_ (optional_), result_ (result)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Choice& c)
+ {
+ using SemanticGraph::Choice;
+ result_ = 0;
+ optional_ = false;
+
+ for (Choice::ContainsIterator i (c.contains_begin ());
+ result_ == 0 && i != c.contains_end ();
+ ++i)
+ {
+ is_optional_.dispatch (i->particle ());
+ if (optional_)
+ result_ = &i->particle ();
+ }
+ }
+
+ struct IsOptional: Traversal::Choice,
+ Traversal::Sequence,
+ Traversal::Element,
+ Traversal::Any
+ {
+ IsOptional (Boolean& r)
+ : r_ (r)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Choice& c)
+ {
+ if (!r_ && c.min () == 0)
+ r_ = true;
+
+ // We need at least one particle to be optional for the whole
+ // choice to be optional.
+ //
+ using SemanticGraph::Choice;
+
+ for (Choice::ContainsIterator i (c.contains_begin ());
+ !r_ && i != c.contains_end ();
+ ++i)
+ {
+ dispatch (i->particle ());
+ }
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Sequence& s)
+ {
+ if (!r_ && s.min () == 0)
+ r_ = true;
+
+ // We need all particles to be optional for the whole sequence
+ // to be optional.
+ //
+ using SemanticGraph::Sequence;
+
+ for (Sequence::ContainsIterator i (s.contains_begin ());
+ !r_ && i != s.contains_end ();
+ ++i)
+ {
+ Boolean r (false);
+ IsOptional test (r);
+ test.dispatch (i->particle ());
+ if (!r)
+ return;
+ }
+
+ r_ = true;
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Element& e)
+ {
+ if (!r_ && e.min () == 0)
+ r_ = true;
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Any& a)
+ {
+ if (!r_ && a.min () == 0)
+ r_ = true;
+ }
+
+ private:
+ Boolean& r_;
+ };
+
+ private:
+ Boolean optional_;
+ IsOptional is_optional_;
+ SemanticGraph::Particle*& result_;
+ };
+
+ //
+ //
+ Void
+ choice_arm_call (SemanticGraph::Particle* p,
+ SemanticGraph::Choice* c,
+ Context* ctx)
+ {
+ using SemanticGraph::Choice;
+
+ ctx->os << "this->" << Context::earm (*c) << " (" <<
+ Context::etag (*p) << ");";
+
+ if ((c = dynamic_cast<Choice*> (p)))
+ {
+ OptionalParticleTest test (p);
+ test.traverse (*c);
+
+ if (p)
+ choice_arm_call (p, c, ctx);
+ }
+ }
+
+ //
+ //
+ struct ParticleTest: Traversal::Compositor,
+ Traversal::Element,
+ Traversal::Any,
+ Context
+ {
+ ParticleTest (Context& c)
+ : Context (c)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Element& e)
+ {
+ String const& name (e.name ());
+ Boolean subst (poly_code && e.global ());
+
+ if (subst)
+ os << "(";
+
+ if (e.qualified () && e.namespace_ ().name ())
+ {
+ String const& ns (e.namespace_ ().name ());
+
+ os << "n == " << L << strlit (name) << " &&" << endl
+ << "ns == " << L << strlit (ns);
+ }
+ else
+ os << "n == " << L << strlit (name) << " && ns.empty ()";
+
+
+ // Only a globally-defined element can be a subst-group root.
+ //
+ if (subst)
+ {
+ String root_id (e.name ());
+
+ if (String const& ns = e.namespace_ ().name ())
+ {
+ root_id += L' ';
+ root_id += ns;
+ }
+
+ os << ") ||" << endl
+ << "::xsde::cxx::parser::substitution_map_instance ()" <<
+ ".check (" << endl
+ << "ns, n, " << strlit (root_id) << ", t)";
+ }
+
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Any& a)
+ {
+ String const& ns (a.definition_namespace ().name ());
+
+ // Note that we need to make sure the "flush" element (both name
+ // and namespace are empty) does not match any compositor.
+ //
+ for (SemanticGraph::Any::NamespaceIterator i (a.namespace_begin ()),
+ e (a.namespace_end ()); i != e;)
+ {
+ if (*i == L"##any")
+ {
+ os << "!n.empty ()";
+ }
+ else if (*i == L"##other")
+ {
+ if (ns)
+ {
+ // Note that here I assume that ##other does not include
+ // unqualified names in a schema with target namespace.
+ // This is not what the spec says but that seems to be
+ // the consensus.
+ //
+ os << "(!ns.empty () && ns != " << L << strlit (ns) << ")";
+ }
+ else
+ os << "!ns.empty ()";
+ }
+ else if (*i == L"##local")
+ {
+ os << "(ns.empty () && !n.empty ())";
+ }
+ else if (*i == L"##targetNamespace")
+ {
+ os << "ns == " << L << strlit (ns);
+ }
+ else
+ {
+ os << "ns == " << L << strlit (*i);
+ }
+
+ if (++i != e)
+ os << " ||" << endl;
+ }
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c)
+ {
+ // This compositor should already have been tested for
+ // triviality (empty).
+ //
+ Particles const& p (c.context ().get<Particles> ("p:prefixes"));
+
+ Boolean paren (p.size () != 1);
+
+ for (Particles::ConstIterator i (p.begin ()), e (p.end ());
+ i != e;)
+ {
+ if (paren)
+ os << "(";
+
+ dispatch (**i);
+
+ if (paren)
+ os << ")";
+
+ if (++i != e)
+ os << " ||" << endl;
+ }
+ }
+ };
+
+
+ // Generates particle namespace-name pair. Used to generate
+ // the _expected_element call.
+ //
+ struct ParticleName: Traversal::Compositor,
+ Traversal::Element,
+ Traversal::Any,
+ Context
+ {
+ ParticleName (Context& c)
+ : Context (c)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Element& e)
+ {
+ String ns (e.qualified () ? e.namespace_ ().name () : String ());
+
+ os << L << strlit (ns) << ", " << L << strlit (e.name ());
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Any& a)
+ {
+ String const& ns (*a.namespace_begin ());
+
+ os << L << strlit (ns) << ", " << L << "\"*\"";
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c)
+ {
+ Particles const& p (c.context ().get<Particles> ("p:prefixes"));
+
+ dispatch (**p.begin ());
+ }
+ };
+
+
+ // Common base for the ParticleIn{All, Choice, Sequence} treversers.
+ //
+ struct ParticleInCompositor: protected Context
+ {
+ protected:
+ ParticleInCompositor (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type), particle_test_ (c)
+ {
+ }
+
+
+ // Generate sub-parser setup code as well as the pre/post calls.
+ //
+ Void
+ pre_post_calls (SemanticGraph::Particle& p)
+ {
+ using SemanticGraph::Element;
+ using SemanticGraph::Complex;
+
+ if (Element* e = dynamic_cast<Element*> (&p))
+ {
+ SemanticGraph::Type& type (e->type ());
+ Boolean poly (poly_code && !anonymous (type));
+
+ String const& name (ename (*e));
+ String inst (poly ? emember_cache (*e) : emember (*e));
+
+ String def_parser, map;
+
+ if (poly)
+ {
+ def_parser = emember (*e);
+ map = emember_map (*e);
+ }
+
+ if (poly)
+ {
+ String cast (mixin ? L"dynamic_cast" : L"static_cast");
+ String fq_type (fq_name (type));
+
+ os << "if (t == 0 && this->" << def_parser << " != 0)" << endl
+ << "this->" << inst << " = this->" << def_parser << ";"
+ << "else"
+ << "{"
+ << "const char* ts = " << fq_type << "::_static_type ();"
+ << endl
+ << "if (t == 0)" << endl
+ << "t = ts;"
+ << endl
+ << "if (this->" << def_parser << " != 0 && " <<
+ "strcmp (t, ts) == 0)" << endl
+ << "this->" << inst << " = this->" << def_parser << ";"
+ << "else"
+ << "{";
+
+ // Check that the types are related by inheritance.
+ //
+ os << "if (t != ts &&" << endl
+ << "!::xsde::cxx::parser::validating::" <<
+ "inheritance_map_instance ().check (t, ts))"
+ << "{"
+ << "ctx.schema_error (::xsde::cxx::schema_error::not_derived);"
+ << "return;"
+ << "}";
+
+ os << "if (this->" << map << " != 0)" << endl
+ << "this->" << inst << " = " << cast << "< " <<
+ fq_type << "* > (" << endl
+ << "this->" << map << "->find (t));"
+ << "else" << endl
+ << "this->" << inst << " = 0;"
+ << "}"
+ << "}";
+ }
+
+ String const& post (post_name (type));
+
+ os << "if (this->" << inst << ")"
+ << "{"
+ << "this->" << inst << "->pre ();";
+
+ if (!exceptions)
+ {
+ // Note that after pre() we need to check both parser and
+ // context error states because of the recursive parsing.
+ //
+ os << endl
+ << "if (this->" << inst << "->_error_type ())" << endl
+ << "this->" << inst << "->_copy_error (ctx);"
+ << endl
+ << "if (!ctx.error_type ())" << endl;
+ }
+
+ os << "this->" << inst << "->_pre_impl (ctx);"
+ << "}"
+ << "else" << endl
+ << "ctx.current_.depth_++;" // Ignoring document fragment.
+ << endl
+ << "}"
+ << "else" // start
+ << "{"
+ << "if (this->" << inst << ")"
+ << "{";
+
+ String const& ret (ret_type (type));
+
+ if (ret == L"void")
+ os << "this->" << inst << "->" << post << " ();";
+ else
+ os << arg_type (type) << " tmp = this->" << inst << "->" <<
+ post << " ();";
+
+ if (!exceptions)
+ {
+ // Note that after post() we need to check both parser and
+ // context error states because of the recursive parsing.
+ //
+ os << endl
+ << "if (this->" << inst << "->_error_type ())" << endl
+ << "this->" << inst << "->_copy_error (ctx);"
+ << endl
+ << "if (!ctx.error_type ())" << endl;
+ }
+
+ if (ret == L"void")
+ os << "this->" << name << " ();";
+ else
+ os << "this->" << name << " (tmp);";
+
+ os << "}";
+ }
+ else
+ {
+ os << "ctx.current_.any_ = true;"
+ << "ctx.current_.depth_++;"
+ << endl
+ << "this->_start_any_element (ns, n" <<
+ (poly_runtime ? (poly_code ? ", t" : ", 0") : "") << ");"
+ << "}"
+ << "else" // start
+ << "{"
+ << "this->_end_any_element (ns, n);";
+ }
+ }
+
+
+ protected:
+ SemanticGraph::Complex& type_;
+ ParticleTest particle_test_;
+ };
+
+
+
+ // The 'all' compositor can only contain elements with min={0,1}, max=1.
+ //
+ struct ParticleInAll: Traversal::Element,
+ ParticleInCompositor
+ {
+ ParticleInAll (Context& c, SemanticGraph::Complex& type)
+ : ParticleInCompositor (c, type)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Element& e)
+ {
+ UnsignedLong state (e.context ().get<UnsignedLong> ("p:state"));
+
+ SemanticGraph::Compositor& c (
+ e.contained_particle ().compositor ());
+
+ if (state != 0)
+ os << "else ";
+
+ os << "if (";
+
+ particle_test_.traverse (e);
+
+ os << ")"
+ << "{"
+ << "if (count[" << state << "UL] == 0)"
+ << "{"
+ << "if (start)"
+ << "{";
+
+ if (c.min () == 0)
+ {
+ // Make the call to _present if we haven't seen any
+ // elements yet.
+ //
+ UnsignedLong state_count (
+ c.context().get<UnsignedLong> ("p:state-count"));
+
+ if (state_count > 1)
+ {
+ os << "if (";
+
+ Boolean sub (false);
+
+ for (UnsignedLong i (0); i < state_count; ++i)
+ {
+ if (i == state)
+ continue;
+
+ if (sub)
+ os << " &&" << endl;
+ else
+ sub = true;
+
+ os << "count[" << i << "UL] == 0";
+ }
+
+ os << ")" << endl
+ << "this->" << epresent (c) << " ();"
+ << endl;
+ }
+ }
+
+ pre_post_calls (e);
+
+ os << "count[" << state << "UL] = 1;"
+ << "}"
+ << "}"
+ << "else" // count != 0
+ << "{"
+ << "assert (start);" // Assuming well-formed XML.
+
+ // Since there is never more content after 'all', we could have
+ // as well thrown here. But instead we will let the code in
+ // start_element handle this along with other unexpected
+ // elements.
+ //
+ << "state = ~0UL;"
+ << "}"
+ << "}";
+ }
+ };
+
+
+ //
+ //
+ struct ParticleInChoice: Traversal::Particle,
+ Traversal::Compositor,
+ ParticleInCompositor
+ {
+ ParticleInChoice (Context& c, SemanticGraph::Complex& type)
+ : ParticleInCompositor (c, type), particle_name_ (c)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Particle& p)
+ {
+ using SemanticGraph::Element;
+
+ UnsignedLong state (p.context ().get<UnsignedLong> ("p:state"));
+
+ UnsignedLong min (p.min ()), max (p.max ());
+
+ os << "case " << state << "UL:" << endl
+ << "{";
+
+ if (max != 1) // We don't need the test if max == 1.
+ {
+ os << "if (";
+
+ particle_test_.dispatch (p);
+
+ os << ")"
+ << "{";
+ }
+
+ os << "if (start)"
+ << "{";
+
+ pre_post_calls (p);
+
+ switch (max)
+ {
+ case 0:
+ {
+ os << "count++;";
+ break;
+ }
+ case 1:
+ {
+ // We do not need to increment count because min <= max and
+ // we do not generate min check for min <= 1 (see below).
+ //
+ os << "state = ~0UL;";
+ break;
+ }
+ default:
+ {
+ os << "if (++count == " << max << "UL)" << endl
+ << "state = ~0UL;";
+ }
+ };
+
+ os << "}"; // start
+
+ // We've already moved to the final state if max == 1.
+ //
+ if (max != 1)
+ {
+ os << "}"
+ << "else"
+ << "{"
+ << "assert (start);"; // Assuming well-formed XML
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 1, don't generate dead code if min <= 1.
+ //
+ if (min > 1)
+ {
+ os << "if (count < " << min << "UL)" << endl
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);";
+
+ /*
+ << "this->_expected_element (" << endl;
+ particle_name_.dispatch (p);
+ os << "," << endl
+ << "ns, n);";
+ */
+ }
+
+
+ os << "state = ~0UL;"
+ << "}";
+ }
+
+ os << "break;"
+ << "}"; // case
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c)
+ {
+ using SemanticGraph::Choice;
+ using SemanticGraph::Sequence;
+ using SemanticGraph::Compositor;
+
+ Boolean choice (c.is_a<Choice> ());
+ SemanticGraph::Context& cc (c.context ());
+
+ UnsignedLong max (c.max ());
+ UnsignedLong min (cc.get<UnsignedLong> ("p:effective-min"));
+ UnsignedLong n (cc.get<UnsignedLong> ("p:comp-number"));
+ UnsignedLong state (cc.get<UnsignedLong> ("p:state"));
+
+ String func (choice ? "choice_" : "sequence_");
+
+ os << "case " << state << "UL:" << endl
+ << "{"
+ << "unsigned long s = ~0UL;"
+ << endl;
+
+ Boolean first (true);
+
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ SemanticGraph::Particle& p (ci->particle ());
+
+ if (p.is_a<Compositor> () && !cc.count ("p:comp-number"))
+ continue; // Empty compositor.
+
+ if (!p.context ().count ("p:prefix"))
+ break;
+
+ UnsignedLong state (p.context ().get<UnsignedLong> ("p:state"));
+
+ if (first)
+ first = false;
+ else
+ os << "else ";
+
+ os << "if (";
+
+ particle_test_.dispatch (p);
+
+ os << ")" << endl
+ << "s = " << state << "UL;";
+ }
+
+ if (!choice)
+ {
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ Choice* pc = dynamic_cast<Choice*> (&ci->particle ());
+
+ if (pc && pc->min () == 1 && pc->max () == 1 &&
+ pc->context ().get<UnsignedLong> ("p:effective-min") == 0)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ {
+ UnsignedLong state (
+ pc->context ().get<UnsignedLong> ("p:state"));
+
+ os << endl
+ << "if (s > " << state << "UL)" << endl
+ << "{";
+ choice_arm_call (p, pc, this);
+ os << "}";
+ }
+ }
+ }
+ }
+
+ // This compositor.
+ //
+ os << endl
+ << "if (s != ~0UL)"
+ << "{"
+ << "assert (start);"; // End is handled by the sub-machine.
+
+ switch (max)
+ {
+ case 0:
+ {
+ os << "count++;";
+ break;
+ }
+ case 1:
+ {
+ // We do not need to increment count because min <= max and
+ // we do not generate min check for min <= 1 (see below).
+ //
+ os << "state = ~0UL;";
+ break;
+ }
+ default:
+ {
+ os << "if (++count == " << max << "UL)" << endl
+ << "state = ~0UL;";
+ }
+ };
+
+ // Delegate to the sub-machine and call _arm, _present, or _next
+ // if necessary.
+ //
+
+ os << endl
+ << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_& vd = vs.data[vs.size++];" // push
+ << endl
+ << "vd.func = &" << ename (type_) << "::" << func << n << ";"
+ << "vd.state = s;"
+ << "vd.count = 0;"
+ << endl;
+
+ if (Choice* pc = dynamic_cast<Choice*> (&c))
+ {
+ os << "this->" << earm (*pc) << " (static_cast< " <<
+ earm_tag (*pc) << " > (s));";
+ }
+ else
+ {
+ Sequence& s (dynamic_cast<Sequence&> (c));
+
+ if (max != 1)
+ os << "this->" << enext (s) << " ();";
+ else if (c.min () == 0)
+ os << "this->" << epresent (s) << " ();";
+ }
+
+ os << "this->" << func << n << " (vd.state, vd.count, ns, n, " <<
+ (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);"
+ << "}";
+
+
+ // Not this compositor. We've elready moved to the final state
+ // if max == 1.
+ //
+ if (max != 1)
+ {
+ os << "else"
+ << "{"
+ << "assert (start);"; // Assuming well-formed XML
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 1, don't generate dead code if min <= 1.
+ //
+ if (min > 1)
+ {
+ os << "if (count < " << min << "UL)" << endl
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);";
+
+ /*
+ << "this->_expected_element (" << endl;
+ particle_name_.dispatch (c);
+ os << "," << endl
+ << "ns, n);";
+ */
+ }
+
+ os << "state = ~0UL;"
+ << "}";
+ }
+
+ os << "break;"
+ << "}"; // case
+ }
+
+ private:
+ ParticleName particle_name_;
+ };
+
+
+ //
+ //
+ struct ParticleInSequence: Traversal::Particle,
+ Traversal::Compositor,
+ ParticleInCompositor
+ {
+ ParticleInSequence (Context& c,
+ UnsignedLong state,
+ UnsignedLong next_state,
+ SemanticGraph::Complex& type)
+ : ParticleInCompositor (c, type),
+ state_ (state), particle_name_ (c)
+ {
+ // next_state == 0 indicates the terminal state (~0UL).
+ //
+ if (next_state != 0)
+ {
+ std::wostringstream ostr;
+ ostr << next_state;
+ next_state_ = ostr.str ();
+ }
+ else
+ next_state_ = L"~0";
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Particle& p)
+ {
+ UnsignedLong min (p.min ()), max (p.max ());
+
+ os << "case " << state_ << "UL:" << endl
+ << "{"
+ << "if (";
+
+ particle_test_.dispatch (p);
+
+ os << ")"
+ << "{";
+
+ // This element.
+ //
+
+ os << "if (start)"
+ << "{";
+
+ pre_post_calls (p);
+
+ switch (max)
+ {
+ case 0:
+ {
+ os << "count++;";
+ break;
+ }
+ case 1:
+ {
+ os << "count = 0;"
+ << "state = " << next_state_ << "UL;";
+ break;
+ }
+ default:
+ {
+ os << "if (++count == " << max << "UL)"
+ << "{"
+ << "count = 0;"
+ << "state = " << next_state_ << "UL;"
+ << "}";
+ }
+ };
+
+ os << "}" // start
+ << "break;"
+ << "}";
+
+ // Not this element.
+ //
+
+ os << "else"
+ << "{"
+ << "assert (start);"; // Assuming well-formed XML.
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 0, don't generate dead code if min == 0.
+ //
+ if (min != 0)
+ {
+ os << "if (count < " << min << "UL)"
+ << "{"
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);"
+ << "break;"
+ << "}";
+
+ /*
+ << "this->_expected_element (" << endl;
+ particle_name_.dispatch (p);
+ os << "," << endl
+ << "ns, n);";
+ */
+ }
+
+ os << "count = 0;"
+ << "state = " << next_state_ << "UL;"
+ << "// Fall through." << endl
+ << "}" // else
+ << "}"; // case
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c)
+ {
+ using SemanticGraph::Choice;
+ using SemanticGraph::Sequence;
+ using SemanticGraph::Compositor;
+
+ Boolean choice (c.is_a<Choice> ());
+ SemanticGraph::Context& cc (c.context ());
+
+ UnsignedLong max (c.max ());
+ UnsignedLong min (cc.get<UnsignedLong> ("p:effective-min"));
+ UnsignedLong n (cc.get<UnsignedLong> ("p:comp-number"));
+
+ String func (choice ? "choice_" : "sequence_");
+
+ os << "case " << state_ << "UL:" << endl
+ << "{"
+ << "unsigned long s = ~0UL;"
+ << endl;
+
+ Boolean first (true);
+
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ SemanticGraph::Particle& p (ci->particle ());
+
+ if (p.is_a<Compositor> () && !cc.count ("p:comp-number"))
+ continue; // Empty compositor.
+
+ if (!p.context ().count ("p:prefix"))
+ break;
+
+ UnsignedLong state (p.context ().get<UnsignedLong> ("p:state"));
+
+ if (first)
+ first = false;
+ else
+ os << "else ";
+
+ os << "if (";
+
+ particle_test_.dispatch (p);
+
+ os << ")" << endl
+ << "s = " << state << "UL;";
+ }
+
+ if (!choice)
+ {
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ Choice* pc = dynamic_cast<Choice*> (&ci->particle ());
+
+ if (pc && pc->min () == 1 && pc->max () == 1 &&
+ pc->context ().get<UnsignedLong> ("p:effective-min") == 0)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ {
+ UnsignedLong state (
+ pc->context ().get<UnsignedLong> ("p:state"));
+
+ os << endl
+ << "if (s > " << state << "UL)" << endl
+ << "{";
+ choice_arm_call (p, pc, this);
+ os << "}";
+ }
+ }
+ }
+ }
+
+ // This element.
+ //
+
+ os << endl
+ << "if (s != ~0UL)"
+ << "{"
+ << "assert (start);"; // End is handled by the sub-machine.
+
+ switch (max)
+ {
+ case 0:
+ {
+ os << "count++;"
+ << endl;
+ break;
+ }
+ case 1:
+ {
+ os << "count = 0;"
+ << "state = " << next_state_ << "UL;"
+ << endl;
+ break;
+ }
+ default:
+ {
+ os << "if (++count == " << max << "UL)"
+ << "{"
+ << "count = 0;"
+ << "state = " << next_state_ << "UL;"
+ << "}";
+ }
+ };
+
+ // Delegate to the sub-machine and call _arm, _present, or _next
+ // if necessary.
+ //
+
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_& vd = vs.data[vs.size++];" // push
+ << endl
+ << "vd.func = &" << ename (type_) << "::" << func << n << ";"
+ << "vd.state = s;"
+ << "vd.count = 0;"
+ << endl;
+
+ Choice* pc = dynamic_cast<Choice*> (&c);
+
+ if (pc)
+ {
+ os << "this->" << earm (*pc) << " (static_cast< " <<
+ earm_tag (*pc) << " > (s));";
+ }
+ else
+ {
+ Sequence& s (dynamic_cast<Sequence&> (c));
+
+ if (max != 1)
+ os << "this->" << enext (s) << " ();";
+ else if (c.min () == 0)
+ os << "this->" << epresent (s) << " ();";
+ }
+
+ os << "this->" << func << n << " (vd.state, vd.count, ns, n, " <<
+ (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);"
+ << "break;"
+ << "}";
+
+ // Not this compositor.
+ //
+
+ os << "else"
+ << "{"
+ << "assert (start);"; // Assuming well-formed XML
+
+ if (pc && c.min () == 1 && min == 0 && max == 1)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ choice_arm_call (p, pc, this);
+ }
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 0, don't generate dead code if min == 0.
+ //
+ if (min != 0)
+ {
+ os << "if (count < " << min << "UL)"
+ << "{"
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);"
+ << "break;"
+ << "}";
+ }
+
+ os << "count = 0;"
+ << "state = " << next_state_ << "UL;"
+ << "// Fall through." << endl
+ << "}" // else
+ << "}"; // case
+ }
+
+ private:
+ UnsignedLong state_;
+ String next_state_;
+
+ ParticleName particle_name_;
+ };
+
+
+ //
+ //
+ struct ParticleFunction: Traversal::All,
+ Traversal::Choice,
+ Traversal::Sequence,
+ Context
+ {
+ ParticleFunction (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type)
+ {
+ *this >> contains_particle_ >> *this;
+ }
+
+
+ virtual Void
+ traverse (SemanticGraph::All& a)
+ {
+ if (!a.context().count ("p:comp-number")) // Empty compositor.
+ return;
+
+ using SemanticGraph::Element;
+ using SemanticGraph::Compositor;
+
+ os << "void " << ename (type_) << "::" << endl
+ << "all_0 (unsigned long& state," << endl
+ << "unsigned char* count," << endl
+ << "const " << string_type << "& ns," << endl
+ << "const " << string_type << "& n," << endl;
+
+ if (poly_runtime)
+ os << "const char*" << (poly_code ? " t" : "") << "," << endl;
+
+ os << "bool start)"
+ << "{";
+
+ if (poly_code)
+ os << "XSDE_UNUSED (t);"
+ << endl;
+
+ os << "::xsde::cxx::parser::context& ctx = this->_context ();"
+ << endl;
+
+ for (Compositor::ContainsIterator ci (a.contains_begin ()),
+ ce (a.contains_end ()); ci != ce; ++ci)
+ {
+ ParticleInAll t (*this, type_);
+ t.dispatch (ci->particle ());
+ }
+
+ // Handle the flush.
+ //
+ os << "else if (n.empty () && ns.empty ())"
+ << "{";
+
+ for (Compositor::ContainsIterator ci (a.contains_begin ()),
+ ce (a.contains_end ()); ci != ce; ++ci)
+ {
+ if (ci->min () == 0)
+ continue;
+
+ Element& e (dynamic_cast<Element&> (ci->particle ()));
+ String ns (e.qualified () ? e.namespace_ ().name () : String ());
+ UnsignedLong state (e.context ().get<UnsignedLong> ("p:state"));
+
+ os << "if (count[" << state << "UL] == 0)"
+ << "{"
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);"
+ << "return;"
+ << "}";
+
+ /*
+ << "this->_expected_element (" << endl
+ << L << "\"" << ns << "\", " <<
+ L << "\"" << e.name () << "\");";
+ */
+ }
+
+ // Error handling code relies on the fact that there is no
+ // code after the if-else block.
+ //
+ os << "state = ~0UL;"
+ << "}"
+ << "else" << endl
+ << "state = ~0UL;"
+ << "}";
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Choice& c)
+ {
+ using SemanticGraph::Compositor;
+
+ SemanticGraph::Context& cc (c.context ());
+
+ if (!cc.count ("p:comp-number")) // Empty compositor.
+ return;
+
+ UnsignedLong n (cc.get<UnsignedLong> ("p:comp-number"));
+
+ os << "void " << ename (type_) << "::" << endl
+ << "choice_" << n << " (unsigned long& state," << endl
+ << "unsigned long& count," << endl
+ << "const " << string_type << "& ns," << endl
+ << "const " << string_type << "& n," << endl;
+
+ if (poly_runtime)
+ os << "const char*" << (poly_code ? " t" : "") << "," << endl;
+
+ os << "bool start)"
+ << "{"
+ << "::xsde::cxx::parser::context& ctx = this->_context ();"
+ << endl;
+
+ os << "XSDE_UNUSED (count);"
+ << "XSDE_UNUSED (ns);"
+ << "XSDE_UNUSED (n);"
+ << "XSDE_UNUSED (ctx);";
+
+ if (poly_code)
+ os << "XSDE_UNUSED (t);";
+
+
+ os << endl
+ << "switch (state)"
+ << "{";
+
+ for (Compositor::ContainsIterator ci (c.contains_begin ()),
+ ce (c.contains_end ()); ci != ce; ++ci)
+ {
+ SemanticGraph::Particle& p (ci->particle ());
+
+ if (p.is_a<Compositor> () && !p.context().count ("p:comp-number"))
+ continue; // Empty compositor.
+
+ ParticleInChoice t (*this, type_);
+ t.dispatch (p);
+ }
+
+ // Error handling code relies on the fact that there is no
+ // code after the switch statement.
+ //
+ os << "}" // switch
+ << "}";
+
+
+ // Generate nested compositor functions.
+ //
+ Traversal::Choice::traverse (c);
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Sequence& s)
+ {
+ if (!s.context().count ("p:comp-number")) // Empty compositor.
+ return;
+
+ using SemanticGraph::Compositor;
+
+ UnsignedLong n (s.context ().get<UnsignedLong> ("p:comp-number"));
+
+ os << "void " << ename (type_) << "::" << endl
+ << "sequence_" << n << " (unsigned long& state," << endl
+ << "unsigned long& count," << endl
+ << "const " << string_type << "& ns," << endl
+ << "const " << string_type << "& n," << endl;
+
+ if (poly_runtime)
+ os << "const char*" << (poly_code ? " t" : "") << "," << endl;
+
+ os << "bool start)"
+ << "{"
+ << "::xsde::cxx::parser::context& ctx = this->_context ();"
+ << endl;
+
+ if (poly_code)
+ os << "XSDE_UNUSED (t);";
+
+ os << "XSDE_UNUSED (ctx);"
+ << endl;
+
+ os << "switch (state)"
+ << "{";
+
+ UnsignedLong state (0);
+
+ for (Compositor::ContainsIterator ci (s.contains_begin ()),
+ ce (s.contains_end ()); ci != ce;)
+ {
+ SemanticGraph::Particle& p (ci->particle ());
+
+ if (p.is_a<Compositor> () && !p.context().count ("p:comp-number"))
+ {
+ // Empty compositor.
+ //
+ ++ci;
+ continue;
+ }
+
+ // Find the next state.
+ //
+ do
+ ++ci;
+ while (ci != ce &&
+ ci->particle ().is_a<Compositor> () &&
+ !ci->particle ().context().count ("p:comp-number"));
+
+ UnsignedLong next (ci == ce ? 0 : state + 1);
+
+ ParticleInSequence t (*this, state++, next, type_);
+ t.dispatch (p);
+ }
+
+ // Error handling code relies on the fact that there is no
+ // code after the switch statement.
+ //
+ os << "case ~0UL:" << endl
+ << "break;"
+ << "}" // switch
+ << "}";
+
+ // Generate nested compositor functions.
+ //
+ Traversal::Sequence::traverse (s);
+ }
+
+ private:
+ SemanticGraph::Complex& type_;
+ Traversal::ContainsParticle contains_particle_;
+ };
+
+ //
+ //
+ struct CompositorPre: Traversal::All,
+ Traversal::Compositor,
+ Context
+ {
+ CompositorPre (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::All& a)
+ {
+ // Clear the counts and push the initial state.
+ //
+ os << "v_all_count_.push ();"
+ << endl;
+
+ SemanticGraph::Compositor& c (a);
+ traverse (c);
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor&) // Choice and sequence.
+ {
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_& vd = vs.data[vs.size++];" // push
+ << endl
+ << "vd.func = 0;"
+ << "vd.state = 0;"
+ << "vd.count = 0;";
+ }
+
+ private:
+ SemanticGraph::Complex& type_;
+ };
+
+
+ //
+ //
+ struct CompositorStartElement: Traversal::All,
+ Traversal::Compositor,
+ Context
+ {
+ CompositorStartElement (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type),
+ particle_test_ (c), particle_name_ (c)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::All&)
+ {
+ // The 'all' state machine reaches the final state only
+ // on an unknown element, in which case we won't get here
+ // again (it would be a validation error). Note that 'all'
+ // compositor cannot contain nested compositors so we don't
+ // need to re-set vd.
+ //
+ os << "all_0 (vd->state, v_all_count_.top (), ns, n, " <<
+ (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);"
+ << endl
+ << "if (vd->state != ~0UL || ctx.error_type ())" << endl
+ << "vd->count++;"
+ << "else" << endl
+ << "return false;" // Let our parent handle this.
+ << endl;
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c) // Choice and sequence.
+ {
+ using SemanticGraph::Choice;
+ using SemanticGraph::Sequence;
+ using SemanticGraph::Compositor;
+
+ Boolean choice (c.is_a<Choice> ());
+ SemanticGraph::Context& cc (c.context ());
+
+ UnsignedLong max (c.max ());
+ UnsignedLong min (cc.get<UnsignedLong> ("p:effective-min"));
+ UnsignedLong n (cc.get<UnsignedLong> ("p:comp-number"));
+
+ String func (choice ? "choice_" : "sequence_");
+
+ // Invoke the current state machine. If it reaches its
+ // terminal state, pop it and invoke the next one until
+ // we reach the top, which requires special handling.
+ //
+ os << "while (vd->func != 0)"
+ << "{"
+ << "(this->*vd->func) (vd->state, vd->count, ns, n, " <<
+ (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);"
+ << endl
+ << "vd = vs.data + (vs.size - 1);" // re-acquire
+ << endl
+ << "if (vd->state == ~0UL && !ctx.error_type ())" << endl
+ << "vd = vs.data + (--vs.size - 1);" // pop
+ << "else" << endl
+ << "break;"
+ << "}";
+
+
+ // Check if we got to the top. This code is pretty much the
+ // same as the one found in ParticleInSequence.
+ //
+ os << "if (vd->func == 0)"
+ << "{"
+ << "if (vd->state != ~0UL)"
+ << "{"
+ << "unsigned long s = ~0UL;"
+ << endl;
+
+ Boolean first (true);
+
+ // Note that we don't need to worry about the compositor
+ // being empty - this case is handled by our caller.
+ //
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ SemanticGraph::Particle& p (ci->particle ());
+
+ if (p.is_a<Compositor> () && !cc.count ("p:comp-number"))
+ continue; // Empty compositor.
+
+ if (!p.context ().count ("p:prefix"))
+ break;
+
+ UnsignedLong state (p.context ().get<UnsignedLong> ("p:state"));
+
+ if (first)
+ first = false;
+ else
+ os << "else ";
+
+ os << "if (";
+
+ particle_test_.dispatch (p);
+
+ os << ")" << endl
+ << "s = " << state << "UL;";
+ }
+
+ if (!choice)
+ {
+ for (Compositor::ContainsIterator ci (c.contains_begin ());
+ ci != c.contains_end (); ++ci)
+ {
+ Choice* pc = dynamic_cast<Choice*> (&ci->particle ());
+
+ if (pc && pc->min () == 1 && pc->max () == 1 &&
+ pc->context ().get<UnsignedLong> ("p:effective-min") == 0)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ {
+ UnsignedLong state (
+ pc->context ().get<UnsignedLong> ("p:state"));
+
+ os << endl
+ << "if (s > " << state << "UL)" << endl
+ << "{";
+ choice_arm_call (p, pc, this);
+ os << "}";
+ }
+ }
+ }
+ }
+
+ os << endl
+ << "if (s != ~0UL)"
+ << "{";
+
+ // This element is a prefix of the root compositor.
+ //
+
+ switch (max)
+ {
+ case 0:
+ {
+ os << "vd->count++;";
+ break;
+ }
+ case 1:
+ {
+ os << "vd->count++;"
+ << "vd->state = ~0UL;";
+ break;
+ }
+ default:
+ {
+ os << "if (++vd->count == " << max << "UL)" << endl
+ << "vd->state = ~0UL;";
+ }
+ };
+
+ // Delegate to the sub-machine and call _arm, _present, or _next
+ // if necessary.
+ //
+
+ os << endl
+ << "vd = vs.data + vs.size++;" // push
+ << "vd->func = &" << ename (type_) << "::" << func << n << ";"
+ << "vd->state = s;"
+ << "vd->count = 0;"
+ << endl;
+
+ Choice* pc (dynamic_cast<Choice*> (&c));
+
+ if (pc)
+ {
+ os << "this->" << earm (*pc) << " (static_cast< " <<
+ earm_tag (*pc) << " > (s));";
+ }
+ else
+ {
+ Sequence& s (dynamic_cast<Sequence&> (c));
+
+ if (max != 1)
+ os << "this->" << enext (s) << " ();";
+ else if (c.min () == 0)
+ os << "this->" << epresent (s) << " ();";
+ }
+
+ os << "this->" << func << n << " (vd->state, vd->count, ns, n, " <<
+ (poly_runtime ? (poly_code ? "t, " : "0, ") : "") << "true);"
+ << "}";
+
+ // This element is not our prefix.
+ //
+
+ os << "else"
+ << "{";
+
+ if (pc && c.min () == 1 && min == 0 && max == 1)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ choice_arm_call (p, pc, this);
+ }
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 0, don't generate dead code if min == 0.
+ //
+ if (min != 0)
+ {
+ // Note that we are returning true in case of an error to
+ // indicate that no further search is needed.
+ //
+ os << "if (vd->count < " << min << "UL)"
+ << "{"
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);"
+ << "return true;"
+ << "}";
+ }
+
+ // Return false to indicate that we are not handling this element.
+ //
+ os << "return false;"
+ << "}"
+ << "}" // if (state != ~0)
+ << "else" << endl
+ << "return false;"
+ << "}"; // if (function == 0)
+ }
+
+ private:
+ SemanticGraph::Complex& type_;
+ ParticleTest particle_test_;
+ ParticleName particle_name_;
+ };
+
+
+ //
+ //
+ struct CompositorEndElement: Traversal::All,
+ Traversal::Compositor,
+ Context
+ {
+ CompositorEndElement (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::All&)
+ {
+ os << "all_0 (vd.state, v_all_count_.top (), " <<
+ "ns, n, " << (poly_runtime ? "0, " : "") << "false);"
+ << endl;
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor&) // Choice and sequence.
+ {
+ os << "assert (vd.func != 0);"
+ << "(this->*vd.func) (vd.state, vd.count, ns, n, " <<
+ (poly_runtime ? "0, " : "") << "false);"
+ << endl
+ << "if (vd.state == ~0UL)" << endl
+ << "vs.size--;" // pop
+ << endl;
+ }
+
+ private:
+ SemanticGraph::Complex& type_;
+ };
+
+
+ //
+ //
+ struct CompositorPost: Traversal::All,
+ Traversal::Compositor,
+ Context
+ {
+ CompositorPost (Context& c, SemanticGraph::Complex& type)
+ : Context (c), type_ (type), particle_name_ (c)
+ {
+ }
+
+ virtual Void
+ traverse (SemanticGraph::All& a)
+ {
+ using SemanticGraph::Element;
+
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_& vd = vs.data[vs.size - 1];"
+ << endl;
+
+ // Flush the state machine with the empty element name. This
+ // allows us to detect missing content.
+ //
+ os << "if (vd.count != 0)"
+ << "{"
+ << string_type << " empty;"
+ << "all_0 (vd.state, v_all_count_.top (), empty, empty, " <<
+ (poly_runtime ? "0, " : "") << "true);"
+ << "}";
+
+ if (a.context ().get<UnsignedLong> ("p:effective-min") != 0)
+ {
+ os << "else" << endl
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);";
+
+ /*
+ << "this->_expected_element (" << endl;
+ particle_name_.dispatch (a);
+ os << ");";
+ */
+ }
+
+ os << endl
+ << "vs.size--;" // pop
+ << "v_all_count_.pop ();";
+ }
+
+ virtual Void
+ traverse (SemanticGraph::Compositor& c) // Choice and sequence.
+ {
+ using SemanticGraph::Choice;
+
+ UnsignedLong min (
+ c.context ().get<UnsignedLong> ("p:effective-min"));
+
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_* vd = vs.data + (vs.size - 1);"
+ << endl;
+
+
+ // Flush unfinished state machines with the empty element name.
+ // This allows us to detect missing content. Note that I am
+ // not re-setting vd since no new compositors are pushed on
+ // flush.
+ //
+ os << string_type << " empty;"
+ << "while (vd->func != 0)"
+ << "{"
+ << "(this->*vd->func) (vd->state, vd->count, empty, empty, " <<
+ (poly_runtime ? "0, " : "") << "true);"
+ << endl
+ << "if (ctx.error_type ())" << endl
+ << "return;"
+ << endl
+ << "assert (vd->state == ~0UL);"
+ << "vd = vs.data + (--vs.size - 1);" // pop
+ << "}";
+
+
+ Choice* pc (dynamic_cast<Choice*> (&c));
+
+ if (pc && c.min () == 1 && min == 0 && c.max () == 1)
+ {
+ // This is a required choice with effective-min == 0 (i.e.,
+ // it contains optional particle). We need to call the arm
+ // callback with that optional particle's tag.
+ //
+ SemanticGraph::Particle* p (0);
+ OptionalParticleTest test (p);
+ test.traverse (*pc);
+
+ if (p)
+ {
+ os << "if (vd->count == 0)" << endl
+ << "{";
+ choice_arm_call (p, pc, this);
+ os << "}";
+ }
+ }
+
+ // Check if min cardinality requirements have been met. Since
+ // count is always >= 0, don't generate dead code if min == 0.
+ //
+ if (min != 0)
+ {
+ os << "if (vd->count < " << min << "UL)" << endl
+ << "this->_schema_error (" <<
+ "::xsde::cxx::schema_error::expected_element);";
+ }
+ }
+
+ private:
+ SemanticGraph::Complex& type_;
+ ParticleName particle_name_;
+ };
+
+
+ //
+ //
+ struct Complex : Traversal::Complex, Context
+ {
+ Complex (Context& c)
+ : Context (c)
+ {
+ }
+
+ virtual Void
+ traverse (Type& c)
+ {
+ // Nothing to generate if we don't have any elements and wildcards.
+ //
+ if (!has<Traversal::Element> (c) &&
+ !has_particle<Traversal::Any> (c))
+ return;
+
+ using SemanticGraph::Compositor;
+
+ String const& name (ename (c));
+ Compositor& comp (c.contains_compositor ().compositor ());
+
+ // Don't use restriction_p here since we don't want special
+ // treatment of anyType.
+ //
+ Boolean restriction (
+ c.inherits_p () &&
+ c.inherits ().is_a<SemanticGraph::Restricts> ());
+
+ os <<"// Element validation and dispatch functions for " <<
+ name << "." << endl
+ <<"//" << endl;
+
+ // _start_element_impl
+ //
+
+ os << "bool " << name << "::" << endl
+ << "_start_element_impl (const " << string_type << "& ns," << endl
+ << "const " << string_type << "& n";
+
+ if (poly_runtime)
+ os << "," << endl
+ << "const char*" << (poly_code ? " t" : "");
+
+ os << ")"
+ << "{";
+
+ if (poly_code)
+ os << "XSDE_UNUSED (t);"
+ << endl;
+
+ os << "::xsde::cxx::parser::context& ctx = this->_context ();"
+ << endl;
+
+
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_* vd = vs.data + (vs.size - 1);"
+ << endl;
+
+ //@@ OPT: I don't really need to call parser_base since it always
+ // returns false.
+ //
+ // In case of an inheritance-by-extension, call our base first.
+ // We don't need to generate this code for the 'all' compositor
+ // because it can only inherit from the empty content model.
+ // Sattes of the root machine for sequence and choice:
+ //
+ // 0 - calling base
+ // 1 - base returned false
+ // ~0 - terminal state
+ //
+ if (!restriction && !comp.is_a<SemanticGraph::All> ())
+ {
+ os << "if (vd->func == 0 && vd->state == 0)"
+ << "{";
+
+ // We cannot use the fully-qualified base name directly
+ // because of some broken compilers (EVC 4.0).
+ //
+ String base (unclash (name, "base"));
+
+ os << "typedef ";
+
+ if (c.inherits_p ())
+ os << fq_name (c.inherits ().base ());
+ else
+ os << complex_base;
+
+ os << " " << base << ";"
+ << "if (" << base << "::";
+
+ if (poly_runtime)
+ os << "_start_element_impl (ns, n, " <<
+ (poly_code ? "t" : "0") << "))" << endl;
+ else
+ os << "_start_element_impl (ns, n))" << endl;
+
+ os << "return true;"
+ << "else" << endl
+ << "vd->state = 1;"
+ << "}";
+ }
+
+ {
+ CompositorStartElement t (*this, c);
+ t.dispatch (comp);
+ }
+
+ os << "return true;"
+ << "}";
+
+
+ // _end_element_impl
+ //
+
+ os << "bool " << name << "::" << endl
+ << "_end_element_impl (const " << string_type << "& ns," << endl
+ << "const " << string_type << "& n)"
+ << "{";
+
+ os << "v_state_& vs = *static_cast< v_state_* > (" <<
+ "this->v_state_stack_.top ());"
+ << "v_state_descr_& vd = vs.data[vs.size - 1];"
+ << endl;
+
+ //@@ OPT: I don't really need to call parser_base since it always
+ // returns false.
+ //
+ // In case of an inheritance-by-extension, call our base first.
+ // We don't need to generate this code for the 'all' compositor
+ // because it can only inherit from the empty content model.
+ //
+ if (!restriction && !comp.is_a<SemanticGraph::All> ())
+ {
+ os << "if (vd.func == 0 && vd.state == 0)"
+ << "{";
+
+ // We cannot use the fully-qualified base name directly
+ // because of some broken compilers (EVC 4.0).
+ //
+ String base (unclash (name, "base"));
+
+ os << "typedef ";
+
+ if (c.inherits_p ())
+ os << fq_name (c.inherits ().base ());
+ else
+ os << complex_base;
+
+ os << " " << base << ";"
+ << "if (!" << base << "::_end_element_impl (ns, n))" << endl
+ << "assert (false);" // Start and end should match.
+ << "return true;"
+ << "}";
+ }
+
+ {
+ CompositorEndElement t (*this, c);
+ t.dispatch (comp);
+ }
+
+ os << "return true;"
+ << "}";
+
+
+ // _pre_e_validate
+ //
+ os << "void " << name << "::" << endl
+ << "_pre_e_validate ()"
+ << "{";
+
+ if (exceptions)
+ os << "this->v_state_stack_.push ();";
+ else
+ os << "if (this->v_state_stack_.push ())"
+ << "{"
+ << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
+ << "return;"
+ << "}";
+
+ os << "static_cast< v_state_* > (this->v_state_stack_.top ())->" <<
+ "size = 0;"
+ << endl;
+
+ {
+ // Assuming that this code cannot trigger an error.
+ //
+ CompositorPre t (*this, c);
+ t.dispatch (comp);
+ }
+
+ // In case of an inheritance-by-extension, call our base
+ // _pre_e_validate. We don't need to generate this code for the
+ // 'all' compositor because it can only inherit from the empty
+ // content model.
+ //
+ if (!restriction && !comp.is_a<SemanticGraph::All> ())
+ {
+ // We don't need to call parser_base's implementation
+ // since it does nothing.
+ //
+ if (c.inherits_p ())
+ {
+ // We cannot use the fully-qualified base name directly
+ // because of some broken compilers (EVC 4.0).
+ //
+ String base (unclash (name, "base"));
+
+ os << "typedef " << fq_name (c.inherits ().base ()) << " " <<
+ base << ";"
+ << base << "::_pre_e_validate ();";
+ }
+ }
+
+ os << "}";
+
+
+ // _post_e_validate
+ //
+ os << "void " << name << "::" << endl
+ << "_post_e_validate ()"
+ << "{";
+
+ if (!comp.is_a<SemanticGraph::All> ())
+ os << "::xsde::cxx::parser::context& ctx = this->_context ();"
+ << endl;
+
+ // In case of an inheritance-by-extension, call our base
+ // _post_e_validate. We don't need to generate this code for
+ // the 'all' compositor because it can only inherit from
+ // the empty content model.
+ //
+ if (!restriction && !comp.is_a<SemanticGraph::All> ())
+ {
+ // We don't need to call parser_base's implementation
+ // since it does nothing.
+ //
+ if (c.inherits_p ())
+ {
+ // We cannot use the fully-qualified base name directly
+ // because of some broken compilers (EVC 4.0).
+ //
+ String base (unclash (name, "base"));
+
+ os << "typedef " << fq_name (c.inherits ().base ()) << " " <<
+ base << ";"
+ << base << "::_post_e_validate ();"
+ << endl;
+
+ os << "if (ctx.error_type ())" << endl
+ << "return;"
+ << endl;
+ }
+ }
+
+ {
+ CompositorPost t (*this, c);
+ t.dispatch (c.contains_compositor ().compositor ());
+ }
+
+ os << endl
+ << "this->v_state_stack_.pop ();"
+ << "}";
+
+ //
+ //
+ ParticleFunction t (*this, c);
+ t.dispatch (c.contains_compositor ().compositor ());
+ }
+ };
+ }
+
+ Void
+ generate_element_validation_source (Context& ctx)
+ {
+ ctx.os << "#include <assert.h>" << endl
+ << endl;
+
+ Traversal::Schema schema;
+
+ Traversal::Sources sources;
+ Traversal::Names schema_names;
+
+ Namespace ns (ctx);
+ Traversal::Names names;
+
+ schema >> sources >> schema;
+ schema >> schema_names >> ns >> names;
+
+ Complex complex (ctx);
+
+ names >> complex;
+
+ schema.dispatch (ctx.schema_root);
+ }
+ }
+}