aboutsummaryrefslogtreecommitdiff
path: root/xsde
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-03-11 09:30:41 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-03-11 09:30:41 +0200
commit9db750f407ceeb5c1fab99414b074d289bfda179 (patch)
treeeb1a5e52ebf84d79d378d5ab2ae56372028776e0 /xsde
parentbc628cff98a1d90d4ee293f22979db56b4ed0695 (diff)
Add support for parsing/serialization of recursive types
tests/cxx/hybrid/recursive/: new test
Diffstat (limited to 'xsde')
-rw-r--r--xsde/cxx/hybrid/elements.cxx32
-rw-r--r--xsde/cxx/hybrid/elements.hxx18
-rw-r--r--xsde/cxx/hybrid/parser-header.cxx49
-rw-r--r--xsde/cxx/hybrid/parser-name-processor.cxx15
-rw-r--r--xsde/cxx/hybrid/parser-source.cxx381
-rw-r--r--xsde/cxx/hybrid/serializer-header.cxx62
-rw-r--r--xsde/cxx/hybrid/serializer-name-processor.cxx15
-rw-r--r--xsde/cxx/hybrid/serializer-source.cxx293
-rw-r--r--xsde/cxx/hybrid/tree-size-processor.cxx45
9 files changed, 727 insertions, 183 deletions
diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx
index c7609ff..68af8df 100644
--- a/xsde/cxx/hybrid/elements.cxx
+++ b/xsde/cxx/hybrid/elements.cxx
@@ -144,15 +144,27 @@ namespace CXX
}
String const& Context::
- epstate_member (SemanticGraph::Type& t)
+ epstate_base (SemanticGraph::Type& t)
{
- return t.context ().get<String> ("pstate-member");
+ return t.context ().get<String> ("pstate-base");
}
String const& Context::
- epstate_base (SemanticGraph::Type& t)
+ epstate_first (SemanticGraph::Type& t)
{
- return t.context ().get<String> ("pstate-base");
+ return t.context ().get<String> ("pstate-first");
+ }
+
+ String const& Context::
+ epstate_top (SemanticGraph::Type& t)
+ {
+ return t.context ().get<String> ("pstate-top");
+ }
+
+ String const& Context::
+ epstate_member (SemanticGraph::Type& t)
+ {
+ return t.context ().get<String> ("pstate-member");
}
String const& Context::
@@ -256,6 +268,18 @@ namespace CXX
}
String const& Context::
+ esstate_first (SemanticGraph::Type& t)
+ {
+ return t.context ().get<String> ("sstate-first");
+ }
+
+ String const& Context::
+ esstate_top (SemanticGraph::Type& t)
+ {
+ return t.context ().get<String> ("sstate-top");
+ }
+
+ String const& Context::
esstate_member (SemanticGraph::Type& t)
{
return t.context ().get<String> ("sstate-member");
diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx
index 73caa35..f5d959b 100644
--- a/xsde/cxx/hybrid/elements.hxx
+++ b/xsde/cxx/hybrid/elements.hxx
@@ -332,6 +332,12 @@ namespace CXX
epstate_base (SemanticGraph::Type&);
static String const&
+ epstate_first (SemanticGraph::Type&);
+
+ static String const&
+ epstate_top (SemanticGraph::Type&);
+
+ static String const&
epstate_member (SemanticGraph::Type&);
static String const&
@@ -396,6 +402,12 @@ namespace CXX
esstate_type (SemanticGraph::Type&);
static String const&
+ esstate_first (SemanticGraph::Type&);
+
+ static String const&
+ esstate_top (SemanticGraph::Type&);
+
+ static String const&
esstate_member (SemanticGraph::Type&);
static String const&
@@ -479,6 +491,12 @@ namespace CXX
return c.context ().get<Boolean> ("fixed");
}
+ Boolean
+ recursive (SemanticGraph::Type& t)
+ {
+ return t.context ().count ("recursive");
+ }
+
public:
String
istream (NarrowString const& is) const;
diff --git a/xsde/cxx/hybrid/parser-header.cxx b/xsde/cxx/hybrid/parser-header.cxx
index 450a27e..72cc2e3 100644
--- a/xsde/cxx/hybrid/parser-header.cxx
+++ b/xsde/cxx/hybrid/parser-header.cxx
@@ -397,6 +397,7 @@ namespace CXX
Boolean restriction (restriction_p (c));
Boolean fixed (fixed_length (c));
+ Boolean rec (recursive (c));
String const& ret (pret_type (c));
@@ -460,6 +461,15 @@ namespace CXX
}
}
+ // _post
+ //
+ if (rec && hb && !recursive (c.inherits ().base ()))
+ {
+ os << "virtual void" << endl
+ << "_post ();"
+ << endl;
+ }
+
// post
//
os << "virtual " << ret << endl
@@ -476,6 +486,13 @@ namespace CXX
<< pre_impl_name (c) << " (" << type << "*);"
<< endl;
+ // Base implementation.
+ //
+ if (tiein && hb)
+ os << (tiein ? "public:" : "protected:") << endl
+ << fq_name (c.inherits ().base (), "p:impl") << " base_impl_;"
+ << endl;
+
// State.
//
String const& state_type (epstate_type (c));
@@ -493,32 +510,35 @@ namespace CXX
if (!restriction && c.contains_compositor_p ())
contains_compositor (c, contains_compositor_state_);
- os << "};"
- << state_type << " " << epstate (c) << ";";
+ os << "};";
- if (!fixed)
- os << "bool " << epstate_base (c) << ";";
+ if (rec)
+ {
+ os << state_type << " " << epstate_first (c) << ";"
+ << "::xsde::cxx::stack " << epstate (c) << ";";
- os << endl;
+ if (hb && !recursive (c.inherits ().base ()))
+ os << "bool " << epstate_top (c) << ";";
+ }
+ else
+ os << state_type << " " << epstate (c) << ";";
- // Base implementation.
- //
- if (tiein && hb)
- os << (tiein ? "public:" : "protected:") << endl
- << fq_name (c.inherits ().base (), "p:impl") << " base_impl_;"
- << endl;
+ if (!fixed)
+ os << "bool " << epstate_base (c) << ";";
os << "};";
}
// Generate include for custom parser.
//
- if (c.context ().count ("p:impl-include"))
+ SemanticGraph::Context& ctx (c.context ());
+
+ if (ctx.count ("p:impl-include"))
{
close_ns ();
os << "#include " << process_include_path (
- c.context ().get<String> ("p:impl-include")) << endl
+ ctx.get<String> ("p:impl-include")) << endl
<< endl;
open_ns ();
@@ -547,6 +567,9 @@ namespace CXX
Void
generate_parser_header (Context& ctx)
{
+ ctx.os << "#include <xsde/cxx/stack.hxx>" << endl
+ << endl;
+
Traversal::Schema schema;
Traversal::Sources sources;
diff --git a/xsde/cxx/hybrid/parser-name-processor.cxx b/xsde/cxx/hybrid/parser-name-processor.cxx
index 482c195..c913766 100644
--- a/xsde/cxx/hybrid/parser-name-processor.cxx
+++ b/xsde/cxx/hybrid/parser-name-processor.cxx
@@ -126,6 +126,12 @@ namespace CXX
return t.context ().get<Boolean> ("fixed");
}
+ Boolean
+ recursive (SemanticGraph::Type& t)
+ {
+ return t.context ().count ("recursive");
+ }
+
public:
String
find_name (String const& n, String const& suffix, NameSet& set)
@@ -379,6 +385,15 @@ namespace CXX
cc.set ("pstate-type", state_type);
cc.set ("pstate", find_name (state_type, "_", set));
+
+ if (recursive (c))
+ {
+ cc.set ("pstate-first", find_name (state_type, "_first_", set));
+
+ if (c.inherits_p () && !recursive (c.inherits ().base ()))
+ cc.set ("pstate-top", find_name (state_type, "_top_", set));
+ }
+
cc.set ("pstate-base", find_name (base + L"_base", "_", set));
// State members are in a nested struct so use a new and
diff --git a/xsde/cxx/hybrid/parser-source.cxx b/xsde/cxx/hybrid/parser-source.cxx
index 4f5fc38..f9c1855 100644
--- a/xsde/cxx/hybrid/parser-source.cxx
+++ b/xsde/cxx/hybrid/parser-source.cxx
@@ -412,8 +412,22 @@ namespace CXX
String tmp;
tmp.swap (r);
- r = epstate (t);
- r += L".";
+
+ if (!recursive (t))
+ {
+ r = L"this->";
+ r += epstate (t);
+ r += L".";
+ }
+ else
+ {
+ r = L"static_cast< ";
+ r += epstate_type (t);
+ r += L"* > (this->";
+ r += epstate (t);
+ r += L".top ())->";
+ }
+
r += tmp;
return r;
@@ -426,8 +440,23 @@ namespace CXX
Complex& t (dynamic_cast<Complex&> (a.scope ()));
- String r (epstate (t));
- r += L".";
+ String r;
+
+ if (!recursive (t))
+ {
+ r = L"this->";
+ r += epstate (t);
+ r += L".";
+ }
+ else
+ {
+ r = L"static_cast< ";
+ r += epstate_type (t);
+ r += L"* > (this->";
+ r += epstate (t);
+ r += L".top ())->";
+ }
+
r += epstate_member (t);
r += fixed_length (t) ? L"." : L"->";
@@ -492,7 +521,7 @@ namespace CXX
String access (access_seq (a));
if (fixed_length (a))
- os << "this->" << access << epresent (a) << " (true);";
+ os << access << epresent (a) << " (true);";
else
{
String const& name (ename (a));
@@ -500,13 +529,13 @@ namespace CXX
String const& scope (fq_scope (a));
if (exceptions)
- os << "this->" << access << name << " (new " <<
+ os << access << name << " (new " <<
scope << "::" << type << ");";
else
os << scope << "::" << type << "* x = new " <<
scope << "::" << type << ";"
<< "if (x)" << endl
- << "this->" << access << name << " (x);"
+ << access << name << " (x);"
<< "else" << endl
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);";
}
@@ -538,57 +567,57 @@ namespace CXX
if (fixed_length (c))
{
if (exceptions)
- os << "this->" << access_s << name << " ().push_back (" <<
+ os << access_s << name << " ().push_back (" <<
type_scope << "::" << type << " ());";
else
- os << "if (this->" << access_s << name << " ().push_back (" <<
+ os << "if (" << access_s << name << " ().push_back (" <<
type_scope << "::" << type << " ()))"
<< "{"
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
<< "return;"
<< "}";
- os << "this->" << access << ptr << " = &this->" <<
- access_s << name << " ().back ();";
+ os << access << ptr << " = &" << access_s << name <<
+ " ().back ();";
}
else
{
- os << "this->" << access << ptr << " = new " <<
- type_scope << "::" << type << ";";
+ os << access << ptr << " = new " << type_scope << "::" <<
+ type << ";";
if (exceptions)
- os << "this->" << access_s << name << " ().push_back (" <<
- "this->" << access << ptr << ");";
+ os << access_s << name << " ().push_back (" <<
+ access << ptr << ");";
else
- os << "if (!this->" << access << ptr << " ||" << endl
- << "this->" << access_s << name << " ().push_back (" <<
- "this->" << access << ptr << "))"
+ os << "if (!" << access << ptr << " ||" << endl
+ << access_s << name << " ().push_back (" <<
+ access << ptr << "))"
<< "{"
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
<< "return;"
<< "}";
}
- os << "this->" << access << ptr << "->";
+ os << access << ptr << "->";
}
else if (c.min () == 0)
{
String const& name (ename (c));
if (fixed_length (c))
- os << "this->" << access << epresent (c) << " (true);";
+ os << access << epresent (c) << " (true);";
else
{
String const& type (etype (c));
if (exceptions)
- os << "this->" << access << name << " (new " <<
- type_scope << "::" << type << ");";
+ os << access << name << " (new " << type_scope << "::" <<
+ type << ");";
else
os << type_scope << "::" << type << "* x = new " <<
type_scope << "::" << type << ";"
<< "if (x)" << endl
- << "this->" << access << name << " (x);"
+ << access << name << " (x);"
<< "else"
<< "{"
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
@@ -596,7 +625,7 @@ namespace CXX
<< "}";
}
- os << "this->" << access << name << " ().";
+ os << access << name << " ().";
}
else
{
@@ -604,12 +633,13 @@ namespace CXX
// type (and accessor function) even for min == max == 1.
//
if (c.context ().count ("type"))
- os << "this->" << access << ename (c) << " ().";
+ os << access << ename (c) << " ().";
else
- os << "this->" << access;
+ os << access;
}
- os << earm (c) << " (static_cast< " << type_scope;
+ os << earm (c) << " (" << endl
+ << "static_cast< " << type_scope;
if (c.context ().count ("type"))
os << "::" << etype (c);
@@ -656,13 +686,13 @@ namespace CXX
String const& scope (fq_scope (p));
if (exceptions)
- os << "this->" << access_seq (p) << ename (p) <<
+ os << access_seq (p) << ename (p) <<
" (new " << scope << "::" << type << ");";
else
os << scope << "::" << type << "* x = new " <<
scope << "::" << type << ";"
<< "if (x)" << endl
- << "this->" << access_seq (p) << ename (p) << " (x);"
+ << access_seq (p) << ename (p) << " (x);"
<< "else" << endl
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);";
@@ -704,31 +734,31 @@ namespace CXX
if (fixed_length (s))
{
if (exceptions)
- os << "this->" << access_s << name << " ().push_back (" <<
+ os << access_s << name << " ().push_back (" <<
scope << "::" << type << " ());";
else
- os << "if (this->" << access_s << name << " ().push_back (" <<
+ os << "if (" << access_s << name << " ().push_back (" <<
scope << "::" << type << " ()))"
<< "{"
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
<< "return;"
<< "}";
- os << "this->" << access << ptr << " = &this->" <<
- access_s << name << " ().back ();";
+ os << access << ptr << " = &" << access_s << name <<
+ " ().back ();";
}
else
{
- os << "this->" << access << ptr << " = new " <<
- scope << "::" << type << ";";
+ os << access << ptr << " = new " << scope << "::" <<
+ type << ";";
if (exceptions)
- os << "this->" << access_s << name << " ().push_back (" <<
- "this->" << access << ptr << ");";
+ os << access_s << name << " ().push_back (" <<
+ access << ptr << ");";
else
- os << "if (!this->" << access << ptr << " ||" << endl
- << "this->" << access_s << name << " ().push_back (" <<
- "this->" << access << ptr << "))" << endl
+ os << "if (!" << access << ptr << " ||" << endl
+ << access_s << name << " ().push_back (" <<
+ access << ptr << "))" << endl
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);";
}
@@ -745,7 +775,7 @@ namespace CXX
String access (access_seq (s));
if (fixed_length (s))
- os << "this->" << access << epresent (s) << " (true);";
+ os << access << epresent (s) << " (true);";
else
{
String const& name (ename (s));
@@ -753,13 +783,13 @@ namespace CXX
String const& scope (fq_scope (s));
if (exceptions)
- os << "this->" << access << name << " (new " <<
+ os << access << name << " (new " <<
scope << "::" << type << ");";
else
os << scope << "::" << type << "* x = new " <<
scope << "::" << type << ";"
<< "if (x)" << endl
- << "this->" << access << name << " (x);"
+ << access << name << " (x);"
<< "else" << endl
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);";
}
@@ -815,16 +845,15 @@ namespace CXX
if (e.max () != 1)
{
if (exceptions)
- os << "this->" << access_seq (e) << ename (e) <<
- " ().push_back (x);";
+ os << access_seq (e) << ename (e) << " ().push_back (x);";
else
- os << "if (this->" << access_seq (e) << ename (e) <<
+ os << "if (" << access_seq (e) << ename (e) <<
" ().push_back (x))" << endl
<< "this->_sys_error (::xsde::cxx::sys_error::no_memory);";
}
else
{
- os << "this->" << access_seq (e) << ename (e) << " (x);";
+ os << access_seq (e) << ename (e) << " (x);";
}
os << "}";
@@ -861,7 +890,7 @@ namespace CXX
{
os << arg << " x)"
<< "{"
- << "this->" << access_seq (a) << ename (a) << " (x);"
+ << access_seq (a) << ename (a) << " (x);"
<< "}";
}
else
@@ -903,8 +932,12 @@ namespace CXX
Boolean hb (c.inherits_p ());
Boolean restriction (restriction_p (c));
Boolean fixed (fixed_length (c));
- Boolean c_string_base (false);
+ Boolean rec (recursive (c));
+
+ Boolean validation (!options.value<CLI::suppress_validation> () &&
+ !options.value<CLI::suppress_parser_val> ());
+ Boolean c_string_base (false);
if (!stl && hb)
{
StringType test (c_string_base);
@@ -915,8 +948,17 @@ namespace CXX
String const& state (epstate (c));
String const& member (epstate_member (c));
+ String const& state_type (epstate_type (c));
String const& type (fq_name (c));
+ String top_member;
+ if (rec)
+ {
+ top_member = L"static_cast< " + state_type + L"* > (this->" +
+ state + L".top ())->" + member;
+ }
+
+
os << "// " << name << endl
<< "//" << endl
<< endl;
@@ -928,11 +970,15 @@ namespace CXX
os << name << "::" << endl
<< name << " (" << (fixed ? "" : "bool b") << ")";
+ String d ("\n: ");
+
if (hb)
{
if (tiein)
- os << endl
- << ": " << epskel (c) << " (&base_impl_)";
+ {
+ os << d << epskel (c) << " (&base_impl_)";
+ d = ",\n ";
+ }
SemanticGraph::Type& b (c.inherits ().base ());
@@ -942,19 +988,29 @@ namespace CXX
if (!c_string_base && !fixed_length (b))
{
if (tiein)
- os << "," << endl
- << " " << "base_impl_" << " (true)";
+ os << d << "base_impl_" << " (true)";
else
- os << endl
- << ": " << fq_name (b, "p:impl") << " (true)";
+ os << d << fq_name (b, "p:impl") << " (true)";
+
+ d = ",\n ";
}
}
+ if (rec)
+ {
+ os << d << state << " (sizeof (" << state_type <<
+ " ), &" << epstate_first (c) << ")";
+ }
+
os << "{";
if (!fixed)
- os << "this->" << epstate_base (c) << " = b;"
- << "this->" << state << "." << member << " = 0;";
+ {
+ os << "this->" << epstate_base (c) << " = b;";
+
+ if (!rec)
+ os << "this->" << state << "." << member << " = 0;";
+ }
os << "}";
}
@@ -965,32 +1021,63 @@ namespace CXX
//
os << name << "::" << endl
<< "~" << name << " ()"
- << "{"
- << "if (!this->" << epstate_base (c) << ")" << endl
- << "delete this->" << state << "." << member << ";"
- << "}";
+ << "{";
+
+ if (!rec)
+ {
+ os << "if (!this->" << epstate_base (c) << ")" << endl
+ << "delete this->" << state << "." << member << ";";
+ }
+ else
+ {
+ os << "for (; !this->" << state << ".empty (); " <<
+ "this->" << state << ".pop ())"
+ << "{"
+ << "if (!this->" << epstate_base (c) << ")" << endl
+ << "delete " << top_member << ";"
+ << "}";
+ }
+
+ os << "}";
// reset
//
if (reset)
+ {
os << "void " << name << "::" << endl
<< "_reset ()"
<< "{";
- if (mixin && hb)
- os << epimpl (c); //@@ fq-name
- else
- os << epskel (c); //@@ fq-name
+ if (mixin && hb)
+ os << epimpl (c); //@@ fq-name
+ else
+ os << epskel (c); //@@ fq-name
- os << "::_reset ();"
- << endl;
+ os << "::_reset ();"
+ << endl;
- os << "if (!this->" << epstate_base (c) << ")"
- << "{"
- << "delete this->" << state << "." << member << ";"
- << "this->" << state << "." << member << " = 0;"
- << "}"
- << "}";
+ if (!rec)
+ {
+ os << "if (!this->" << epstate_base (c) << ")"
+ << "{"
+ << "delete this->" << state << "." << member << ";"
+ << "this->" << state << "." << member << " = 0;"
+ << "}";
+ }
+ else
+ {
+ // Same code as in d-tor.
+ //
+ os << "for (; !this->" << state << ".empty (); " <<
+ "this->" << state << ".pop ())"
+ << "{"
+ << "if (!this->" << epstate_base (c) << ")" << endl
+ << "delete " << top_member << ";"
+ << "}";
+ }
+
+ os << "}";
+ }
}
// pre_impl
@@ -999,8 +1086,83 @@ namespace CXX
{
os << "void " << name << "::" << endl
<< pre_impl_name (c) << " (" << type << "* x)"
- << "{"
- << "this->" << state << "." << member << " = x;";
+ << "{";
+
+ if (!rec)
+ os << "this->" << state << "." << member << " = x;";
+ else
+ {
+ // If we are recursive but our base is not, we need
+ // to call _post() and post() to end parsing and copy
+ // the result in case of recursion.
+ //
+ if (hb && !recursive (c.inherits ().base ()))
+ {
+ SemanticGraph::Type& b (c.inherits ().base ());
+
+ os << "if (!this->" << state << ".empty ())"
+ << "{";
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << epimpl (b) << "::"; //@@ fq-name.
+
+ os << "_post ();";
+
+ if (!exceptions || validation)
+ {
+ os << endl
+ << "if (this->_context ().error_type ())" << endl
+ << "return;"
+ << endl;
+ }
+
+ // The following code is similar to what we have in post().
+ //
+
+ // Default parser implementations for anyType and
+ // anySimpleType return void.
+ //
+ if (!b.is_a<SemanticGraph::AnyType> () &&
+ !b.is_a<SemanticGraph::AnySimpleType> ())
+ {
+ // If our base is a fixed-length type then copy the data
+ // over. Note that it cannot be a C-string.
+ //
+ if (fixed_length (b))
+ {
+ os << "static_cast< ";
+
+ base_name_.dispatch (b);
+
+ os << "& > (" << endl
+ << "*" << top_member << ") = " << endl;
+ }
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << epimpl (b) << "::"; //@@ fq-name.
+
+ os << post_name (b) << " ();";
+ }
+
+ os << "}"
+ << "else" << endl
+ << "this->" << epstate_top (c) << " = true;"
+ << endl;
+ }
+
+ if (exceptions)
+ os << "this->" << state << ".push ();";
+ else
+ os << "if (this->" << state << ".push ())" << endl
+ << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
+ << endl;
+
+ os << top_member << " = x;";
+ }
// Call base pre_impl (var-length) or pre (fix-length). C-string-
// based built-in parser implementations don't have pre_impl().
@@ -1068,6 +1230,27 @@ namespace CXX
contains_compositor (c, contains_compositor_callback_);
}
+ // _post
+ //
+ if (rec && hb && !recursive (c.inherits ().base ()))
+ {
+ // If we are recursive but our base is not, we only call
+ // base _post() if it is the first _post call.
+ //
+ os << "void " << name << "::" << endl
+ << "_post ()"
+ << "{"
+ << "if (this->" << epstate_top (c) << ")" << endl;
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << epimpl (c.inherits ().base ()) << "::"; //@@ fq-name.
+
+ os << "_post ();"
+ << "}";
+ }
+
// post
//
os << ret << " " << name << "::" << endl
@@ -1084,6 +1267,16 @@ namespace CXX
if (!b.is_a<SemanticGraph::AnyType> () &&
!b.is_a<SemanticGraph::AnySimpleType> ())
{
+ // If we are recursive but our base is not, we only call
+ // base post() if it is the first post call.
+ //
+ if (rec && !recursive (b))
+ {
+ os << "if (this->" << epstate_top (c) << ")"
+ << "{"
+ << "this->" << epstate_top (c) << " = false;";
+ }
+
// If our base is a fixed-length type or C-string-base, then
// copy the data over.
//
@@ -1093,8 +1286,16 @@ namespace CXX
base_name_.dispatch (b);
- os << "& > (" << (fixed ? "" : "*") << "this->" <<
- state << "." << member << ") = ";
+ os << "& > (";
+
+ if (!rec)
+ os << (fixed ? "" : "*") << "this->" << state << "." <<
+ member;
+ else
+ os << endl
+ << "*" << top_member;
+
+ os << ") = " << endl;
}
if (c_string_base)
@@ -1103,8 +1304,14 @@ namespace CXX
base_name_.dispatch (b);
- os << "* > (this->" <<
- state << "." << member << ")->base_value (";
+ os << "* > (";
+
+ if (!rec)
+ os << "this->" << state << "." << member;
+ else
+ os << top_member;
+
+ os << ")->base_value (" << endl;
}
if (tiein)
@@ -1118,15 +1325,25 @@ namespace CXX
os << ")";
os << ";";
+
+ if (rec && !recursive (b))
+ os << "}";
}
}
if (fixed)
os << "return this->" << state << "." << member << ";";
else
- os << type << "* r = this->" << state << "." << member << ";"
- << "this->" << state << "." << member << " = 0;"
- << "return r;";
+ {
+ if (!rec)
+ os << type << "* r = this->" << state << "." << member << ";"
+ << "this->" << state << "." << member << " = 0;";
+ else
+ os << type << "* r = " << top_member << ";"
+ << "this->" << state << ".pop ();";
+
+ os << "return r;";
+ }
os << "}";
}
diff --git a/xsde/cxx/hybrid/serializer-header.cxx b/xsde/cxx/hybrid/serializer-header.cxx
index c6fbc6c..20f4e15 100644
--- a/xsde/cxx/hybrid/serializer-header.cxx
+++ b/xsde/cxx/hybrid/serializer-header.cxx
@@ -400,6 +400,8 @@ namespace CXX
Boolean hae (has_particle<Traversal::Any> (c));
Boolean haa (has<Traversal::AnyAttribute> (c));
+ Boolean rec (recursive (c));
+
String const& arg (sarg_type (c));
os << "class " << name << ": public " <<
@@ -414,7 +416,7 @@ namespace CXX
// c-tor
//
- if (tiein && hb)
+ if (rec || (tiein && hb))
os << name << " ();"
<< endl;
@@ -445,12 +447,40 @@ namespace CXX
}
}
+ if (rec)
+ {
+ // _post
+ //
+ if (hb && !recursive (c.inherits ().base ()))
+ os << "virtual void" << endl
+ << "_post ();"
+ << endl;
+
+ // post
+ //
+ os << "virtual void" << endl
+ << "post ();"
+ << endl;
+
+ // reset
+ //
+ if (reset)
+ os << "virtual void" << endl
+ << "_reset ();"
+ << endl;
+ }
+
+ if (tiein && hb)
+ os << (tiein ? "public:" : "protected:") << endl
+ << fq_name (c.inherits ().base (), "s:impl") << " base_impl_;"
+ << endl;
+
if (!restriction)
{
String const& state_type (esstate_type (c));
String const& member (esstate_member (c));
- os << "protected:" << endl
+ os << (tiein ? "public:" : "protected:") << endl
<< "struct " << state_type
<< "{"
<< "const " << fq_name (c) << "* " << member << ";";
@@ -458,26 +488,33 @@ namespace CXX
if (c.contains_compositor_p ())
contains_compositor (c, contains_compositor_state_);
- os << "};"
- << state_type << " " << esstate (c) << ";";
- }
+ os << "};";
- if (tiein && hb)
- os << endl
- << "protected:" << endl
- << fq_name (c.inherits ().base (), "s:impl") << " base_impl_;";
+ if (rec)
+ {
+ os << state_type << " " << esstate_first (c) << ";"
+ << "::xsde::cxx::stack " << esstate (c) << ";";
+
+ if (hb && !recursive (c.inherits ().base ()))
+ os << "bool " << esstate_top (c) << ";";
+ }
+ else
+ os << state_type << " " << esstate (c) << ";";
+ }
os << "};";
}
// Generate include for custom serializer.
//
- if (c.context ().count ("s:impl-include"))
+ SemanticGraph::Context& ctx (c.context ());
+
+ if (ctx.count ("s:impl-include"))
{
close_ns ();
os << "#include " << process_include_path (
- c.context ().get<String> ("s:impl-include")) << endl
+ ctx.get<String> ("s:impl-include")) << endl
<< endl;
open_ns ();
@@ -507,6 +544,9 @@ namespace CXX
Void
generate_serializer_header (Context& ctx)
{
+ ctx.os << "#include <xsde/cxx/stack.hxx>" << endl
+ << endl;
+
Traversal::Schema schema;
Traversal::Sources sources;
diff --git a/xsde/cxx/hybrid/serializer-name-processor.cxx b/xsde/cxx/hybrid/serializer-name-processor.cxx
index 8d3c15d..b6ab09b 100644
--- a/xsde/cxx/hybrid/serializer-name-processor.cxx
+++ b/xsde/cxx/hybrid/serializer-name-processor.cxx
@@ -142,6 +142,13 @@ namespace CXX
}
public:
+ Boolean
+ recursive (SemanticGraph::Type& t)
+ {
+ return t.context ().count ("recursive");
+ }
+
+ public:
using CXX::Context::ename;
static String const&
@@ -391,6 +398,14 @@ namespace CXX
cc.set ("sstate-type", state_type);
cc.set ("sstate", find_name (state_type, "_", set));
+ if (recursive (c))
+ {
+ cc.set ("sstate-first", find_name (state_type, "_first_", set));
+
+ if (c.inherits_p () && !recursive (c.inherits ().base ()))
+ cc.set ("sstate-top", find_name (state_type, "_top_", set));
+ }
+
// State members are in a nested struct so use a new and
// empty name set.
//
diff --git a/xsde/cxx/hybrid/serializer-source.cxx b/xsde/cxx/hybrid/serializer-source.cxx
index 37fff42..6e82bd0 100644
--- a/xsde/cxx/hybrid/serializer-source.cxx
+++ b/xsde/cxx/hybrid/serializer-source.cxx
@@ -318,10 +318,23 @@ namespace CXX
String tmp;
tmp.swap (r);
- r = esstate (t);
- r += L".";
- r += tmp;
+ if (!recursive (t))
+ {
+ r = L"this->";
+ r += esstate (t);
+ r += L".";
+ }
+ else
+ {
+ r = L"static_cast< ";
+ r += esstate_type (t);
+ r += L"* > (this->";
+ r += esstate (t);
+ r += L".top ())->";
+ }
+
+ r += tmp;
return r;
}
@@ -332,8 +345,23 @@ namespace CXX
Complex& t (dynamic_cast<Complex&> (a.scope ()));
- String r (esstate (t));
- r += L".";
+ String r;
+
+ if (!recursive (t))
+ {
+ r = L"this->";
+ r += esstate (t);
+ r += L".";
+ }
+ else
+ {
+ r = L"static_cast< ";
+ r += esstate_type (t);
+ r += L"* > (this->";
+ r += esstate (t);
+ r += L".top ())->";
+ }
+
r += esstate_member (t);
r += L"->";
@@ -420,10 +448,10 @@ namespace CXX
// Initialize the iterator.
//
- os << "this->" << access << end << " = this->" <<
- access_s << ename (c) << " ().end ();"
- << "this->" << access << iter << " = this->" <<
- access << end << ";";
+ os << access << end << " = " << endl
+ << access_s << ename (c) << " ().end ();"
+ << access << iter << " = " << endl
+ << access << end << ";";
}
}
@@ -439,10 +467,10 @@ namespace CXX
// Initialize the iterator.
//
- os << "this->" << access << end << " = this->" <<
- access_s << ename (s) << " ().end ();"
- << "this->" << access << iter << " = this->" <<
- access << end << ";";
+ os << access << end << " = " << endl
+ << access_s << ename (s) << " ().end ();"
+ << access << iter << " = " << endl
+ << access << end << ";";
}
else if (s.min () == 1)
{
@@ -473,10 +501,10 @@ namespace CXX
// Initialize the iterator.
//
- os << "this->" << access << iter << " = this->" <<
- access_s << name << " ().begin ();"
- << "this->" << access << end << " = this->" <<
- access_s << name << " ().end ();";
+ os << access << iter << " = " << endl
+ << access_s << name << " ().begin ();"
+ << access << end << " = " << endl
+ << access_s << name << " ().end ();";
}
}
};
@@ -513,7 +541,7 @@ namespace CXX
os << "bool " << s << "::" << endl
<< espresent (a) << " ()"
<< "{"
- << "return this->" << access_seq (a) << epresent (a) << " ();"
+ << "return " << access_seq (a) << epresent (a) << " ();"
<< "}";
}
@@ -543,37 +571,36 @@ namespace CXX
os << "bool " << s << "::" << endl
<< esnext (c) << " ()"
<< "{"
- << "if (this->" << access << iter << " != this->" <<
- access << end << ")" << endl
- << "this->" << access << iter << "++;"
+ << "if (" << access << iter << " != " << endl
+ << access << end << ")" << endl
+ << access << iter << "++;"
<< "else" << endl
- << "this->" << access << iter << " = this->" <<
- access_s << ename (c) << " ().begin ();"
+ << access << iter << " = " << endl
+ << access_s << ename (c) << " ().begin ();"
<< endl
- << "return this->" << access << iter << " != this->" <<
- access << end << ";"
+ << "return " << access << iter << " != " << endl
+ << access << end << ";"
<< "}";
os << esskel (t) << "::" << arm_tag << " " << s << "::" << endl
<< esarm (c) << " ()"
<< "{"
<< arm_tag << " t (static_cast< " << arm_tag << " > (" << endl
- << "this->" << access << iter << "->" << earm (c) << " ()));";
+ << access << iter << "->" << earm (c) << " ()));";
}
else if (c.min () == 0)
{
os << "bool " << s << "::" << endl
<< espresent (c) << " ()"
<< "{"
- << "return this->" << access << epresent (c) << " ();"
+ << "return " << access << epresent (c) << " ();"
<< "}";
os << esskel (t) << "::" << arm_tag << " " << s << "::" << endl
<< esarm (c) << " ()"
<< "{"
<< arm_tag << " t (static_cast< " << arm_tag << " > (" << endl
- << "this->" << access << ename (c) << " ()." <<
- earm (c) << " ()));";
+ << access << ename (c) << " ()." << earm (c) << " ()));";
}
else
{
@@ -587,10 +614,9 @@ namespace CXX
// type (and accessor function) even for min == max == 1.
//
if (c.context ().count ("type"))
- os << "this->" << access << ename (c) << " ()." <<
- earm (c) << " ()));";
+ os << access << ename (c) << " ()." << earm (c) << " ()));";
else
- os << "this->" << access << earm (c) << " ()));";
+ os << access << earm (c) << " ()));";
}
// Test whether we have any arms that need initialization.
@@ -663,15 +689,15 @@ namespace CXX
os << "bool " << sc << "::" << endl
<< esnext (s) << " ()"
<< "{"
- << "if (this->" << access << iter << " != this->" <<
- access << end << ")" << endl
- << "this->" << access << iter << "++;"
+ << "if (" << access << iter << " != " << endl
+ << access << end << ")" << endl
+ << access << iter << "++;"
<< "else" << endl
- << "this->" << access << iter << " = this->" <<
- access_s << ename (s) << " ().begin ();"
+ << access << iter << " = " << endl
+ << access_s << ename (s) << " ().begin ();"
<< endl
- << "if (this->" << access << iter << " != this->" <<
- access << end << ")"
+ << "if (" << access << iter << " != " << endl
+ << access << end << ")"
<< "{";
Sequence::contains (s, init_);
@@ -687,7 +713,7 @@ namespace CXX
os << "bool " << sc << "::" << endl
<< espresent (s) << " ()"
<< "{"
- << "if (this->" << access_seq (s) << epresent (s) << " ())"
+ << "if (" << access_seq (s) << epresent (s) << " ())"
<< "{";
Sequence::contains (s, init_);
@@ -749,8 +775,8 @@ namespace CXX
os << "bool " << s << "::" << endl
<< esnext (e) << " ()"
<< "{"
- << "return this->" << access << iter << " != this->" <<
- access << esstate_member_end (e) << ";"
+ << "return " << access << iter << " != " << endl
+ << access << esstate_member_end (e) << ";"
<< "}";
os << ret << " " << s << "::" << endl
@@ -761,7 +787,7 @@ namespace CXX
{
os << "return ";
type_pass_.dispatch (t);
- os << "*this->" << access << iter << "++;";
+ os << "*" << access << iter << "++;";
}
os << "}";
@@ -773,7 +799,7 @@ namespace CXX
os << "bool " << s << "::" << endl
<< espresent (e) << " ()"
<< "{"
- << "return this->" << access << epresent (e) << " ();"
+ << "return " << access << epresent (e) << " ();"
<< "}";
}
@@ -785,7 +811,7 @@ namespace CXX
{
os << "return ";
type_pass_.dispatch (t);
- os << "this->" << access << ename (e) << " ();";
+ os << access << ename (e) << " ();";
}
os << "}";
@@ -817,7 +843,7 @@ namespace CXX
os << "bool " << s << "::" << endl
<< espresent (a) << " ()"
<< "{"
- << "return this->" << access << epresent (a) << " ();"
+ << "return " << access << epresent (a) << " ();"
<< "}";
}
@@ -832,7 +858,7 @@ namespace CXX
{
os << "return ";
type_pass_.dispatch (t);
- os << "this->" << access << ename (a) << " ();";
+ os << access << ename (a) << " ();";
}
os << "}";
@@ -887,20 +913,51 @@ namespace CXX
return;
Boolean hb (c.inherits_p ());
+ Boolean rec (recursive (c));
Boolean restriction (restriction_p (c));
+ Boolean validation (!options.value<CLI::suppress_validation> () &&
+ !options.value<CLI::suppress_serializer_val> ());
+
+ String const& state (esstate (c));
+ String const& member (esstate_member (c));
+ String const& state_type (esstate_type (c));
+
+ String top_member;
+ if (rec)
+ {
+ top_member = L"static_cast< " + state_type + L"* > (this->" +
+ state + L".top ())->" + member;
+ }
+
os << "// " << name << endl
<< "//" << endl
<< endl;
// c-tor
//
- if (tiein && hb)
+ if (rec || (tiein && hb))
+ {
os << name << "::" << endl
- << name << " ()" << endl
- << ": " << esskel (c) << " (&base_impl_)"
- << "{"
+ << name << " ()" << endl;
+
+ String d ("\n: ");
+
+ if (tiein && hb)
+ {
+ os << d << esskel (c) << " (&base_impl_)";
+ d = ",\n ";
+ }
+
+ if (rec)
+ {
+ os << d << state << " (sizeof (" << state_type <<
+ " ), &" << esstate_first (c) << ")";
+ }
+
+ os << "{"
<< "}";
+ }
// pre
//
@@ -914,8 +971,44 @@ namespace CXX
{
SemanticGraph::Type& b (c.inherits ().base ());
- // Default serializer implementations for anyType and
- // anySimpleType return void.
+ // If we are recursive but our base is not, we need to call
+ // _post() and post() to end serialization.
+ //
+ if (rec && !recursive (b))
+ {
+ os << "if (!this->" << state << ".empty ())"
+ << "{";
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << esimpl (b) << "::";
+
+ os << "_post ();";
+
+ if (!exceptions || validation)
+ {
+ os << endl
+ << "if (this->_context ().error_type ())" << endl
+ << "return;"
+ << endl;
+ }
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << esimpl (b) << "::";
+
+ os << "post ();";
+
+ os << "}"
+ << "else" << endl
+ << "this->" << esstate_top (c) << " = true;"
+ << endl;
+ }
+
+ // Call base pre(). Default serializer implementations for
+ // anyType and anySimpleType return void.
//
if (!b.is_a<SemanticGraph::AnyType> () &&
!b.is_a<SemanticGraph::AnySimpleType> ())
@@ -934,8 +1027,19 @@ namespace CXX
if (!restriction)
{
- os << "this->" << esstate (c) << "." << esstate_member (c) <<
- " = &x;";
+ if (!rec)
+ os << "this->" << state << "." << member << " = &x;";
+ else
+ {
+ if (exceptions)
+ os << "this->" << state << ".push ();";
+ else
+ os << "if (this->" << state << ".push ())" << endl
+ << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"
+ << endl;
+
+ os << top_member << " = &x;";
+ }
contains_compositor (c, contains_compositor_init_);
}
@@ -949,6 +1053,85 @@ namespace CXX
names (c, names_attribute_callback_);
contains_compositor (c, contains_compositor_callback_);
}
+
+ if (rec)
+ {
+ // _post
+ //
+ if (hb && !recursive (c.inherits ().base ()))
+ {
+ // If we are recursive but our base is not, we only call
+ // base _post() if it is the first _post call.
+ //
+ os << "void " << name << "::" << endl
+ << "_post ()"
+ << "{"
+ << "if (this->" << esstate_top (c) << ")" << endl;
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << esimpl (c.inherits ().base ()) << "::";
+
+ os << "_post ();"
+ << "}";
+ }
+
+ // post
+ //
+ os << "void " << name << "::" << endl
+ << "post ()"
+ << "{"
+ << "this->" << state << ".pop ();";
+
+ if (hb)
+ {
+ SemanticGraph::Type& b (c.inherits ().base ());
+
+ // If we are recursive but our base is not, we only call
+ // base post() if it is the first post call.
+ //
+ if (!recursive (b))
+ {
+ os << "if (this->" << esstate_top (c) << ")"
+ << "{"
+ << "this->" << esstate_top (c) << " = false;";
+ }
+
+ if (tiein)
+ os << "this->base_impl_.";
+ else
+ os << esimpl (c.inherits ().base ()) << "::";
+
+ os << "post ();";
+
+ if (!recursive (b))
+ os << "}";
+ }
+
+ os << "}";
+
+ // reset
+ //
+ if (reset)
+ {
+ os << "void " << name << "::" << endl
+ << "_reset ()"
+ << "{";
+
+ if (mixin && hb)
+ os << esimpl (c);
+ else
+ os << esskel (c);
+
+ os << "::_reset ();";
+
+ os << "for (; !this->" << state << ".empty (); " <<
+ "this->" << state << ".pop ());";
+
+ os << "}";
+ }
+ }
}
private:
diff --git a/xsde/cxx/hybrid/tree-size-processor.cxx b/xsde/cxx/hybrid/tree-size-processor.cxx
index 43fa2fc..d492b24 100644
--- a/xsde/cxx/hybrid/tree-size-processor.cxx
+++ b/xsde/cxx/hybrid/tree-size-processor.cxx
@@ -10,6 +10,7 @@
#include <xsd-frontend/traversal.hxx>
#include <cult/containers/set.hxx>
+#include <cult/containers/vector.hxx>
namespace CXX
{
@@ -55,24 +56,18 @@ namespace CXX
virtual Void
traverse (SemanticGraph::Element& e)
{
+ // Check the type. We need to do it even if fixed_ is
+ // false to detect recursive types.
+ //
+ SemanticGraph::Type& t (e.type ());
+ type_traverser_.dispatch (t);
+
if (fixed_)
{
- // Check cardinality.
- //
if (e.max () != 1)
- {
fixed_ = false;
- return;
- }
-
- // Check the type.
- //
- SemanticGraph::Type& t (e.type ());
-
- if (!test (t))
- type_traverser_.dispatch (t);
-
- fixed_ = get (t);
+ else
+ fixed_ = get (t);
}
}
@@ -195,6 +190,8 @@ namespace CXX
virtual Void
traverse (SemanticGraph::Attribute& a)
{
+ // Simple types cannot be recursive.
+ //
if (fixed_)
{
SemanticGraph::Type& t (a.type ());
@@ -264,14 +261,22 @@ namespace CXX
{
SemanticGraph::Context& ctx (c.context ());
- if (test (c))
- return;
-
if (ctx.count ("recurse"))
+ {
set (c, false);
- else
+ ctx.set ("recursive", true);
+
+ // Mark all the types involved in the cycle as recursive.
+ //
+ for (Path::ReverseIterator i (path_.rbegin ()); *i != &c; ++i)
+ {
+ (*i)->context ().set ("recursive", true);
+ }
+ }
+ else if (!test (c))
{
ctx.set ("recurse", true);
+ path_.push_back (&c);
Boolean fixed = true;
@@ -328,6 +333,7 @@ namespace CXX
if (!test (c))
set (c, fixed);
+ path_.pop_back ();
ctx.remove ("recurse");
}
}
@@ -335,6 +341,9 @@ namespace CXX
private:
TypeSet& custom_data_;
Boolean stl;
+
+ typedef Containers::Vector<SemanticGraph::Complex*> Path;
+ Path path_;
};
struct FundType : Traversal::AnyType,