aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS6
-rw-r--r--libxsde/xsde/cxx/hashmap.hxx4
-rw-r--r--libxsde/xsde/cxx/stack.cxx42
-rw-r--r--libxsde/xsde/cxx/stack.hxx83
-rw-r--r--libxsde/xsde/cxx/stack.ixx86
-rw-r--r--libxsde/xsde/makefile2
-rw-r--r--tests/cxx/hybrid/makefile2
-rw-r--r--tests/cxx/hybrid/recursive/driver.cxx56
-rw-r--r--tests/cxx/hybrid/recursive/makefile98
-rw-r--r--tests/cxx/hybrid/recursive/output1
-rw-r--r--tests/cxx/hybrid/recursive/test.xml25
-rw-r--r--tests/cxx/hybrid/recursive/test.xsd115
-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
21 files changed, 1242 insertions, 188 deletions
diff --git a/NEWS b/NEWS
index 73398df..fc57707 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,12 @@ Version 3.1.0
Started Guide as well as examples in the examples/cxx/hybrid/binary/
directory.
+ * The generated parser and serializer implementations are now capable
+ of parsing/serializing recursive types. The XSD/e compiler detects
+ recursive types and generates stack-based implementations with
+ optimized non-recursive case (i.e., the first iteration still does
+ not result in any heap allocations for the state maintenance).
+
Version 3.0.0
* The new Embedded C++/Hybrid mapping provides a light-weight, tree-
diff --git a/libxsde/xsde/cxx/hashmap.hxx b/libxsde/xsde/cxx/hashmap.hxx
index 29c47e7..8554327 100644
--- a/libxsde/xsde/cxx/hashmap.hxx
+++ b/libxsde/xsde/cxx/hashmap.hxx
@@ -73,9 +73,7 @@ namespace xsde
private:
hashmap (hashmap&);
-
- hashmap&
- operator= (hashmap&);
+ hashmap& operator= (hashmap&);
public:
void
diff --git a/libxsde/xsde/cxx/stack.cxx b/libxsde/xsde/cxx/stack.cxx
new file mode 100644
index 0000000..a27acc8
--- /dev/null
+++ b/libxsde/xsde/cxx/stack.cxx
@@ -0,0 +1,42 @@
+// file : xsde/cxx/stack.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 <string.h> // memcpy
+
+#include <xsde/cxx/stack.hxx>
+
+namespace xsde
+{
+ namespace cxx
+ {
+#ifdef XSDE_EXCEPTIONS
+ void stack::
+#else
+ stack::error stack::
+#endif
+ grow ()
+ {
+ size_t c = capacity_ ? capacity_ * 2 : 8;
+ char* d = new char[c * el_size_];
+
+#ifndef XSDE_EXCEPTIONS
+ if (d == 0)
+ return error_no_memory;
+#endif
+
+ if (size_ > 1)
+ memcpy (d, data_, (size_ - 1) * el_size_);
+
+ delete[] data_;
+
+ data_ = d;
+ capacity_ = c;
+
+#ifndef XSDE_EXCEPTIONS
+ return error_none;
+#endif
+ }
+ }
+}
diff --git a/libxsde/xsde/cxx/stack.hxx b/libxsde/xsde/cxx/stack.hxx
new file mode 100644
index 0000000..f58b1c7
--- /dev/null
+++ b/libxsde/xsde/cxx/stack.hxx
@@ -0,0 +1,83 @@
+// file : xsde/cxx/stack.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef XSDE_CXX_STACK_HXX
+#define XSDE_CXX_STACK_HXX
+
+#include <stddef.h> // size_t
+
+#include <xsde/cxx/config.hxx>
+
+namespace xsde
+{
+ namespace cxx
+ {
+ // POD stack with pre-allocated first element. You may
+ // need to pad your elements to get the proper alignment.
+ //
+ struct stack
+ {
+#ifndef XSDE_EXCEPTIONS
+ enum error
+ {
+ error_none,
+ error_no_memory
+ };
+#endif
+
+ ~stack ();
+ stack (size_t element_size, void* first_element);
+
+ private:
+ stack (stack&);
+ stack& operator= (stack&);
+
+ public:
+ void
+ pop ();
+
+#ifdef XSDE_EXCEPTIONS
+ void
+#else
+ error
+#endif
+ push ();
+
+ void*
+ top ();
+
+ void
+ clear ();
+
+ bool
+ empty () const;
+
+ size_t
+ size () const;
+
+ size_t
+ element_size () const;
+
+ private:
+#ifdef XSDE_EXCEPTIONS
+ void
+#else
+ error
+#endif
+ grow ();
+
+ private:
+ size_t el_size_;
+ void* first_;
+ char* data_;
+ size_t size_;
+ size_t capacity_;
+ };
+ }
+}
+
+#include <xsde/cxx/stack.ixx>
+
+#endif // XSDE_CXX_STACK_HXX
diff --git a/libxsde/xsde/cxx/stack.ixx b/libxsde/xsde/cxx/stack.ixx
new file mode 100644
index 0000000..b0e81ff
--- /dev/null
+++ b/libxsde/xsde/cxx/stack.ixx
@@ -0,0 +1,86 @@
+// file : xsde/cxx/stack.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace xsde
+{
+ namespace cxx
+ {
+ inline stack::
+ ~stack ()
+ {
+ delete[] data_;
+ }
+
+ inline stack::
+ stack (size_t el_size, void* first_el)
+ : el_size_ (el_size),
+ first_ (first_el),
+ data_ (0),
+ size_ (0),
+ capacity_ (0)
+ {
+ }
+
+ inline void stack::
+ pop ()
+ {
+ --size_;
+ }
+
+#ifdef XSDE_EXCEPTIONS
+ inline void stack::
+#else
+ inline stack::error stack::
+#endif
+ push ()
+ {
+ if (size_ > capacity_)
+ {
+#ifdef XSDE_EXCEPTIONS
+ grow ();
+#else
+ if (error e = grow ())
+ return e;
+#endif
+ }
+
+ ++size_;
+
+#ifndef XSDE_EXCEPTIONS
+ return error_none;
+#endif
+ }
+
+ inline void* stack::
+ top ()
+ {
+ return size_ == 1 ? first_ : data_ + (size_ - 1) * el_size_;
+ }
+
+ inline void stack::
+ clear ()
+ {
+ size_ = 0;
+ }
+
+ inline bool stack::
+ empty () const
+ {
+ return size_ == 0;
+ }
+
+ inline size_t stack::
+ size () const
+ {
+ return size_;
+ }
+
+ inline size_t stack::
+ element_size () const
+ {
+ return el_size_;
+ }
+ }
+}
diff --git a/libxsde/xsde/makefile b/libxsde/xsde/makefile
index d42fabf..b9b3884 100644
--- a/libxsde/xsde/makefile
+++ b/libxsde/xsde/makefile
@@ -5,7 +5,7 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
-cxx_tun := cxx/string.cxx cxx/ro-string.cxx
+cxx_tun := cxx/string.cxx cxx/ro-string.cxx cxx/stack.cxx
ifeq ($(xsde_stl),n)
cxx_tun += cxx/strdupx.cxx
diff --git a/tests/cxx/hybrid/makefile b/tests/cxx/hybrid/makefile
index 84fed4c..2ea9a3d 100644
--- a/tests/cxx/hybrid/makefile
+++ b/tests/cxx/hybrid/makefile
@@ -8,7 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
tests := sequences
ifeq ($(xsde_iostream),y)
-tests += built-in list test-template union
+tests += built-in list recursive test-template union
ifeq ($(xsde_cdr),y)
tests += binary/cdr
diff --git a/tests/cxx/hybrid/recursive/driver.cxx b/tests/cxx/hybrid/recursive/driver.cxx
new file mode 100644
index 0000000..d3ce1c3
--- /dev/null
+++ b/tests/cxx/hybrid/recursive/driver.cxx
@@ -0,0 +1,56 @@
+// file : tests/cxx/hybrid/recursive/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+// Test recursive parsing and serialization.
+//
+
+#include <iostream>
+
+#include "test.hxx"
+#include "test-pimpl.hxx"
+#include "test-simpl.hxx"
+
+using namespace std;
+using namespace test;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " test.xml" << endl;
+ return 1;
+ }
+
+ // Parse.
+ //
+ root_paggr root_p;
+
+ xml_schema::document_pimpl doc_p (
+ root_p.root_parser (),
+ root_p.root_namespace (),
+ root_p.root_name ());
+
+ root_p.pre ();
+ doc_p.parse (argv[1]);
+ type* r = root_p.post ();
+
+ // Serialize.
+ //
+ root_saggr root_s;
+
+ xml_schema::document_simpl doc_s (
+ root_s.root_serializer (),
+ root_s.root_namespace (),
+ root_s.root_name ());
+
+ doc_s.add_prefix ("t", "test");
+
+ root_s.pre (*r);
+ doc_s.serialize (cout);
+ root_s.post ();
+
+ delete r;
+}
diff --git a/tests/cxx/hybrid/recursive/makefile b/tests/cxx/hybrid/recursive/makefile
new file mode 100644
index 0000000..7c65294
--- /dev/null
+++ b/tests/cxx/hybrid/recursive/makefile
@@ -0,0 +1,98 @@
+# file : tests/cxx/hybrid/recursive/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := test.xsd
+cxx := driver.cxx
+
+obj := $(addprefix $(out_base)/,\
+$(cxx:.cxx=.o) \
+$(xsd:.xsd=.o) \
+$(xsd:.xsd=-pskel.o) \
+$(xsd:.xsd=-pimpl.o) \
+$(xsd:.xsd=-sskel.o) \
+$(xsd:.xsd=-simpl.o))
+
+dep := $(obj:.o=.o.d)
+
+xsde.l := $(out_root)/libxsde/xsde/xsde.l
+xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+
+# Build.
+#
+$(driver): $(obj) $(xsde.l)
+
+$(obj) $(dep): $(xsde.l.cpp-options)
+
+genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \
+ $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \
+ $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \
+ $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \
+ $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx)
+
+gen := $(addprefix $(out_base)/,$(genf))
+
+$(gen): $(out_root)/xsde/xsde
+$(gen): xsde := $(out_root)/xsde/xsde
+$(gen): xsde_options += --generate-parser --generate-serializer \
+--generate-aggregate
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+.PHONY: $(out_base)/
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+.PHONY: $(test)
+
+$(test): driver := $(driver)
+$(test): $(driver) $(src_base)/test.xml $(src_base)/output
+ $(call message,test $$1,$$1 $(src_base)/test.xml | diff -ubB $(src_base)/output -,$(driver))
+
+# Clean.
+#
+.PHONY: $(clean)
+
+$(clean): $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(obj)) \
+ $(addsuffix .cxx.clean,$(dep)) \
+ $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(gen): | $(out_base)/.gitignore
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make)
+
+
+# Dependencies.
+#
+$(call import,$(src_root)/xsde/makefile)
+$(call import,$(src_root)/libxsde/xsde/makefile)
diff --git a/tests/cxx/hybrid/recursive/output b/tests/cxx/hybrid/recursive/output
new file mode 100644
index 0000000..6b89789
--- /dev/null
+++ b/tests/cxx/hybrid/recursive/output
@@ -0,0 +1 @@
+<t:root xmlns:t="test"><test1><a>123</a></test1><test1><b><a>123</a></b></test1><test1><b><b><a>123</a></b></b></test1><test2></test2><test2><b><d><x>123</x></d></b></test2><test2><b><c></c><d><x>123</x></d></b></test2><test2><b><c><a></a></c><d><x>123</x></d></b></test2><test2><b><c><a><b><c><a></a></c><d><x>123</x></d></b></a></c><d><x>123</x></d></b></test2><test3><a>123</a><b>abc</b><c>a1</c></test3><test3><a>123</a><b>abc</b><c>a1</c><d><a>456</a><b>def</b><c>b2</c></d></test3><test3><a>123</a><b>abc</b><c>a1</c><d><a>456</a><b>def</b><c>b2</c><d><a>789</a><b>ghi</b><c>c3</c></d></d></test3><test4><a>123</a><c>abc</c></test4><test4><b><a>123</a></b><c>abc</c></test4><test4><b><b><a>123</a></b></b><c>abc</c></test4><test5><a>123</a><c>abc</c></test5><test5><b><a>123</a><c>abc</c></b><c>def</c></test5><test5><b><b><a>123</a><c>abc</c></b><c>def</c></b><c>ghi</c></test5></t:root> \ No newline at end of file
diff --git a/tests/cxx/hybrid/recursive/test.xml b/tests/cxx/hybrid/recursive/test.xml
new file mode 100644
index 0000000..4db2950
--- /dev/null
+++ b/tests/cxx/hybrid/recursive/test.xml
@@ -0,0 +1,25 @@
+<t:root xmlns:t="test">
+
+ <test1><a>123</a></test1>
+ <test1><b><a>123</a></b></test1>
+ <test1><b><b><a>123</a></b></b></test1>
+
+ <test2></test2>
+ <test2><b><d><x>123</x></d></b></test2>
+ <test2><b><c></c><d><x>123</x></d></b></test2>
+ <test2><b><c><a></a></c><d><x>123</x></d></b></test2>
+ <test2><b><c><a><b><c><a></a></c><d><x>123</x></d></b></a></c><d><x>123</x></d></b></test2>
+
+ <test3><a>123</a><b>abc</b><c>a1</c></test3>
+ <test3><a>123</a><b>abc</b><c>a1</c><d><a>456</a><b>def</b><c>b2</c></d></test3>
+ <test3><a>123</a><b>abc</b><c>a1</c><d><a>456</a><b>def</b><c>b2</c><d><a>789</a><b>ghi</b><c>c3</c></d></d></test3>
+
+ <test4><a>123</a><c>abc</c></test4>
+ <test4><b><a>123</a></b><c>abc</c></test4>
+ <test4><b><b><a>123</a></b></b><c>abc</c></test4>
+
+ <test5><a>123</a><c>abc</c></test5>
+ <test5><b><a>123</a><c>abc</c></b><c>def</c></test5>
+ <test5><b><b><a>123</a><c>abc</c></b><c>def</c></b><c>ghi</c></test5>
+
+</t:root>
diff --git a/tests/cxx/hybrid/recursive/test.xsd b/tests/cxx/hybrid/recursive/test.xsd
new file mode 100644
index 0000000..578bf8f
--- /dev/null
+++ b/tests/cxx/hybrid/recursive/test.xsd
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test">
+
+ <element name="root" type="t:type"/>
+
+ <complexType name="type">
+ <sequence>
+ <element name="test1" type="t:test1" maxOccurs="unbounded"/>
+ <element name="test2" type="t:test2a" maxOccurs="unbounded"/>
+ <element name="test3" type="t:test3b" maxOccurs="unbounded"/>
+ <element name="test4" type="t:test4b" maxOccurs="unbounded"/>
+ <element name="test5" type="t:test5b" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+
+ <!-- test 1: single type recursion -->
+
+ <complexType name="test1">
+ <choice>
+ <element name="a" type="int"/>
+ <element name="b" type="t:test1"/>
+ </choice>
+ </complexType>
+
+
+ <!-- test 2: muti-type recursion -->
+
+ <complexType name="test2a">
+ <sequence>
+ <element name="b" type="t:test2b" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="test2b">
+ <sequence>
+ <element name="c" type="t:test2c" minOccurs="0" maxOccurs="unbounded"/>
+ <element name="d" type="t:test2d"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="test2c">
+ <sequence>
+ <element name="a" type="t:test2a" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="test2d">
+ <sequence>
+ <element name="x" type="int"/>
+ </sequence>
+ </complexType>
+
+
+ <!-- test 3: single type recursion with a non-recursive base -->
+
+ <complexType name="test3a">
+ <sequence>
+ <element name="a" type="int"/>
+ <element name="b" type="string"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="test3b">
+ <complexContent>
+ <extension base="t:test3a">
+ <sequence>
+ <element name="c" type="string"/>
+ <element name="d" type="t:test3b" minOccurs="0"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+
+ <!-- test 4: single type recursion with a non-recursive derived -->
+
+ <complexType name="test4a">
+ <choice>
+ <element name="a" type="int"/>
+ <element name="b" type="t:test4a"/>
+ </choice>
+ </complexType>
+
+ <complexType name="test4b">
+ <complexContent>
+ <extension base="t:test4a">
+ <sequence>
+ <element name="c" type="string"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+
+ <!-- test 5: recursion via derivation -->
+
+ <complexType name="test5a">
+ <choice>
+ <element name="a" type="int"/>
+ <element name="b" type="t:test5b"/>
+ </choice>
+ </complexType>
+
+ <complexType name="test5b">
+ <complexContent>
+ <extension base="t:test5a">
+ <sequence>
+ <element name="c" type="string"/>
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>
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,