diff options
42 files changed, 2842 insertions, 240 deletions
@@ -1,15 +1,20 @@ Version 3.2.0 - * When built with Xerces-C++ 3-series, enable handling of multiple - imports for the same namespace. Before, all subsequent imports for - a namespace were ignored which caused error in some schemas. + * When built with Xerces-C++ 3-series, enable handling of multiple imports + for the same namespace. Before, all subsequent imports for a namespace + were ignored which caused error in some schemas. C++/Hybrid + * String-based types that use XML Schema restriction by enumeration are + now mapped to C++ classes with semantics similar to C++ enum. You can + suppress this new mapping and instead get the old behavior (plain + inheritance) by specifying the --suppress-enum compiler option. + * New configuration parameter, XSDE_STL_ITERATOR, makes iterators - provided by the mapping conform to the STL requirements. This - feature requires working <iterator> header and allows you to use the - standard algorithms such as find_if, etc. + provided by the mapping conform to the STL requirements. This feature + requires working <iterator> header and allows you to use the standard + algorithms such as find_if, etc. * When the code is generated with the --generate-polymorphic or --runtime-polymorphic option, the resulting parser and serializer diff --git a/dist/tests/cxx/hybrid/makefile b/dist/tests/cxx/hybrid/makefile index 8733e6b..3cd2d7d 100644 --- a/dist/tests/cxx/hybrid/makefile +++ b/dist/tests/cxx/hybrid/makefile @@ -5,7 +5,7 @@ include $(root)/build/config.make dirs := sequences ifeq ($(XSDE_POLYMORPHIC),y) -dirs += polymorphism/multischema +dirs += polymorphism/enumeration polymorphism/multischema endif ifeq ($(XSDE_STL),y) @@ -15,7 +15,7 @@ endif endif ifeq ($(XSDE_IOSTREAM),y) -dirs += built-in default list test-template union +dirs += built-in default enumeration list test-template union ifeq ($(XSDE_CDR),y) dirs += binary/cdr diff --git a/dist/tests/cxx/hybrid/nmakefile b/dist/tests/cxx/hybrid/nmakefile index 0f42e79..9052637 100644 --- a/dist/tests/cxx/hybrid/nmakefile +++ b/dist/tests/cxx/hybrid/nmakefile @@ -5,7 +5,7 @@ root = ..\..\.. dirs = sequences !if "$(XSDE_POLYMORPHIC)" == "y" -dirs = $(dirs) polymorphism\multischema +dirs = $(dirs) polymorphism\enumeration polymorphism\multischema !endif !if "$(XSDE_STL)" == "y" @@ -15,7 +15,7 @@ dirs = $(dirs) iterator !endif !if "$(XSDE_IOSTREAM)" == "y" -dirs = $(dirs) built-in default list test-template union +dirs = $(dirs) built-in default enumeration list test-template union !if "$(XSDE_CDR)" == "y" dirs = $(dirs) binary/cdr diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml index 6856e8c..5a4b33a 100644 --- a/documentation/cxx/hybrid/guide/index.xhtml +++ b/documentation/cxx/hybrid/guide/index.xhtml @@ -241,13 +241,14 @@ <table class="toc"> <tr><th>4.1</th><td><a href="#4.1">Namespaces</a></td></tr> <tr><th>4.2</th><td><a href="#4.2">Memory Management</a></td></tr> - <tr><th>4.3</th><td><a href="#4.3">Attributes and Elements</a></td></tr> - <tr><th>4.4</th><td><a href="#4.4">Compositors</a></td></tr> - <tr><th>4.5</th><td><a href="#4.5">Accessing the Object Model</a></td></tr> - <tr><th>4.6</th><td><a href="#4.6">Modifying the Object Model</a></td></tr> - <tr><th>4.7</th><td><a href="#4.7">Creating the Object Model from Scratch</a></td></tr> - <tr><th>4.8</th><td><a href="#4.8">Customizing the Object Model</a></td></tr> - <tr><th>4.9</th><td><a href="#4.9">Polymorphic Object Models</a></td></tr> + <tr><th>4.3</th><td><a href="#4.3">Enumerations</a></td></tr> + <tr><th>4.4</th><td><a href="#4.4">Attributes and Elements</a></td></tr> + <tr><th>4.5</th><td><a href="#4.5">Compositors</a></td></tr> + <tr><th>4.6</th><td><a href="#4.6">Accessing the Object Model</a></td></tr> + <tr><th>4.7</th><td><a href="#4.7">Modifying the Object Model</a></td></tr> + <tr><th>4.8</th><td><a href="#4.8">Creating the Object Model from Scratch</a></td></tr> + <tr><th>4.9</th><td><a href="#4.9">Customizing the Object Model</a></td></tr> + <tr><th>4.10</th><td><a href="#4.10">Polymorphic Object Models</a></td></tr> </table> </td> </tr> @@ -1542,7 +1543,7 @@ $ xsde cxx-hybrid --generate-parser --generate-serializer \ </pre> <p>For information on how to use object models with polymorphic types, - refer to <a href="#4.9">Section 4.9, "Polymorphic Object Models"</a>.</p> + refer to <a href="#4.10">Section 4.10, "Polymorphic Object Models"</a>.</p> <!-- Chapater 4 --> @@ -1626,12 +1627,30 @@ $ xsde cxx-hybrid --generate-parser --generate-serializer \ <pre class="c++"> // gender (fixed-length) // -class gender: public std::string +class gender { public: + enum value_type + { + male, + female + }; + gender (); + gender (value_type); gender (const gender&); gender& operator= (const gender&); + + void + value (value_type); + + operator value_type () const; + + const char* + string () const; + +private: + ... }; // person (fixed-length) @@ -1807,7 +1826,7 @@ private: <li>it is recursive (that is, one of its elements contains a reference, directly or indirectly, to the type itself)</li> - <li>it is polymorphic (see <a href="#4.9">Section 4.9, "Polymorphic + <li>it is polymorphic (see <a href="#4.10">Section 4.10, "Polymorphic Object Models"</a> for details)</li> </ol> @@ -1827,10 +1846,9 @@ private: variable-length because it contains a sequence of <code>person</code> elements (<code>maxOccurs="unbounded"</code>). If we recompile the <code>people.xsd</code> schema with the <code>--no-stl</code> - option, the first two types will also become variable-length - since <code>gender</code> inherits from and <code>person</code> - contains elements of the <code>string</code> built-in type. And - when STL is disabled, <code>string</code> is variable-length.</p> + option, the <code>person</code> type will also become variable-length + since it contains elements of the <code>string</code> built-in type. + And when STL is disabled, <code>string</code> is variable-length.</p> <p>The object model uses different methods for storing and passing around fixed-length and variable-length types. Instances of @@ -1932,7 +1950,81 @@ s->permanent (per) // Assumes ownership or per. s->contract (con) // Assumes ownership or con. </pre> - <h2><a name="4.3">4.3 Attributes and Elements</a></h2> + <h2><a name="4.3">4.3 Enumerations</a></h2> + + <p>By default, string-based types that use XML Schema restriction by + enumeration are mapped to C++ classes with semantics similar to + C++ enum (you can suppress this mapping and instead get the plain + inheritance by specifying the <code>--suppress-enum</code> compiler + option). The following code fragment again shows the C++ class that + was generated for the <code>gender</code> XML Schema type presented + at the beginning of this chapter:</p> + + <pre class="c++"> +// gender (fixed-length) +// +class gender +{ +public: + enum value_type + { + male, + female + }; + + gender (); + gender (value_type); + gender (const gender&); + gender& operator= (const gender&); + + void + value (value_type); + + operator value_type () const; + + const char* + string () const; + +private: + value_type v_; +}; +</pre> + + <p>The <code>gender</code> class defines the underlying C++ enum type + (<code>value_type</code>) with enumerators corresponding to the + <code>enumeration</code> elements in XML Schema. The class also + defines the default constructor, copy constructor, constructor + with the underlying enum type as its argument, and the assignment + operator. The <code>gender</code> class also supports the implicit + conversion to the underlying enum type and the explicit conversion + to string via the <code>string()</code> function. Finally, it + provides the <code>value()</code> modifier function which allows you + to set the underlying enum value explicitly. Note also that such an + enumeration class is always fixed-length since it only contains the + C++ enum value. The following example shows how we can use the + <code>gender</code> class:</p> + + <pre class="c++"> +gender g = gender::male; +g = gender::female; +g.value (gender::female); // Same as above. + +cerr << g.string () << endl; + +if (g != gender::male) + ... + +switch (g) +{ +case gender::male: + ... +case gender::female: + ... +} + </pre> + + + <h2><a name="4.4">4.4 Attributes and Elements</a></h2> <p>As we have seen before, XSD/e generates a different set of member functions for elements with different cardinalities. @@ -1945,7 +2037,7 @@ s->contract (con) // Assumes ownership or con. example, the <code>first-name</code>, <code>last-name</code>, <code>gender</code>, and <code>age</code> elements as well as the <code>id</code> attribute belong to this cardinality class. - The following code fragment shows again the accessor and modifier + The following code fragment again shows the accessor and modifier functions that are generated for the <code>first-name</code> element in the <code>person</code> class:</p> @@ -1975,7 +2067,7 @@ class person <p>The <em>optional</em> cardinality class covers all elements that can occur zero or one time as well as optional attributes. In our example, the <code>middle-name</code> element belongs to this - cardinality class. The following code fragment shows again the + cardinality class. The following code fragment again shows the accessor and modifier functions that are generated for this element in the <code>person</code> class:</p> @@ -2664,13 +2756,13 @@ namespace xml_schema } </pre> - <h2><a name="4.4">4.4 Compositors</a></h2> + <h2><a name="4.5">4.5 Compositors</a></h2> <p>The XML Schema language provides three compositor constructs that are used to group elements: <code>all</code>, <code>sequence</code>, and <code>choice</code>. If a compositor has an <em>optional</em> - or <em>sequence</em> cardinality class (see <a href="#4.3">Section - 4.3, "Attributes and Elements"</a>) or if a compositor is + or <em>sequence</em> cardinality class (see <a href="#4.4">Section + 4.4, "Attributes and Elements"</a>) or if a compositor is inside <code>choice</code>, then the C++/Hybrid mapping generates a nested class for such a compositor as well as a set of accessor and modifier functions similar to the ones defined for elements @@ -3082,7 +3174,7 @@ private: }; </pre> - <h2><a name="4.5">4.5 Accessing the Object Model</a></h2> + <h2><a name="4.6">4.6 Accessing the Object Model</a></h2> <p>In this section we will examine how to get to the information stored in the object model for the person records vocabulary @@ -3131,7 +3223,7 @@ main () // Print gender, age, and id which are all required. // - cout << "gender: " << p.gender () << endl + cout << "gender: " << p.gender ().string () << endl << "age: " << p.age () << endl << "id: " << p.id () << endl << endl; @@ -3174,7 +3266,7 @@ id: 2 </pre> - <h2><a name="4.6">4.6 Modifying the Object Model</a></h2> + <h2><a name="4.7">4.7 Modifying the Object Model</a></h2> <p>In this section we will examine how to modify the information stored in the object model for our person records vocabulary. @@ -3284,7 +3376,7 @@ main () </people> </pre> - <h2><a name="4.7">4.7 Creating the Object Model from Scratch</a></h2> + <h2><a name="4.8">4.8 Creating the Object Model from Scratch</a></h2> <p>In this section we will examine how to create a new object model for our person records vocabulary. The following application @@ -3311,13 +3403,10 @@ main () person p; p.first_name ("John"); p.last_name ("Doe"); + p.gender (gender::male); p.age (32); p.id (1); - gender g; - g.assign ("male"); - p.gender (g); - ps.push_back (p); } @@ -3328,13 +3417,10 @@ main () p.first_name ("Jane"); p.middle_name ("Mary"); p.last_name ("Doe"); + p.gender (gender::female); p.age (28); p.id (2); - gender g; - g.assign ("male"); - p.gender (g); - ps.push_back (p); } @@ -3385,7 +3471,7 @@ main () </people> </pre> - <h2><a name="4.8">4.8 Customizing the Object Model</a></h2> + <h2><a name="4.9">4.9 Customizing the Object Model</a></h2> <p>Sometimes it is desirable to add extra, application-specific data or functionality to some object model classes or @@ -3809,7 +3895,7 @@ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) </pre> - <h2><a name="4.9">4.9 Polymorphic Object Models</a></h2> + <h2><a name="4.10">4.10 Polymorphic Object Models</a></h2> <p>When generating polymorphism-aware code (see <a href="#3.7">Section 3.7, "Support for Polymorphism"</a>), some objects @@ -4673,7 +4759,7 @@ namespace xml_schema <p>The <code>NMTOKENS</code> and <code>IDREFS</code> built-in XML Schema types are mapped to the string sequence type which - is discussed in <a href="#4.3">Section 4.3, "Attributes and + is discussed in <a href="#4.4">Section 4.4, "Attributes and Elements"</a>.</p> <h2><a name="5.3">5.3 Mapping for <code>base64Binary</code> and <code>hexBinary</code></a></h2> @@ -5783,7 +5869,7 @@ main (int argc, char* argv[]) { cerr << "first: " << i->first_name () << endl << "last: " << i->last_name () << endl - << "gender: " << i->gender () << endl + << "gender: " << i->gender ().string () << endl << "age: " << i->age () << endl << endl; } @@ -5795,9 +5881,7 @@ main (int argc, char* argv[]) // Initialize the filter. // - gender g; - g.assign ("female"); - root_s.gender_filter (g); + root_s.gender_filter (gender::female); xml_schema::document_simpl doc_s (root_s, people_s.root_name ()); diff --git a/documentation/xsde.1 b/documentation/xsde.1 index 5d4d5cf..90637e0 100644 --- a/documentation/xsde.1 +++ b/documentation/xsde.1 @@ -948,6 +948,9 @@ Suppress the generation of validation code in serializer. Omit attributes with default and fixed values from serialized XML documents. +.IP "\fB\--suppress-enum\fR" +Suppress the generation of the XML Schema enumeration to C++ enum mapping. + .IP "\fB\--generate-detach\fR" Generate detach functions for elements and attributes of variable-length types. These functions, for example, allow you to move sub-trees in the diff --git a/documentation/xsde.xhtml b/documentation/xsde.xhtml index c4c8995..11a90f5 100644 --- a/documentation/xsde.xhtml +++ b/documentation/xsde.xhtml @@ -820,6 +820,10 @@ <dd>Omit attributes with default and fixed values from serialized XML documents.</dd> + <dt><code><b>--suppress-enum</b></code></dt> + <dd>Suppress the generation of the XML Schema enumeration to C++ + enum mapping.</dd> + <dt><code><b>--generate-detach</b></code></dt> <dd>Generate detach functions for elements and attributes of variable-length types. These functions, for example, allow diff --git a/examples/cxx/hybrid/filter/driver.cxx b/examples/cxx/hybrid/filter/driver.cxx index 67efb60..46017ab 100644 --- a/examples/cxx/hybrid/filter/driver.cxx +++ b/examples/cxx/hybrid/filter/driver.cxx @@ -54,7 +54,7 @@ main (int argc, char* argv[]) { cerr << "first: " << i->first_name () << endl << "last: " << i->last_name () << endl - << "gender: " << i->gender () << endl + << "gender: " << i->gender ().string () << endl << "age: " << i->age () << endl << endl; } @@ -66,9 +66,7 @@ main (int argc, char* argv[]) // Initialize the filter. // - gender g; - g.assign ("female"); - root_s.gender_filter (g); + root_s.gender_filter (gender::female); xml_schema::document_simpl doc_s (root_s, people_s.root_name ()); diff --git a/examples/cxx/hybrid/library/driver.cxx b/examples/cxx/hybrid/library/driver.cxx index 5aa406e..41e3e1b 100644 --- a/examples/cxx/hybrid/library/driver.cxx +++ b/examples/cxx/hybrid/library/driver.cxx @@ -56,7 +56,7 @@ main (int argc, char* argv[]) { cerr << "ISBN : " << i->isbn () << endl << "Title : " << i->title () << endl - << "Genre : " << i->genre () << endl; + << "Genre : " << i->genre ().string () << endl; for (book::author_const_iterator j = i->author ().begin (); j != i->author ().end (); @@ -108,9 +108,7 @@ main (int argc, char* argv[]) t.assign ("Dead Souls"); b->title (t); - genre g; - g.assign ("philosophy"); - b->genre (g); + b->genre (genre::philosophy); author a; a.name ("Nikolai Gogol"); diff --git a/examples/cxx/hybrid/minimal/driver.cxx b/examples/cxx/hybrid/minimal/driver.cxx index 6573237..cb13edf 100644 --- a/examples/cxx/hybrid/minimal/driver.cxx +++ b/examples/cxx/hybrid/minimal/driver.cxx @@ -160,7 +160,7 @@ main (int argc, char* argv[]) printf ("first: %s\n" "last: %s\n" "gender: %s\n" "age: %hu\n\n", i->first_name (), i->last_name (), - i->gender ().base_value (), + i->gender ().string (), i->age ()); } @@ -181,10 +181,7 @@ main (int argc, char* argv[]) p->first_name (strdupx ("Joe")); p->last_name (strdupx ("Dirt")); p->age (36); - - gender* g = new gender; - g->base_value (strdupx ("male")); - p->gender (g); + p->gender (gender::male); ps.insert (ps.begin (), p); } diff --git a/tests/cxx/hybrid/enumeration/driver.cxx b/tests/cxx/hybrid/enumeration/driver.cxx new file mode 100644 index 0000000..ffbbf0b --- /dev/null +++ b/tests/cxx/hybrid/enumeration/driver.cxx @@ -0,0 +1,97 @@ +// file : tests/cxx/hybrid/enumeration/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 XML Schema enumeration to C++ enum mapping. +// + +#include <cassert> +#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 (); + + // Test the mapping. + // + { + simple x; + x = simple::a; + assert (x == simple::a); + + x.value (simple::b); + assert (x == simple::b); + + simple y (simple::c); + + switch (y) + { + case simple::c: + { + break; + } + default: + assert (false); + } + } + + { + final x (final::c); + assert (x == final::c); + + simple s = x; + assert (s == simple::c); + } + + { + complex c; + c.value (complex::a); + assert (c == complex::a); + + simple s = c; + assert (s == simple::a); + } + + // 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/enumeration/makefile b/tests/cxx/hybrid/enumeration/makefile new file mode 100644 index 0000000..a7a6b3c --- /dev/null +++ b/tests/cxx/hybrid/enumeration/makefile @@ -0,0 +1,109 @@ +# file : tests/cxx/hybrid/enumeration/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 +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +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) $(dist) $(dist-win): xsde_options += --generate-parser \ +--generate-serializer --generate-aggregate --custom-data simple-cd \ +--custom-data fbvd + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Test. +# +$(test): driver := $(driver) +$(test): $(driver) $(src_base)/test-000.xml $(src_base)/test-000.std + $(call message,test $$1,$$1 $(src_base)/test-000.xml | diff -u $(src_base)/test-000.std -,$(driver)) + + +# Dist. +# +$(dist) $(dist-win): opt := -src $(src_base) -cmd cxx-hybrid -xsd "$(xsd)" \ +-cxx "$(cxx)" -gen "$(genf)" -opt "$(xsde_options)" -out $(dist_prefix) + +$(dist): + $(call message,install $(src_base),$(scf_root)/dist $(opt)) + +$(dist-win): + $(call message,install $(src_base),$(scf_root)/dist -win $(opt)) + + +# 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/enumeration/test-000.std b/tests/cxx/hybrid/enumeration/test-000.std new file mode 100644 index 0000000..8bb771a --- /dev/null +++ b/tests/cxx/hybrid/enumeration/test-000.std @@ -0,0 +1 @@ +<t:root xmlns:t="test" x="a" y="c" z="b"><simple>a</simple><simple>b</simple><derived>a</derived><derived>b</derived><final>a</final><final>c</final><complex x="a">a</complex><complex x="c">c</complex><simple-cd>a</simple-cd><simple-cd>b</simple-cd><fbvd>a</fbvd><fbvd>c</fbvd><vbvd>a</vbvd><vbvd>c</vbvd></t:root>
\ No newline at end of file diff --git a/tests/cxx/hybrid/enumeration/test-000.xml b/tests/cxx/hybrid/enumeration/test-000.xml new file mode 100644 index 0000000..6db0a36 --- /dev/null +++ b/tests/cxx/hybrid/enumeration/test-000.xml @@ -0,0 +1,24 @@ +<t:root xmlns:t="test"> + + <simple>a</simple> + <simple>b</simple> + + <derived>a</derived> + <derived>b</derived> + + <final>a</final> + <final>c</final> + + <complex x="a">a</complex> + <complex x="c">c</complex> + + <simple-cd>a</simple-cd> + <simple-cd>b</simple-cd> + + <fbvd>a</fbvd> + <fbvd>c</fbvd> + + <vbvd>a</vbvd> + <vbvd>c</vbvd> + +</t:root> diff --git a/tests/cxx/hybrid/enumeration/test.xsd b/tests/cxx/hybrid/enumeration/test.xsd new file mode 100644 index 0000000..782c707 --- /dev/null +++ b/tests/cxx/hybrid/enumeration/test.xsd @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <simpleType name="base"> + <restriction base="string"/> + </simpleType> + + <simpleType name="simple"> + <restriction base="string"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <simpleType name="derived"> + <restriction base="t:base"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <simpleType name="interm"> + <restriction base="t:simple"/> + </simpleType> + + <simpleType name="final"> + <restriction base="t:interm"> + <enumeration value="a"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <complexType name="complex"> + <simpleContent> + <extension base="t:final"> + <attribute name="x" type="string"/> + </extension> + </simpleContent> + </complexType> + + <!-- Variable-length (custom data) --> + + <simpleType name="simple-cd"> + <restriction base="string"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <!-- fixed base, variable derived --> + <simpleType name="fbvd"> + <restriction base="t:simple"> + <enumeration value="a"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <!-- variable base, variable derived --> + <simpleType name="vbvd"> + <restriction base="t:simple-cd"> + <enumeration value="a"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + + <complexType name="type"> + <sequence> + <element name="simple" type="t:simple" maxOccurs="unbounded"/> + <element name="derived" type="t:derived" maxOccurs="unbounded"/> + <element name="final" type="t:final" maxOccurs="unbounded"/> + <element name="complex" type="t:complex" maxOccurs="unbounded"/> + + <element name="simple-cd" type="t:simple-cd" maxOccurs="unbounded"/> + <element name="fbvd" type="t:fbvd" maxOccurs="unbounded"/> + <element name="vbvd" type="t:vbvd" maxOccurs="unbounded"/> + </sequence> + <attribute name="x" type="t:simple" default="a"/> + <attribute name="y" type="t:final" default="c"/> + <attribute name="z" type="t:simple-cd" default="b"/> + </complexType> + + <element name="root" type="t:type"/> + +</schema> diff --git a/tests/cxx/hybrid/polymorphism/enumeration/driver.cxx b/tests/cxx/hybrid/polymorphism/enumeration/driver.cxx new file mode 100644 index 0000000..b2c9429 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/enumeration/driver.cxx @@ -0,0 +1,67 @@ +// file : tests/cxx/hybrid/polymorphism/enumeration/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 XML Schema enumeration to C++ enum mapping. +// + +#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 (), + true); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + // Test the mapping. + // + simple s (simple::a); + s.value (simple::b); + + complex c; + c.value (complex::a); + + // Serialize. + // + root_saggr root_s; + + xml_schema::document_simpl doc_s ( + root_s.root_serializer (), + root_s.root_namespace (), + root_s.root_name (), + true); + + doc_s.add_prefix ("t", "test"); + doc_s.add_prefix ("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + root_s.pre (*r); + doc_s.serialize (cout); + root_s.post (); + + delete r; +} diff --git a/tests/cxx/hybrid/polymorphism/enumeration/makefile b/tests/cxx/hybrid/polymorphism/enumeration/makefile new file mode 100644 index 0000000..fbd4337 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/enumeration/makefile @@ -0,0 +1,110 @@ +# file : tests/cxx/hybrid/polymorphism/enumeration/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 +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +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) $(dist) $(dist-win): xsde_options += --generate-parser \ +--generate-serializer --generate-aggregate --custom-data simple-cd \ +--custom-data fbvd --generate-polymorphic --generate-typeinfo \ +--polymorphic-type base --polymorphic-type simple + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Test. +# +$(test): driver := $(driver) +$(test): $(driver) $(src_base)/test-000.xml $(src_base)/test-000.std + $(call message,test $$1,$$1 $(src_base)/test-000.xml | diff -u $(src_base)/test-000.std -,$(driver)) + + +# Dist. +# +$(dist) $(dist-win): opt := -src $(src_base) -cmd cxx-hybrid -xsd "$(xsd)" \ +-cxx "$(cxx)" -gen "$(genf)" -opt "$(xsde_options)" -out $(dist_prefix) + +$(dist): + $(call message,install $(src_base),$(scf_root)/dist $(opt)) + +$(dist-win): + $(call message,install $(src_base),$(scf_root)/dist -win $(opt)) + + +# 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/polymorphism/enumeration/test-000.std b/tests/cxx/hybrid/polymorphism/enumeration/test-000.std new file mode 100644 index 0000000..ecb1b29 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/enumeration/test-000.std @@ -0,0 +1 @@ +<t:root xmlns:t="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><base xsi:type="t:derived">a</base><base xsi:type="t:derived">b</base><simple>a</simple><simple>b</simple><simple xsi:type="t:interm">b</simple><simple xsi:type="t:final">c</simple><simple x="c" xsi:type="t:complex">c</simple></t:root>
\ No newline at end of file diff --git a/tests/cxx/hybrid/polymorphism/enumeration/test-000.xml b/tests/cxx/hybrid/polymorphism/enumeration/test-000.xml new file mode 100644 index 0000000..b43342e --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/enumeration/test-000.xml @@ -0,0 +1,13 @@ +<t:root xmlns:t="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <base xsi:type="t:derived">a</base> + <base xsi:type="t:derived">b</base> + + <simple>a</simple> + <simple>b</simple> + + <simple xsi:type="t:interm">b</simple> + <simple xsi:type="t:final">c</simple> + <simple xsi:type="t:complex" x="c">c</simple> + +</t:root> diff --git a/tests/cxx/hybrid/polymorphism/enumeration/test.xsd b/tests/cxx/hybrid/polymorphism/enumeration/test.xsd new file mode 100644 index 0000000..235990c --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/enumeration/test.xsd @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <!-- base is polymorphic --> + + <simpleType name="base"> + <restriction base="string"/> + </simpleType> + + <simpleType name="derived"> + <restriction base="t:base"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <!-- enum is polymorphic --> + + <simpleType name="simple"> + <restriction base="string"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <!-- base enum is polymorphic --> + + <simpleType name="interm"> + <restriction base="t:simple"/> + </simpleType> + + <simpleType name="final"> + <restriction base="t:interm"> + <enumeration value="a"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <complexType name="complex"> + <simpleContent> + <extension base="t:final"> + <attribute name="x" type="string"/> + </extension> + </simpleContent> + </complexType> + + <complexType name="type"> + <sequence> + <element name="base" type="t:base" maxOccurs="unbounded"/> + <element name="simple" type="t:simple" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="root" type="t:type"/> + +</schema> diff --git a/tests/cxx/hybrid/polymorphism/makefile b/tests/cxx/hybrid/polymorphism/makefile index 72f0c87..703ef9a 100644 --- a/tests/cxx/hybrid/polymorphism/makefile +++ b/tests/cxx/hybrid/polymorphism/makefile @@ -5,12 +5,15 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make -all_tests := multischema +# NOTE: remember to update dist/tests/cxx/hybrid/polymorphis/{makefile, +# nmakefile} if you change anything here. +# +all_tests := enumeration multischema build_tests := ifeq ($(xsde_iostream),y) -build_tests += multischema +build_tests += enumeration multischema endif default := $(out_base)/ diff --git a/xsde/cxx/hybrid/cli.hxx b/xsde/cxx/hybrid/cli.hxx index 509005a..4e86e41 100644 --- a/xsde/cxx/hybrid/cli.hxx +++ b/xsde/cxx/hybrid/cli.hxx @@ -34,6 +34,7 @@ namespace CXX extern Key suppress_parser_val; extern Key suppress_serializer_val; extern Key omit_default_attributes; + extern Key suppress_enum; extern Key generate_detach; extern Key generate_insertion; extern Key generate_extraction; @@ -122,6 +123,7 @@ namespace CXX suppress_parser_val, Boolean, suppress_serializer_val, Boolean, omit_default_attributes, Boolean, + suppress_enum, Boolean, generate_detach, Boolean, generate_insertion, Cult::Containers::Vector<NarrowString>, generate_extraction, Cult::Containers::Vector<NarrowString>, diff --git a/xsde/cxx/hybrid/default-value.cxx b/xsde/cxx/hybrid/default-value.cxx index e232eae..6abfb05 100644 --- a/xsde/cxx/hybrid/default-value.cxx +++ b/xsde/cxx/hybrid/default-value.cxx @@ -578,6 +578,38 @@ namespace CXX } Void InitValue:: + traverse (SemanticGraph::Enumeration& e) + { + using SemanticGraph::Enumerator; + using SemanticGraph::Enumeration; + + // First see if we should delegate this one to the Complex + // generator. + // + Enumeration* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + traverse (static_cast<SemanticGraph::Complex&> (e)); + return; + } + + Enumeration& x (base_enum ? *base_enum : e); + + os << member_ << x.context ().get<String> ("value") << "("; + + Enumeration::NamesIteratorPair ip (x.find (value_)); + + if (ip.first != ip.second) + { + Enumerator& er (dynamic_cast<Enumerator&> (ip.first->named ())); + os << fq_name (e) << "::" << ename (er); + } + + os << ");"; + } + + Void InitValue:: traverse (SemanticGraph::Type& t) { // This is a fall-back case where we handle all other (literal) @@ -1213,6 +1245,21 @@ namespace CXX } Void CompareValue:: + traverse (SemanticGraph::Enumeration& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + traverse (static_cast<SemanticGraph::Complex&> (e)); + return; + } + + os << *lhs_ << " == " << *rhs_; + } + + Void CompareValue:: traverse (SemanticGraph::Type&) { // This is a fall-back case where we handle all other types. diff --git a/xsde/cxx/hybrid/default-value.hxx b/xsde/cxx/hybrid/default-value.hxx index b9f902c..46a6bf0 100644 --- a/xsde/cxx/hybrid/default-value.hxx +++ b/xsde/cxx/hybrid/default-value.hxx @@ -163,6 +163,7 @@ namespace CXX struct InitValue: Traversal::List, Traversal::Union, Traversal::Complex, + Traversal::Enumeration, Traversal::Type, Traversal::AnySimpleType, @@ -217,6 +218,9 @@ namespace CXX traverse (SemanticGraph::Complex&); virtual Void + traverse (SemanticGraph::Enumeration&); + + virtual Void traverse (SemanticGraph::Type& t); // anySimpleType. @@ -337,6 +341,7 @@ namespace CXX struct CompareValue: Traversal::Union, Traversal::Complex, + Traversal::Enumeration, Traversal::Type, Context { @@ -354,6 +359,9 @@ namespace CXX traverse (SemanticGraph::Complex&); virtual Void + traverse (SemanticGraph::Enumeration&); + + virtual Void traverse (SemanticGraph::Type& t); private: diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx index 6db57ff..eba0880 100644 --- a/xsde/cxx/hybrid/elements.cxx +++ b/xsde/cxx/hybrid/elements.cxx @@ -39,6 +39,7 @@ namespace CXX detach (ops.value<CLI::generate_detach> ()), mixin (ops.value<CLI::reuse_style_mixin> ()), tiein (!mixin), + enum_ (!ops.value<CLI::suppress_enum> ()), fwd_expr (fe), hxx_expr (he), ixx_expr (ie), @@ -495,6 +496,34 @@ namespace CXX return os; } + Boolean Context:: + enum_mapping (SemanticGraph::Enumeration& e, + SemanticGraph::Enumeration** base) + { + Boolean gen (false); + StringBasedType t (gen); + t.dispatch (e); + + if (gen) + { + // The first enumeration in the inheritance hierarchy breaks + // inheritance. If its base is polymorphic then generating + // the enum mapping will most likely break things. + // + SemanticGraph::Enumeration* b (0); + EnumBasedType t (b); + t.dispatch (e); + + SemanticGraph::Enumeration& first (b ? *b : e); + gen = !polymorphic (first.inherits ().base ()); + + if (gen && base) + *base = b; + } + + return gen; + } + // Namespace // Namespace:: diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx index 5a94dda..77b91a2 100644 --- a/xsde/cxx/hybrid/elements.hxx +++ b/xsde/cxx/hybrid/elements.hxx @@ -48,6 +48,7 @@ namespace CXX typeinfo (c.typeinfo), mixin (c.mixin), tiein (c.tiein), + enum_ (c.enum_), fwd_expr (c.fwd_expr), hxx_expr (c.hxx_expr), ixx_expr (c.ixx_expr), @@ -78,6 +79,7 @@ namespace CXX typeinfo (c.typeinfo), mixin (c.mixin), tiein (c.tiein), + enum_ (c.enum_), fwd_expr (c.fwd_expr), hxx_expr (c.hxx_expr), ixx_expr (c.ixx_expr), @@ -572,6 +574,13 @@ namespace CXX open_ns (); public: + // Determine whether we are generating the enum mapping for this + // enumeration. Also optionally return the base enum. + // + static Boolean + enum_mapping (SemanticGraph::Enumeration& e, + SemanticGraph::Enumeration** base = 0); + public: typedef Cult::Containers::Deque<String> NamespaceStack; @@ -588,6 +597,7 @@ namespace CXX Boolean typeinfo; Boolean mixin; Boolean tiein; + Boolean enum_; Regex const* fwd_expr; Regex const* hxx_expr; @@ -871,6 +881,124 @@ namespace CXX Boolean& r_; }; + // Check whether this is a string-based type (excluding ID, IDFER, + // anyURI, and ENTITY). + // + struct StringBasedType: Traversal::Complex, + Traversal::Fundamental::String, + Traversal::Fundamental::NormalizedString, + Traversal::Fundamental::Token, + Traversal::Fundamental::Name, + Traversal::Fundamental::NameToken, + Traversal::Fundamental::NCName, + Traversal::Fundamental::Language + { + StringBasedType (Boolean& r) + : r_ (r) + { + *this >> inherits_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + } + + // Strings. + // + virtual Void + traverse (SemanticGraph::Fundamental::String&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NormalizedString&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Token&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NameToken&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Name&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::NCName&) + { + r_ = true; + } + + virtual Void + traverse (SemanticGraph::Fundamental::Language&) + { + r_ = true; + } + + private: + Boolean& r_; + Traversal::Inherits inherits_; + }; + + + // Check whether this is a enumeration-based type. + // + struct EnumBasedType: Traversal::Complex + { + EnumBasedType (SemanticGraph::Enumeration*& e) + : enum_ (e) + { + *this >> inherits_; + + inherits_ >> *this; + inherits_ >> enum_; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c, inherits_); + } + + private: + struct Enumeration: Traversal::Enumeration + { + Enumeration (SemanticGraph::Enumeration*& e) + : e_ (e) + { + } + + virtual Void + traverse (Type& e) + { + if (e_ == 0) + e_ = &e; + } + + private: + SemanticGraph::Enumeration*& e_; + }; + + + private: + Enumeration enum_; + Traversal::Inherits inherits_; + }; + // // diff --git a/xsde/cxx/hybrid/extraction-header.cxx b/xsde/cxx/hybrid/extraction-header.cxx index dc729f6..e2ed714 100644 --- a/xsde/cxx/hybrid/extraction-header.cxx +++ b/xsde/cxx/hybrid/extraction-header.cxx @@ -14,6 +14,47 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + for (Streams::ConstIterator i (istreams.begin ()); + i != istreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator>> (" << istream (*i) << "&," << endl + << name << "&);" + << endl; + } + } + + private: + Traversal::Complex& complex_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -256,6 +297,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -263,6 +305,7 @@ namespace CXX names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/extraction-source.cxx b/xsde/cxx/hybrid/extraction-source.cxx index 5460740..e829760 100644 --- a/xsde/cxx/hybrid/extraction-source.cxx +++ b/xsde/cxx/hybrid/extraction-source.cxx @@ -14,6 +14,60 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + for (Streams::ConstIterator i (istreams.begin ()); + i != istreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator>> (" << istream (*i) << "& s," << endl + << name << "& x)" + << "{" + << "unsigned int i;"; + + if (exceptions) + os << "s >> i;"; + else + os << "if (!(s >> i))" << endl + << "return false;"; + + os << "x = static_cast< " << name << "::" << + e.context ().get<String> ("value-type") << " > (i);" + << (exceptions ? "" : "return true;") + << "}" + << endl; + } + } + + private: + Traversal::Complex& complex_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -1102,6 +1156,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -1109,6 +1164,7 @@ namespace CXX names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx index 78b9142..c7dcb1d 100644 --- a/xsde/cxx/hybrid/generator.cxx +++ b/xsde/cxx/hybrid/generator.cxx @@ -122,6 +122,7 @@ namespace CXX extern Key suppress_parser_val = "suppress-parser-val"; extern Key suppress_serializer_val = "suppress-serializer-val"; extern Key omit_default_attributes = "omit-default-attributes"; + extern Key suppress_enum = "suppress-enum"; extern Key generate_detach = "generate-detach"; extern Key generate_insertion = "generate-insertion"; extern Key generate_extraction = "generate-extraction"; @@ -257,6 +258,11 @@ namespace CXX << " from serialized XML documents." << endl; + e << "--suppress-enum" << endl + << " Suppress the generation of the XML Schema\n" + << " enumeration to C++ enum mapping." + << endl; + e << "--generate-detach" << endl << " Generate detach functions for elements and\n" << " attributes of variable-length types." diff --git a/xsde/cxx/hybrid/insertion-header.cxx b/xsde/cxx/hybrid/insertion-header.cxx index 4898c02..b1a4dbe 100644 --- a/xsde/cxx/hybrid/insertion-header.cxx +++ b/xsde/cxx/hybrid/insertion-header.cxx @@ -14,6 +14,47 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + for (Streams::ConstIterator i (ostreams.begin ()); + i != ostreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator<< (" << ostream (*i) << "&," << endl + << "const " << name << "&);" + << endl; + } + } + + private: + Traversal::Complex& complex_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -256,6 +297,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -263,6 +305,7 @@ namespace CXX names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/insertion-source.cxx b/xsde/cxx/hybrid/insertion-source.cxx index 7dc6fcb..7fce9ee 100644 --- a/xsde/cxx/hybrid/insertion-source.cxx +++ b/xsde/cxx/hybrid/insertion-source.cxx @@ -14,6 +14,51 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + for (Streams::ConstIterator i (ostreams.begin ()); + i != ostreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator<< (" << ostream (*i) << "& s," << endl + << "const " << name << "& x)" + << "{" + << "unsigned int i = x;" + << (exceptions ? "" : "return ") << "s << i;" + << "}" + << endl; + } + } + + private: + Traversal::Complex& complex_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -721,6 +766,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -728,6 +774,7 @@ namespace CXX names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/parser-header.cxx b/xsde/cxx/hybrid/parser-header.cxx index c174df4..d8948d7 100644 --- a/xsde/cxx/hybrid/parser-header.cxx +++ b/xsde/cxx/hybrid/parser-header.cxx @@ -14,6 +14,194 @@ namespace CXX { namespace { + // + // + struct PostOverride: Traversal::Complex, Context + { + PostOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + os << "virtual " << pret_type (b) << endl + << post_name (b) << " ();" + << endl; + } + } + } + }; + + // + // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex), post_override_ (c) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (epimpl_custom (e)); + + // We may not need to generate the class if this parser is + // being customized. + // + if (name) + { + Boolean fl (fixed_length (e)); + SemanticGraph::Type& b (e.inherits ().base ()); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << epskel (e); + + // Derive from base pimpl even if base_enum == 0. This is done + // so that we have implementations for all the (otherwise pure + // virtual) post_*() functions. + // + if (mixin) + os << "," << endl + << " public " << fq_name (b, "p:impl"); + + os << "{" + << "public:" << endl; + + // c-tor + // + if (!fl || tiein) + os << name << " (" << (fl ? "" : "bool = false") << ");" + << endl; + + if (!fl) + { + // d-tor + // + os << "~" << name << " ();" + << endl; + + // reset + // + if (reset) + os << "virtual void" << endl + << "_reset ();" + << endl; + } + + // pre + // + os << "virtual void" << endl + << "pre ();" + << endl; + + // _characters + // + if (!base_enum) + os << "virtual void" << endl + << "_characters (const " << string_type << "&);" + << endl; + + // post + // + String const& ret (pret_type (e)); + + if (polymorphic (e)) + post_override_.dispatch (e); + + os << "virtual " << ret << endl + << post_name (e) << " ();" + << endl; + + String const& type (fq_name (e)); + + // pre_impl + // + if (!fl) + os << (tiein ? "public:" : "protected:") << endl + << "void" << endl + << pre_impl_name (e) << " (" << type << "*);" + << endl; + + // Base implementation. + // + if (tiein && base_enum) + os << (tiein ? "public:" : "protected:") << endl + << fq_name (b, "p:impl") << " base_impl_;" + << endl; + + // State. + // + if (!fl || !base_enum) + { + String const& state_type (epstate_type (e)); + + os << (tiein ? "public:" : "protected:") << endl + << "struct " << state_type + << "{"; + + if (!fl) + os << type << "* " << "x_;"; + + if (!base_enum) + { + if (stl) + os << "::std::string str_;"; + else + os << "::xsde::cxx::string str_;"; + } + + os << "};" + << state_type << " " << epstate (e) << ";"; + } + + if (!fl) + os << "bool " << epstate_base (e) << ";"; + + os << "};"; + } + + // Generate include for custom parser. + // + if (e.context ().count ("p:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + e.context ().get<String> ("p:impl-include")) << endl + << endl; + + open_ns (); + } + } + + private: + Traversal::Complex& complex_; + PostOverride post_override_; + }; + struct List: Traversal::List, Context { List (Context& c) @@ -352,35 +540,6 @@ namespace CXX // // - struct PostOverride: Traversal::Complex, Context - { - PostOverride (Context& c) - : Context (c) - { - } - - virtual Void - traverse (SemanticGraph::Complex& c) - { - if (c.inherits_p ()) - { - SemanticGraph::Type& b (c.inherits ().base ()); - - if (polymorphic (b)) - { - if (tiein) - dispatch (b); - - os << "virtual " << pret_type (b) << endl - << post_name (b) << " ();" - << endl; - } - } - } - }; - - // - // struct Complex : Traversal::Complex, Context { Complex (Context& c) @@ -624,10 +783,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/parser-name-processor.cxx b/xsde/cxx/hybrid/parser-name-processor.cxx index c635aec..819280f 100644 --- a/xsde/cxx/hybrid/parser-name-processor.cxx +++ b/xsde/cxx/hybrid/parser-name-processor.cxx @@ -4,6 +4,7 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include <cxx/elements.hxx> +#include <cxx/hybrid/elements.hxx> #include <cxx/hybrid/parser-name-processor.hxx> #include <xsd-frontend/semantic-graph.hxx> @@ -251,6 +252,61 @@ namespace CXX // // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (options.value<CLI::suppress_enum> () || + !Hybrid::Context::enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + SemanticGraph::Context& ec (e.context ()); + + // In case of customization use p:impl-base instead of p:impl. + // If the name is empty then we are not generating anything. + // + String const& name (ec.count ("p:impl-base") + ? ec.get<String> ("p:impl-base") + : ec.get<String> ("p:impl")); + if (!name) + return; + + Boolean fl (fixed_length (e)); + + NameSet set; + set.insert (name); + + if (!fl || !base_enum) + { + String state_type (find_name (name + L"_state", set)); + ec.set ("pstate-type", state_type); + ec.set ("pstate", find_name (state_type, "_", set)); + } + + if (!fl) + ec.set ("pstate-base", find_name (name + L"_base", "_", set)); + } + + private: + Traversal::Complex& complex_; + }; + + // + // struct List: Traversal::List, Context { List (Context& c) @@ -708,10 +764,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); ns_names >> list; ns_names >> union_; ns_names >> complex; + ns_names >> enumeration; schema.dispatch (tu); } diff --git a/xsde/cxx/hybrid/parser-source.cxx b/xsde/cxx/hybrid/parser-source.cxx index c877e1d..e5bbb90 100644 --- a/xsde/cxx/hybrid/parser-source.cxx +++ b/xsde/cxx/hybrid/parser-source.cxx @@ -14,6 +14,423 @@ namespace CXX { namespace { + // + // + struct PostOverride: Traversal::Complex, Context + { + PostOverride (Context& c) + : Context (c), scope_ (0) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + Boolean clear (false); + + if (scope_ == 0) + { + scope_ = &c; + clear = true; + } + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + String const& scope (epimpl_custom (*scope_)); + + os << pret_type (b) << " " << scope << "::" << endl + << post_name (b) << " ()" + << "{" + << "return this->" << post_name (c) << " ();" + << "}"; + } + } + + if (clear) + scope_ = 0; + } + + private: + SemanticGraph::Complex* scope_; + }; + + // + // + struct Enumerator: Traversal::Enumerator, Context + { + Enumerator (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + using SemanticGraph::Enumeration; + + Enumeration& s (dynamic_cast<Enumeration&> (e.scope ())); + + os << "if (strcmp (s, " << + strlit (e.name ()) << ") == 0)" << endl + << "v = " << fq_name (s) << "::" << ename (e) << ";"; + } + }; + + // + // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), + complex_ (complex), + post_override_ (c), + enumerator_ (c) + { + names_ >> enumerator_; + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (epimpl_custom (e)); + + if (!name) + return; + + os << "// " << name << endl + << "//" << endl + << endl; + + Boolean fl (fixed_length (e)); + + SemanticGraph::Context& ec (e.context ()); + SemanticGraph::Type& b (e.inherits ().base ()); + + String const& type (fq_name (e)); + String state; + + if (!fl || !base_enum) + state = epstate (e); + + // c-tor + // + if (!fl || tiein) + { + os << name << "::" << endl + << name << " (" << (fl ? "" : "bool b") << ")"; + + if (tiein) + os << endl + << ": " << epskel (e) << " (" << + (base_enum ? "&base_impl_" : "0") << ")"; + + if (base_enum && !fixed_length (b)) + { + if (tiein) + os << "," << endl + << " base_impl_" << " (true)"; + else + os << endl + << ": " << fq_name (b, "p:impl") << " (true)"; + } + + os << "{"; + + if (!fl) + { + os << "this->" << epstate_base (e) << " = b;" + << "this->" << state << ".x_ = 0;"; + } + + os << "}"; + } + + if (!fl) + { + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "if (!this->" << epstate_base (e) << ")" << endl + << "delete this->" << state << ".x_;" + << "}"; + + // reset + // + if (reset) + { + os << "void " << name << "::" << endl + << "_reset ()" + << "{"; + + if (mixin && base_enum) + os << epimpl (b) << "::_reset ();"; + + os << epskel (e) << "::_reset ();" + << endl; + + os << "if (!this->" << epstate_base (e) << ")" + << "{" + << "delete this->" << state << ".x_;" + << "this->" << state << ".x_ = 0;" + << "}" + << "}"; + } + } + + // pre_impl + // + if (!fl) + { + os << "void " << name << "::" << endl + << pre_impl_name (e) << " (" << type << "* x)" + << "{" + << "this->" << state << ".x_ = x;"; + + // Call base pre_impl (var-length) or pre (fix-length). + // + if (base_enum) + { + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + if (fixed_length (b)) + os << "pre ();"; + else + os << pre_impl_name (b) << " (x);"; + } + + // Clear the string buffer. + // + if (!base_enum) + { + if (stl) + os << "this->" << state << ".str_.clear ();"; + else + { + if (exceptions) + os << "this->" << state << ".str_.assign (\"\", 0);"; + else + { + os << endl + << "if (this->" << state << ".str_.assign (\"\", 0))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + } + } + + os << "}"; + } + + // pre + // + os << "void " << name << "::" << endl + << "pre ()" + << "{"; + + if (fl) + { + if (base_enum) + { + // Our base is also fixed-length so call its pre() + // + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + os << "pre ();"; + } + + // Clear the string buffer. + // + if (!base_enum) + { + if (stl) + os << "this->" << state << ".str_.clear ();"; + else + { + if (exceptions) + os << "this->" << state << ".str_.assign (\"\", 0);"; + else + { + os << endl + << "if (this->" << state << ".str_.assign (\"\", 0))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + } + } + } + else + { + if (exceptions) + os << "this->" << pre_impl_name (e) << " (new " << type << ");"; + else + os << type << "* x = new " << type << ";" + << "if (x)" << endl + << "this->" << pre_impl_name (e) << " (x);" + << "else" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + + os << "}"; + + // _characters + // + if (!base_enum) + { + os << "void " << name << "::" << endl + << "_characters (const " << string_type << "& s)" + << "{"; + + if (stl) + os << "this->" << state << ".str_.append (s.data (), s.size ());"; + else + { + if (exceptions) + os << "this->" << state << ".str_.append (s.data (), s.size ());"; + else + { + os << "if (this->" << state << ".str_.append (" << + "s.data (), s.size ()))" << endl + << "this->_sys_error (::xsde::cxx::sys_error::no_memory);"; + } + } + + os << "}"; + } + + // post + // + String const& ret (pret_type (e)); + + if (polymorphic (e)) + post_override_.dispatch (e); + + os << ret << " " << name << "::" << endl + << post_name (e) << " ()" + << "{"; + + if (base_enum) + { + if (fl) + { + os << type << " r;" + << "static_cast< " << fq_name (b) << "& > (r) = "; + + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + os << post_name (b) << " ();"; + } + else + { + os << type << "* r = this->" << state << ".x_;" + << "this->" << state << ".x_ = 0;"; + + Boolean flb (fixed_length (b)); + + // Copy the value if our base is fixed-length. + // + if (flb) + os << "r->" << base_enum->context ().get<String> ("value") << + " ("; + + if (tiein) + os << "this->base_impl_."; + else + os << epimpl (b) << "::"; //@@ fq-name. + + os << post_name (b) << " ()"; + + if (flb) + os << ")"; + + os << ";"; + } + + // + // @@ TODO: check enumerators (switch) + // + } + else + { + String const& vt (ec.get<String> ("value-type")); + + os << type << "::" << vt << " v = static_cast< " << type << + "::" << vt << " > (0);" + << "const char* s = this->" << state << ".str_." << + (stl ? "c_str" : "data") << " ();" + << endl; + + names<Enumeration> (e, names_, 0, 0, 0, &Enumeration::comma); + + + /* + // @@ Cannot do error checking in post. + + if (!options.value<CLI::suppress_validation> () && + !options.value<CLI::suppress_parser_val> ()) + { + os << "else" << endl + << "this->_schema_error (" << + "::xsde::cxx::schema_error::invalid_enumeration_value);"; + } + */ + + os << endl; + + if (fl) + os << type << " r (v);"; + else + os << type << "* r = this->" << state << ".x_;" + << "this->" << state << ".x_ = 0;" + << "r->" << ec.get<String> ("value") << " (v);"; + } + + os << "return r;" + << "}"; + } + + virtual Void + comma (Type&) + { + os << "else "; + } + + private: + Traversal::Complex& complex_; + PostOverride post_override_; + + Traversal::Names names_; + Enumerator enumerator_; + }; + + // + // struct List: Traversal::List, Context { List (Context& c) @@ -907,53 +1324,6 @@ namespace CXX // // - struct PostOverride: Traversal::Complex, Context - { - PostOverride (Context& c) - : Context (c), scope_ (0) - { - } - - virtual Void - traverse (SemanticGraph::Complex& c) - { - Boolean clear (false); - - if (scope_ == 0) - { - scope_ = &c; - clear = true; - } - - if (c.inherits_p ()) - { - SemanticGraph::Type& b (c.inherits ().base ()); - - if (polymorphic (b)) - { - if (tiein) - dispatch (b); - - String const& scope (epimpl_custom (*scope_)); - - os << pret_type (b) << " " << scope << "::" << endl - << post_name (b) << " ()" - << "{" - << "return this->" << post_name (c) << " ();" - << "}"; - } - } - - if (clear) - scope_ = 0; - } - - private: - SemanticGraph::Complex* scope_; - }; - - // - // struct Complex: Traversal::Complex, Context { Complex (Context& c) @@ -1444,10 +1814,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/serializer-header.cxx b/xsde/cxx/hybrid/serializer-header.cxx index 153da8d..b36b910 100644 --- a/xsde/cxx/hybrid/serializer-header.cxx +++ b/xsde/cxx/hybrid/serializer-header.cxx @@ -14,6 +14,141 @@ namespace CXX { namespace { + // + // + struct PreOverride: Traversal::Complex, Context + { + PreOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + os << "virtual void" << endl + << "pre (" << sarg_type (b) << ");" + << endl; + } + } + } + }; + + // + // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex), pre_override_ (c) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (esimpl_custom (e)); + + // We may not need to generate the class if this serializer is + // being customized. + // + if (name) + { + String const& arg (sarg_type (e)); + SemanticGraph::Type& b (e.inherits ().base ()); + + os << "class " << name << ": public " << + (mixin ? "virtual " : "") << esskel (e); + + // Derive from base simpl even if base_enum == 0. This is done + // so that we have implementations for all the (otherwise pure + // virtual) pre() functions. + // + if (mixin) + os << "," << endl + << " public " << fq_name (b, "s:impl"); + + os << "{" + << "public:" << endl; + + // c-tor + // + if (tiein) + os << name << " ();" + << endl; + + // pre + // + if (polymorphic (e)) + pre_override_.dispatch (e); + + os << "virtual void" << endl + << "pre (" << arg << ");" + << endl; + + // _serialize_content + // + if (!base_enum) + os << "virtual void" << endl + << "_serialize_content ();" + << endl; + + // State. + // + if (!base_enum) + { + os << (tiein ? "public:" : "protected:") << endl + << "const " << fq_name (e) << "* " << esstate (e) << ";"; + } + else if (tiein) + { + os << "public:" << endl + << fq_name (b, "s:impl") << " base_impl_;"; + } + + os << "};"; + } + + // Generate include for custom serializer. + // + if (e.context ().count ("s:impl-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + e.context ().get<String> ("s:impl-include")) << endl + << endl; + + open_ns (); + } + } + + private: + Traversal::Complex& complex_; + PreOverride pre_override_; + }; + + // + // struct List: Traversal::List, Context { List (Context& c) @@ -343,35 +478,6 @@ namespace CXX // // - struct PreOverride: Traversal::Complex, Context - { - PreOverride (Context& c) - : Context (c) - { - } - - virtual Void - traverse (SemanticGraph::Complex& c) - { - if (c.inherits_p ()) - { - SemanticGraph::Type& b (c.inherits ().base ()); - - if (polymorphic (b)) - { - if (tiein) - dispatch (b); - - os << "virtual void" << endl - << "pre (" << sarg_type (b) << ");" - << endl; - } - } - } - }; - - // - // struct Complex : Traversal::Complex, Context { Complex (Context& c) @@ -511,7 +617,7 @@ namespace CXX if (tiein && hb) - os << (tiein ? "public:" : "protected:") << endl + os << "public:" << endl << fq_name (c.inherits ().base (), "s:impl") << " base_impl_;" << endl; @@ -605,10 +711,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/serializer-name-processor.cxx b/xsde/cxx/hybrid/serializer-name-processor.cxx index 2f7d296..159e3b0 100644 --- a/xsde/cxx/hybrid/serializer-name-processor.cxx +++ b/xsde/cxx/hybrid/serializer-name-processor.cxx @@ -4,6 +4,7 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include <cxx/elements.hxx> +#include <cxx/hybrid/elements.hxx> #include <cxx/hybrid/serializer-name-processor.hxx> #include <xsd-frontend/semantic-graph.hxx> @@ -244,6 +245,54 @@ namespace CXX // // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (options.value<CLI::suppress_enum> () || + !Hybrid::Context::enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + SemanticGraph::Context& ec (e.context ()); + + // In case of customization use s:impl-base instead of s:impl. + // If the name is empty then we are not generating anything. + // + String const& name (ec.count ("s:impl-base") + ? ec.get<String> ("s:impl-base") + : ec.get<String> ("s:impl")); + if (!name) + return; + + if (!base_enum) + { + NameSet set; + set.insert (name); + + ec.set ("sstate", find_name (name + L"_state", "_", set)); + } + } + + private: + Traversal::Complex& complex_; + }; + + // + // struct List: Traversal::List, Context { List (Context& c) @@ -288,9 +337,9 @@ namespace CXX } virtual Void - traverse (Type& l) + traverse (Type& u) { - SemanticGraph::Context& uc (l.context ()); + SemanticGraph::Context& uc (u.context ()); // In case of customization use s:impl-base instead of s:impl. // If the name is empty then we are not generating anything. @@ -723,10 +772,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); ns_names >> list; ns_names >> union_; ns_names >> complex; + ns_names >> enumeration; schema.dispatch (tu); } diff --git a/xsde/cxx/hybrid/serializer-source.cxx b/xsde/cxx/hybrid/serializer-source.cxx index 0aeaf89..1268631 100644 --- a/xsde/cxx/hybrid/serializer-source.cxx +++ b/xsde/cxx/hybrid/serializer-source.cxx @@ -70,6 +70,155 @@ namespace CXX // // + struct PreOverride: Traversal::Complex, Context + { + PreOverride (Context& c) + : Context (c), scope_ (0) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + Boolean clear (false); + + if (scope_ == 0) + { + scope_ = &c; + clear = true; + } + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + String const& scope (esimpl_custom (*scope_)); + + os << "void " << scope << "::" << endl + << "pre (" << sarg_type (b) << " x)" + << "{" + << "this->pre (static_cast< " << sarg_type (c) << " > (x));" + << "}"; + } + } + + if (clear) + scope_ = 0; + } + + private: + SemanticGraph::Complex* scope_; + }; + + // + // + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), + complex_ (complex), + pre_override_ (c), + type_pass_(c) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (esimpl_custom (e)); + + if (!name) + return; + + String state; + + if (!base_enum) + state = esstate (e); + + os << "// " << name << endl + << "//" << endl + << endl; + + // c-tor + // + if (tiein) + { + os << name << "::" << endl + << name << " ()" << endl + << ": " << esskel (e) << " (" << + (base_enum ? "&base_impl_" : "0") << ")" + << "{" + << "}"; + } + + // pre + // + String const& arg (sarg_type (e)); + + if (polymorphic (e)) + pre_override_.dispatch (e); + + os << "void " << name << "::" << endl + << "pre (" << arg << " x)" + << "{"; + + if (base_enum) + { + SemanticGraph::Type& b (e.inherits ().base ()); + + if (tiein) + os << "this->base_impl_.pre ("; + else + os << esimpl (b) << "::pre ("; + + type_pass_.dispatch (b); + + os << "x);"; + } + else + os << "this->" << state << " = &x;"; + + os << "}"; + + // _serialize_content + // + if (!base_enum) + { + String const& string (e.context ().get<String> ("string")); + + os << "void " << name << "::" << endl + << "_serialize_content ()" + << "{" + << "this->_characters (this->" << state << "->" << + string << " ());" + << "}"; + } + } + + private: + Traversal::Complex& complex_; + PreOverride pre_override_; + TypePass type_pass_; + }; + + // + // struct List: Traversal::List, Context { List (Context& c) @@ -931,53 +1080,6 @@ namespace CXX // // - struct PreOverride: Traversal::Complex, Context - { - PreOverride (Context& c) - : Context (c), scope_ (0) - { - } - - virtual Void - traverse (SemanticGraph::Complex& c) - { - Boolean clear (false); - - if (scope_ == 0) - { - scope_ = &c; - clear = true; - } - - if (c.inherits_p ()) - { - SemanticGraph::Type& b (c.inherits ().base ()); - - if (polymorphic (b)) - { - if (tiein) - dispatch (b); - - String const& scope (esimpl_custom (*scope_)); - - os << "void " << scope << "::" << endl - << "pre (" << sarg_type (b) << " x)" - << "{" - << "this->pre (static_cast< " << sarg_type (c) << " > (x));" - << "}"; - } - } - - if (clear) - scope_ = 0; - } - - private: - SemanticGraph::Complex* scope_; - }; - - // - // struct Complex: Traversal::Complex, Context { Complex (Context& c) @@ -1125,7 +1227,6 @@ namespace CXX if (!b.is_a<SemanticGraph::AnyType> () && !b.is_a<SemanticGraph::AnySimpleType> ()) { - if (tiein) os << "this->base_impl_.pre ("; else @@ -1290,10 +1391,12 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/tree-forward.cxx b/xsde/cxx/hybrid/tree-forward.cxx index 17a4916..bd53f9d 100644 --- a/xsde/cxx/hybrid/tree-forward.cxx +++ b/xsde/cxx/hybrid/tree-forward.cxx @@ -14,6 +14,50 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + if (!enum_ || !enum_mapping (e)) + { + complex_.traverse (e); + return; + } + + SemanticGraph::Context& ctx (e.context ()); + + // Forward-declare the base. + // + if (ctx.count ("name-base")) + { + if (String base = ctx.get<String> ("name-base")) + os << "class " << base << ";"; + } + + // Typedef or forward-declare the type. + // + if (ctx.count ("name-typedef")) + { + os << "typedef " << ctx.get<String> ("name-typedef") << " " << + ename (e) << ";"; + } + else + os << "class " << ename (e) << ";"; + } + + private: + Traversal::Complex& complex_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -752,7 +796,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); - //Enumeration enumeration (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -760,7 +804,7 @@ namespace CXX names >> list; names >> union_; names >> complex; - //names >> enumeration; + names >> enumeration; schema.dispatch (ctx.schema_root); diff --git a/xsde/cxx/hybrid/tree-header.cxx b/xsde/cxx/hybrid/tree-header.cxx index 929ea6e..aba65c7 100644 --- a/xsde/cxx/hybrid/tree-header.cxx +++ b/xsde/cxx/hybrid/tree-header.cxx @@ -14,6 +14,229 @@ namespace CXX { namespace { + struct Enumerator: Traversal::Enumerator, Context + { + Enumerator (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + os << ename (e); + } + }; + + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), + complex_ (complex), + base_name_ (c, TypeName::base), + enumerator_ (c) + { + names_ >> enumerator_; + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + SemanticGraph::Context& ec (e.context ()); + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (name) + { + Boolean fl (fixed_length (e)); + Boolean cd (ec.count ("cd-name")); + Boolean poly (polymorphic (e)); + String const& vt (ec.get<String> ("value-type")); + + os << "// " << comment (e.name ()) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "//" << endl; + + os << "class " << name; + + if (base_enum) + { + os << ": public "; + base_name_.dispatch (e.inherits ().base ()); + } + + os << "{"; + + if (!fl) + os << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; + + os << "public:" << endl; + + // value_type + // + if (base_enum) + { + os << "typedef "; + base_name_.dispatch (*base_enum); + os << "::" << base_enum->context ().get<String> ("value-type") << + " " << vt << ";" + << endl; + } + else + { + os << "enum " << vt + << "{"; + names<Enumeration> (e, names_, 0, 0, 0, &Enumeration::comma); + os << "};"; + } + + // c-tors + // + os << name << " ();" + << name << " (" << vt << ");" + << endl; + + // value (value_type) + // + if (!base_enum) + os << "void" << endl + << ec.get<String> ("value") << " (" << vt << ");" + << endl; + + // d-tor + // + if (poly) + os << "virtual" << endl + << "~" << name << " ();" + << endl; + + if (!base_enum) + { + // operator value() + // + // Name lookup differences in various compilers make generation + // of this operator outside of the class a really hard task. So + // we are going to make it always inline. + // + os << "operator " << vt << " () const" + << "{" + << "return " << ec.get<String> ("value-member") << ";" + << "}"; + + // string() + // + os << "const char*" << endl + << ec.get<String> ("string") << " () const;" + << endl; + } + + // Custom data. + // + if (cd) + { + String const& name (ecd_name (e)); + String const& sequence (ecd_sequence (e)); + String const& iterator (ecd_iterator (e)); + String const& const_iterator (ecd_const_iterator (e)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef " << data_seq << " " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; + + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; + + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + if (poly && typeinfo) + { + os << "// Type information." << endl + << "//" << endl; + + os << "static const " << + (stl ? "::std::string&" : "char*") << endl + << "_static_type ();" + << endl; + + os << "virtual const " << + (stl ? "::std::string&" : "char*") << endl + << "_dynamic_type () const;" + << endl; + } + + if (!base_enum || cd) + os << "private:" << endl; + + if (!base_enum) + os << vt << " " << ec.get<String> ("value-member") << ";"; + + if (cd) + os << ecd_sequence (e) << " " << ecd_member (e) << ";"; + + os << "};"; + } + + // Generate include for custom type. + // + if (ec.count ("name-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + ec.get<String> ("name-include")) << endl + << endl; + + open_ns (); + } + } + + virtual Void + comma (Type&) + { + os << "," << endl; + } + + private: + Traversal::Complex& complex_; + TypeName base_name_; + + Traversal::Names names_; + Enumerator enumerator_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -2412,6 +2635,14 @@ namespace CXX os << "{"; + // copy c-tor & operator= (private) + // + if (!fl) + os << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; + // c-tor // os << "public:" << endl @@ -2422,19 +2653,13 @@ namespace CXX if (!restriction || poly) os << (poly ? "virtual\n" : "") << "~" << name << " ();"; - // copy c-tor & operator= + // copy c-tor & operator= (public) // - if (!fl) - os << endl - << "private:" << endl; - - if (!fl || !restriction) + if (fl && !restriction) os << name << " (const " << name << "&);" - << name << "& operator= (const " << name << "&);" - << endl; + << name << "& operator= (const " << name << "&);"; - if ((!restriction && !fl) || cd) - os << "public:" << endl; + os << endl; if (!restriction) { @@ -2614,7 +2839,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); - //Enumeration enumeration (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -2622,7 +2847,7 @@ namespace CXX names >> list; names >> union_; names >> complex; - //names >> enumeration; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/tree-inline.cxx b/xsde/cxx/hybrid/tree-inline.cxx index 26b1a48..28a0582 100644 --- a/xsde/cxx/hybrid/tree-inline.cxx +++ b/xsde/cxx/hybrid/tree-inline.cxx @@ -15,6 +15,115 @@ namespace CXX { namespace { + struct Enumeration : Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), + complex_ (complex), + base_name_ (c, TypeName::base) + { + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + SemanticGraph::Context& ec (e.context ()); + String const& vt (ec.get<String> ("value-type")); + + os << "// " << comment (e.name ()) << endl + << "//" << endl + << endl; + + // c-tors + // + os << inl + << name << "::" << endl + << name << " ()" + << "{" + << "}"; + + os << inl + << name << "::" << endl + << name << " (" << vt << " v)" + << "{"; + + if (base_enum) + { + os << "this->" << base_enum->context ().get<String> ("value") << + " (v);"; + } + else + os << ec.get<String> ("value-member") << " = v;"; + + os << "}"; + + // value (value_type) + // + if (!base_enum) + { + os << inl + << "void " << name << "::" << endl + << ec.get<String> ("value") << " (" << vt << " v)" + << "{" + << ec.get<String> ("value-member") << " = v;" + << "}"; + } + + // Custom data. + // + if (ec.count ("cd-name")) + { + String const& cd_name (ecd_name (e)); + String const& member (ecd_member (e)); + String const& sequence (ecd_sequence (e)); + + // const seq& + // name () const + // + os << inl + << "const " << name << "::" << sequence << "& " << + name << "::" << endl + << cd_name << " () const" + << "{" + << "return this->" << member << ";" + << "}"; + + // seq& + // name () + // + os << inl + << name << "::" << sequence << "& " << name << "::" << endl + << cd_name << " ()" + << "{" + << "return this->" << member << ";" + << "}"; + } + } + + private: + Traversal::Complex& complex_; + TypeName base_name_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -2029,7 +2138,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); - //Enumeration enumeration (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -2037,7 +2146,7 @@ namespace CXX names >> list; names >> union_; names >> complex; - //names >> enumeration; + names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/tree-name-processor.cxx b/xsde/cxx/hybrid/tree-name-processor.cxx index 240da59..e5c55db 100644 --- a/xsde/cxx/hybrid/tree-name-processor.cxx +++ b/xsde/cxx/hybrid/tree-name-processor.cxx @@ -4,6 +4,8 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include <cxx/elements.hxx> + +#include <cxx/hybrid/elements.hxx> #include <cxx/hybrid/tree-name-processor.hxx> #include <xsd-frontend/semantic-graph.hxx> @@ -51,6 +53,7 @@ namespace CXX schema_path (schema_path_), stl (!ops.value<CLI::no_stl> ()), detach (ops.value<CLI::generate_detach> ()), + enum_ (!ops.value<CLI::suppress_enum> ()), custom_data_map (custom_data_map_), custom_type_map (custom_type_map_), global_type_names (global_type_names_) @@ -179,6 +182,7 @@ namespace CXX schema_path (c.schema_path), stl (c.stl), detach (c.detach), + enum_ (c.enum_), custom_data_map (c.custom_data_map), custom_type_map (c.custom_type_map), global_type_names (c.global_type_names) @@ -279,6 +283,7 @@ namespace CXX Boolean stl; Boolean detach; + Boolean enum_; CustomDataMap& custom_data_map; CustomTypeMap& custom_type_map; @@ -1140,9 +1145,29 @@ namespace CXX // // + struct Enumerator: Traversal::Enumerator, Context + { + Enumerator (Context& c, NameSet& set) + : Context (c), set_ (set) + { + } + + virtual Void + traverse (Type& e) + { + e.context ().set ("name", find_name (e.name (), set_)); + } + + private: + NameSet& set_; + }; + + // + // struct GlobalTypeMembers: Traversal::List, Traversal::Union, Traversal::Complex, + Traversal::Enumeration, Context { GlobalTypeMembers (Context& c, Boolean data_members) @@ -1151,6 +1176,82 @@ namespace CXX } virtual Void + traverse (SemanticGraph::Enumeration& e) + { + // First see if we should delegate this one to Complex. + // + SemanticGraph::Enumeration* base_enum (0); + + if (!enum_ || !Hybrid::Context::enum_mapping (e, &base_enum)) + { + traverse (static_cast<SemanticGraph::Complex&> (e)); + return; + } + + SemanticGraph::Context& ec (e.context ()); + + // In case of customization use name-base instead of name. + // If name is empty then we are not generating anything. + // + String const& name (ec.count ("name-base") + ? ec.get<String> ("name-base") + : ec.get<String> ("name")); + if (!name) + return; + + if (!data_members_) + { + ec.set (member_set_key, NameSet ()); + NameSet& set (ec.get<NameSet> (member_set_key)); + set.insert (name); + + String v (ec.get<String> ("value-type")); // Set by GlobalTypeName. + set.insert (v); + + Enumerator enumerator (*this, set); + Traversal::Names names (enumerator); + Enumeration::names (e, names); + + if (!base_enum) + { + ec.set ("value", find_name ("value", set)); + ec.set ("string", find_name ("string", set)); + } + + // Check if this type has custom data. + // + CustomDataMap::Iterator i (custom_data_map.find (e.name ())); + + if (i != custom_data_map.end () && + i->second->find (L"") != i->second->end ()) + { + String name (find_name ("custom_data", set)); + + ec.set ("cd-name", name); + ec.set ("cd-sequence", find_name (name + L"_sequence", set)); + ec.set ("cd-iterator", find_name (name + L"_iterator", set)); + ec.set ("cd-const-iterator", + find_name (name + L"_const_iterator", set)); + } + } + else + { + NameSet& set (ec.get<NameSet> (member_set_key)); + + if (!base_enum) + ec.set ("value-member", find_name ("value_", set)); + + // Custom data. + // + if (ec.count ("cd-name")) + { + String const& base (ec.get<String> ("cd-name")); + ec.set ("cd-member", find_name (base + L"_", set)); + } + } + } + + virtual Void traverse (SemanticGraph::List& l) { SemanticGraph::Context& lc (l.context ()); @@ -1531,6 +1632,7 @@ namespace CXX // struct GlobalTypeName: Traversal::Type, Traversal::Union, + Traversal::Enumeration, Context { GlobalTypeName (Context& c, NameSet& set) @@ -1591,6 +1693,32 @@ namespace CXX uc.set ("value", find_name ("value", set)); } + virtual Void + traverse (SemanticGraph::Enumeration& e) + { + traverse (static_cast<SemanticGraph::Type&> (e)); + + if (enum_ && Hybrid::Context::enum_mapping (e)) + { + // We need to assign the value type name for enumerations + // even in included/imported schemas since we may need this + // information when generating derived enums. We need to do + // this even if the type is completely customized. + // + SemanticGraph::Context& ec (e.context ()); + String name (ec.count ("name-base") + ? ec.get<String> ("name-base") + : ec.get<String> ("name")); + + if (!name) + name = ec.get<String> ("name"); + + NameSet set; + set.insert (name); + ec.set ("value-type", find_name ("value_type", set)); + } + } + private: NameSet& set_; }; diff --git a/xsde/cxx/hybrid/tree-size-processor.cxx b/xsde/cxx/hybrid/tree-size-processor.cxx index 33d829a..c6b347e 100644 --- a/xsde/cxx/hybrid/tree-size-processor.cxx +++ b/xsde/cxx/hybrid/tree-size-processor.cxx @@ -237,20 +237,23 @@ namespace CXX // struct Type: Traversal::List, Traversal::Union, - Traversal::Complex + Traversal::Complex, + Traversal::Enumeration { Type (Boolean& valid, TypeSet& custom_data, CustomTypeMap& custom_type_map, TypeSet& poly_types, Boolean stl_, - Boolean poly_) + Boolean poly_, + Boolean enum_mapping) : valid_ (valid), custom_data_ (custom_data), custom_type_map_ (custom_type_map), poly_types_ (poly_types), stl (stl_), - poly (poly_) + poly (poly_), + enum_ (enum_mapping) { } @@ -281,6 +284,44 @@ namespace CXX } virtual Void + traverse (SemanticGraph::Enumeration& e) + { + if (!test (e)) + { + // First process our base since enum_mapping() needs the + // polymorphic property determined. + // + SemanticGraph::Type& b (e.inherits ().base ()); + + if (!test (b)) + dispatch (b); + + SemanticGraph::Enumeration* base_enum (0); + + if (!enum_ || !Context::enum_mapping (e, &base_enum)) + { + traverse (static_cast<SemanticGraph::Complex&> (e)); + return; + } + + Boolean fixed (true); + + if (base_enum && !get (b)) + fixed = false; + + // Check for custom data. + // + if (fixed) + { + if (custom_data_.find (e.name ()) != custom_data_.end ()) + fixed = false; + } + + set (e, fixed); + } + } + + virtual Void traverse (SemanticGraph::Complex& c) { SemanticGraph::Context& ctx (c.context ()); @@ -428,6 +469,7 @@ namespace CXX TypeSet& poly_types_; Boolean stl; Boolean poly; + Boolean enum_; typedef Containers::Vector<SemanticGraph::Complex*> Path; Path path_; @@ -1184,7 +1226,8 @@ namespace CXX custom_type_map, poly_types, stl, - poly); + poly, + !ops.value<CLI::suppress_enum> ()); schema >> schema_names >> ns >> ns_names >> type; diff --git a/xsde/cxx/hybrid/tree-source.cxx b/xsde/cxx/hybrid/tree-source.cxx index eb83658..61186b5 100644 --- a/xsde/cxx/hybrid/tree-source.cxx +++ b/xsde/cxx/hybrid/tree-source.cxx @@ -15,6 +15,135 @@ namespace CXX { namespace { + struct Enumerator: Traversal::Enumerator, Context + { + Enumerator (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& e) + { + os << strlit (e.name ()); + } + }; + + struct Enumeration: Traversal::Enumeration, Context + { + Enumeration (Context& c, Traversal::Complex& complex) + : Context (c), complex_ (complex), enumerator_ (c) + { + names_ >> enumerator_; + } + + virtual Void + traverse (Type& e) + { + // First see if we should delegate this one to the Complex + // generator. + // + Type* base_enum (0); + + if (!enum_ || !enum_mapping (e, &base_enum)) + { + complex_.traverse (e); + return; + } + + String const& name (ename_custom (e)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + SemanticGraph::Context& ec (e.context ()); + + os << "// " << comment (e.name ()) << endl + << "//" << endl + << endl; + + if (!base_enum) + { + os << "static const char* _xsde_" << name << "_enumerators_[] = {"; + names<Enumeration> (e, names_, 0, 0, 0, &Enumeration::comma); + os << "};"; + + // string() + // + os << "const char* " << name << "::" << endl + << ec.get<String> ("string") << " () const" + << "{" + << "return _xsde_" << name << "_enumerators_[" << + ec.get<String> ("value-member") << "];" + << "}"; + } + + if (polymorphic (e)) + { + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "}"; + + if (typeinfo) + { + String id (e.name ()); + + if (String ns = xml_ns_name (e)) + { + id += L' '; + id += ns; + } + + if (stl) + { + os << "static const ::std::string _xsde_" << name << + "_static_type_ = " << strlit (id) << ";" + << endl; + + os << "const ::std::string& " << name << "::" << endl + << "_static_type ()" + << "{" + << "return _xsde_" << name << "_static_type_;" + << "}"; + } + else + { + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + } + + os << "const " << (stl ? "::std::string& " : "char* ") << + name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + } + + virtual Void + comma (Type&) + { + os << "," << endl; + } + + private: + Traversal::Complex& complex_; + + Traversal::Names names_; + Enumerator enumerator_; + }; + struct List : Traversal::List, Context { List (Context& c) @@ -1968,6 +2097,7 @@ namespace CXX List list (ctx); Union union_ (ctx); Complex complex (ctx); + Enumeration enumeration (ctx, complex); schema >> sources >> schema; schema >> names_ns >> ns >> names; @@ -1975,6 +2105,7 @@ namespace CXX names >> list; names >> union_; names >> complex; + names >> enumeration; schema.dispatch (ctx.schema_root); } |