From 3dcdc88b14aec626c87f8f480a1d07781a27c069 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 27 Oct 2009 10:10:46 +0200 Subject: Implement schema enumeration to C++ enum mapping in C++/Hybrid --- NEWS | 17 +- dist/tests/cxx/hybrid/makefile | 4 +- dist/tests/cxx/hybrid/nmakefile | 4 +- documentation/cxx/hybrid/guide/index.xhtml | 162 +++++-- documentation/xsde.1 | 3 + documentation/xsde.xhtml | 4 + examples/cxx/hybrid/filter/driver.cxx | 6 +- examples/cxx/hybrid/library/driver.cxx | 6 +- examples/cxx/hybrid/minimal/driver.cxx | 7 +- tests/cxx/hybrid/enumeration/driver.cxx | 97 +++++ tests/cxx/hybrid/enumeration/makefile | 109 +++++ tests/cxx/hybrid/enumeration/test-000.std | 1 + tests/cxx/hybrid/enumeration/test-000.xml | 24 ++ tests/cxx/hybrid/enumeration/test.xsd | 88 ++++ .../cxx/hybrid/polymorphism/enumeration/driver.cxx | 67 +++ tests/cxx/hybrid/polymorphism/enumeration/makefile | 110 +++++ .../hybrid/polymorphism/enumeration/test-000.std | 1 + .../hybrid/polymorphism/enumeration/test-000.xml | 13 + tests/cxx/hybrid/polymorphism/enumeration/test.xsd | 58 +++ tests/cxx/hybrid/polymorphism/makefile | 7 +- xsde/cxx/hybrid/cli.hxx | 2 + xsde/cxx/hybrid/default-value.cxx | 47 +++ xsde/cxx/hybrid/default-value.hxx | 8 + xsde/cxx/hybrid/elements.cxx | 29 ++ xsde/cxx/hybrid/elements.hxx | 128 ++++++ xsde/cxx/hybrid/extraction-header.cxx | 43 ++ xsde/cxx/hybrid/extraction-source.cxx | 56 +++ xsde/cxx/hybrid/generator.cxx | 6 + xsde/cxx/hybrid/insertion-header.cxx | 43 ++ xsde/cxx/hybrid/insertion-source.cxx | 47 +++ xsde/cxx/hybrid/parser-header.cxx | 219 ++++++++-- xsde/cxx/hybrid/parser-name-processor.cxx | 58 +++ xsde/cxx/hybrid/parser-source.cxx | 466 ++++++++++++++++++--- xsde/cxx/hybrid/serializer-header.cxx | 168 ++++++-- xsde/cxx/hybrid/serializer-name-processor.cxx | 55 ++- xsde/cxx/hybrid/serializer-source.cxx | 199 ++++++--- xsde/cxx/hybrid/tree-forward.cxx | 48 ++- xsde/cxx/hybrid/tree-header.cxx | 249 ++++++++++- xsde/cxx/hybrid/tree-inline.cxx | 113 ++++- xsde/cxx/hybrid/tree-name-processor.cxx | 128 ++++++ xsde/cxx/hybrid/tree-size-processor.cxx | 51 ++- xsde/cxx/hybrid/tree-source.cxx | 131 ++++++ 42 files changed, 2842 insertions(+), 240 deletions(-) create mode 100644 tests/cxx/hybrid/enumeration/driver.cxx create mode 100644 tests/cxx/hybrid/enumeration/makefile create mode 100644 tests/cxx/hybrid/enumeration/test-000.std create mode 100644 tests/cxx/hybrid/enumeration/test-000.xml create mode 100644 tests/cxx/hybrid/enumeration/test.xsd create mode 100644 tests/cxx/hybrid/polymorphism/enumeration/driver.cxx create mode 100644 tests/cxx/hybrid/polymorphism/enumeration/makefile create mode 100644 tests/cxx/hybrid/polymorphism/enumeration/test-000.std create mode 100644 tests/cxx/hybrid/polymorphism/enumeration/test-000.xml create mode 100644 tests/cxx/hybrid/polymorphism/enumeration/test.xsd diff --git a/NEWS b/NEWS index 04dbd32..3eb2cf5 100644 --- a/NEWS +++ b/NEWS @@ -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 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 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 @@ - - - - - - - + + + + + + + +
4.1Namespaces
4.2Memory Management
4.3Attributes and Elements
4.4Compositors
4.5Accessing the Object Model
4.6Modifying the Object Model
4.7Creating the Object Model from Scratch
4.8Customizing the Object Model
4.9Polymorphic Object Models
4.3Enumerations
4.4Attributes and Elements
4.5Compositors
4.6Accessing the Object Model
4.7Modifying the Object Model
4.8Creating the Object Model from Scratch
4.9Customizing the Object Model
4.10Polymorphic Object Models
@@ -1542,7 +1543,7 @@ $ xsde cxx-hybrid --generate-parser --generate-serializer \

For information on how to use object models with polymorphic types, - refer to Section 4.9, "Polymorphic Object Models".

+ refer to Section 4.10, "Polymorphic Object Models".

@@ -1626,12 +1627,30 @@ $ xsde cxx-hybrid --generate-parser --generate-serializer \
 // 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:
     
  • it is recursive (that is, one of its elements contains a reference, directly or indirectly, to the type itself)
  • -
  • it is polymorphic (see Section 4.9, "Polymorphic +
  • it is polymorphic (see Section 4.10, "Polymorphic Object Models" for details)
  • @@ -1827,10 +1846,9 @@ private: variable-length because it contains a sequence of person elements (maxOccurs="unbounded"). If we recompile the people.xsd schema with the --no-stl - option, the first two types will also become variable-length - since gender inherits from and person - contains elements of the string built-in type. And - when STL is disabled, string is variable-length.

    + option, the person type will also become variable-length + since it contains elements of the string built-in type. + And when STL is disabled, string is variable-length.

    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.

    -

    4.3 Attributes and Elements

    +

    4.3 Enumerations

    + +

    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 --suppress-enum compiler + option). The following code fragment again shows the C++ class that + was generated for the gender XML Schema type presented + at the beginning of this chapter:

    + +
    +// 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_;
    +};
    +
    + +

    The gender class defines the underlying C++ enum type + (value_type) with enumerators corresponding to the + enumeration 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 gender class also supports the implicit + conversion to the underlying enum type and the explicit conversion + to string via the string() function. Finally, it + provides the value() 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 + gender class:

    + +
    +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:
    +  ...
    +}
    +  
    + + +

    4.4 Attributes and Elements

    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 first-name, last-name, gender, and age elements as well as the id 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 first-name element in the person class:

    @@ -1975,7 +2067,7 @@ class person

    The optional cardinality class covers all elements that can occur zero or one time as well as optional attributes. In our example, the middle-name 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 person class:

    @@ -2664,13 +2756,13 @@ namespace xml_schema } -

    4.4 Compositors

    +

    4.5 Compositors

    The XML Schema language provides three compositor constructs that are used to group elements: all, sequence, and choice. If a compositor has an optional - or sequence cardinality class (see Section - 4.3, "Attributes and Elements") or if a compositor is + or sequence cardinality class (see Section + 4.4, "Attributes and Elements") or if a compositor is inside choice, 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: }; -

    4.5 Accessing the Object Model

    +

    4.6 Accessing the Object Model

    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 -

    4.6 Modifying the Object Model

    +

    4.7 Modifying the Object Model

    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> -

    4.7 Creating the Object Model from Scratch

    +

    4.8 Creating the Object Model from Scratch

    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> -

    4.8 Customizing the Object Model

    +

    4.9 Customizing the Object Model

    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) -

    4.9 Polymorphic Object Models

    +

    4.10 Polymorphic Object Models

    When generating polymorphism-aware code (see Section 3.7, "Support for Polymorphism"), some objects @@ -4673,7 +4759,7 @@ namespace xml_schema

    The NMTOKENS and IDREFS built-in XML Schema types are mapped to the string sequence type which - is discussed in Section 4.3, "Attributes and + is discussed in Section 4.4, "Attributes and Elements".

    5.3 Mapping for base64Binary and hexBinary

    @@ -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 @@
    Omit attributes with default and fixed values from serialized XML documents.
    +
    --suppress-enum
    +
    Suppress the generation of the XML Schema enumeration to C++ + enum mapping.
    +
    --generate-detach
    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 +// 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 +#include + +#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 +# 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 @@ +ababacacabacac \ 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 @@ + + + a + b + + a + b + + a + c + + a + c + + a + b + + a + c + + a + c + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +// 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 + +#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 +# 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 @@ +ababbcc \ 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 @@ + + + a + b + + a + b + + b + c + c + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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, generate_extraction, Cult::Containers::Vector, 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 (e)); + return; + } + + Enumeration& x (base_enum ? *base_enum : e); + + os << member_ << x.context ().get ("value") << "("; + + Enumeration::NamesIteratorPair ip (x.find (value_)); + + if (ip.first != ip.second) + { + Enumerator& er (dynamic_cast (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 (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 ()), mixin (ops.value ()), tiein (!mixin), + enum_ (!ops.value ()), 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 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 ("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 ("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 +#include #include #include @@ -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 () || + !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 ("p:impl-base") + : ec.get ("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 (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 ("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 ("value-type")); + + os << type << "::" << vt << " v = static_cast< " << type << + "::" << vt << " > (0);" + << "const char* s = this->" << state << ".str_." << + (stl ? "c_str" : "data") << " ();" + << endl; + + names (e, names_, 0, 0, 0, &Enumeration::comma); + + + /* + // @@ Cannot do error checking in post. + + if (!options.value () && + !options.value ()) + { + 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 ("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 ("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 +#include #include #include @@ -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 () || + !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 ("s:impl-base") + : ec.get ("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")); + + 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 () && !b.is_a ()) { - 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 ("name-base")) + os << "class " << base << ";"; + } + + // Typedef or forward-declare the type. + // + if (ctx.count ("name-typedef")) + { + os << "typedef " << ctx.get ("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 ("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 ("value-type") << + " " << vt << ";" + << endl; + } + else + { + os << "enum " << vt + << "{"; + names (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 ("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 ("value-member") << ";" + << "}"; + + // string() + // + os << "const char*" << endl + << ec.get ("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 ("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 ("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 ("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 ("value") << + " (v);"; + } + else + os << ec.get ("value-member") << " = v;"; + + os << "}"; + + // value (value_type) + // + if (!base_enum) + { + os << inl + << "void " << name << "::" << endl + << ec.get ("value") << " (" << vt << " v)" + << "{" + << ec.get ("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 + +#include #include #include @@ -51,6 +53,7 @@ namespace CXX schema_path (schema_path_), stl (!ops.value ()), detach (ops.value ()), + enum_ (!ops.value ()), 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 (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 ("name-base") + : ec.get ("name")); + if (!name) + return; + + if (!data_members_) + { + ec.set (member_set_key, NameSet ()); + NameSet& set (ec.get (member_set_key)); + set.insert (name); + + String v (ec.get ("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 (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 ("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 (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 ("name-base") + : ec.get ("name")); + + if (!name) + name = ec.get ("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 (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 Path; Path path_; @@ -1184,7 +1226,8 @@ namespace CXX custom_type_map, poly_types, stl, - poly); + poly, + !ops.value ()); 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 (e, names_, 0, 0, 0, &Enumeration::comma); + os << "};"; + + // string() + // + os << "const char* " << name << "::" << endl + << ec.get ("string") << " () const" + << "{" + << "return _xsde_" << name << "_enumerators_[" << + ec.get ("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); } -- cgit v1.1