From bce9d5a76072ec697ef69021818aa68709036da5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 16 Mar 2009 08:16:43 +0200 Subject: Add support for type customization in C++/Hybrid examples/cxx/hybrid/custom/wildcard/: new example --- NEWS | 7 + dist/examples/cxx/hybrid/custom/makefile | 25 + dist/examples/cxx/hybrid/custom/nmakefile | 21 + dist/examples/cxx/hybrid/custom/wildcard/makefile | 56 +++ dist/examples/cxx/hybrid/custom/wildcard/nmakefile | 53 ++ dist/examples/cxx/hybrid/custom/wildcard/options | 8 + dist/examples/cxx/hybrid/makefile | 2 +- dist/examples/cxx/hybrid/nmakefile | 2 +- documentation/cxx/hybrid/guide/index.xhtml | 224 ++++++++- documentation/xsde.1 | 38 +- documentation/xsde.xhtml | 28 +- examples/cxx/hybrid/README | 6 + examples/cxx/hybrid/custom/README | 7 + examples/cxx/hybrid/custom/makefile | 45 ++ examples/cxx/hybrid/custom/wildcard/README | 83 ++++ examples/cxx/hybrid/custom/wildcard/body.cxx | 20 + examples/cxx/hybrid/custom/wildcard/body.hxx | 76 +++ examples/cxx/hybrid/custom/wildcard/driver.cxx | 185 +++++++ examples/cxx/hybrid/custom/wildcard/email.xml | 31 ++ examples/cxx/hybrid/custom/wildcard/email.xsd | 45 ++ .../cxx/hybrid/custom/wildcard/envelope-pimpl.cxx | 100 ++++ .../cxx/hybrid/custom/wildcard/envelope-pimpl.hxx | 78 +++ .../cxx/hybrid/custom/wildcard/envelope-simpl.cxx | 137 ++++++ .../cxx/hybrid/custom/wildcard/envelope-simpl.hxx | 67 +++ examples/cxx/hybrid/custom/wildcard/envelope.cxx | 11 + examples/cxx/hybrid/custom/wildcard/envelope.hxx | 39 ++ examples/cxx/hybrid/custom/wildcard/makefile | 124 +++++ examples/cxx/hybrid/makefile | 4 +- examples/cxx/hybrid/wildcard/README | 13 +- examples/cxx/hybrid/wildcard/envelope-pimpl.hxx | 2 +- xsde/cxx/hybrid/cli.hxx | 2 + xsde/cxx/hybrid/elements.cxx | 36 +- xsde/cxx/hybrid/elements.hxx | 11 + xsde/cxx/hybrid/extraction-header.cxx | 49 +- xsde/cxx/hybrid/extraction-source.cxx | 27 +- xsde/cxx/hybrid/generator.cxx | 31 +- xsde/cxx/hybrid/insertion-header.cxx | 49 +- xsde/cxx/hybrid/insertion-source.cxx | 27 +- xsde/cxx/hybrid/parser-name-processor.cxx | 15 +- xsde/cxx/hybrid/parser-source.cxx | 2 +- xsde/cxx/hybrid/serializer-name-processor.cxx | 14 +- xsde/cxx/hybrid/tree-forward.cxx | 60 ++- xsde/cxx/hybrid/tree-header.cxx | 540 ++++++++++++--------- xsde/cxx/hybrid/tree-inline.cxx | 33 +- xsde/cxx/hybrid/tree-name-processor.cxx | 194 +++++++- xsde/cxx/hybrid/tree-size-processor.cxx | 164 ++++++- xsde/cxx/hybrid/tree-size-processor.hxx | 2 +- xsde/cxx/hybrid/tree-source.cxx | 10 +- xsde/xsde.cxx | 22 +- 49 files changed, 2424 insertions(+), 401 deletions(-) create mode 100644 dist/examples/cxx/hybrid/custom/makefile create mode 100644 dist/examples/cxx/hybrid/custom/nmakefile create mode 100644 dist/examples/cxx/hybrid/custom/wildcard/makefile create mode 100644 dist/examples/cxx/hybrid/custom/wildcard/nmakefile create mode 100644 dist/examples/cxx/hybrid/custom/wildcard/options create mode 100644 examples/cxx/hybrid/custom/README create mode 100644 examples/cxx/hybrid/custom/makefile create mode 100644 examples/cxx/hybrid/custom/wildcard/README create mode 100644 examples/cxx/hybrid/custom/wildcard/body.cxx create mode 100644 examples/cxx/hybrid/custom/wildcard/body.hxx create mode 100644 examples/cxx/hybrid/custom/wildcard/driver.cxx create mode 100644 examples/cxx/hybrid/custom/wildcard/email.xml create mode 100644 examples/cxx/hybrid/custom/wildcard/email.xsd create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope-pimpl.cxx create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope-pimpl.hxx create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope-simpl.cxx create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope-simpl.hxx create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope.cxx create mode 100644 examples/cxx/hybrid/custom/wildcard/envelope.hxx create mode 100644 examples/cxx/hybrid/custom/wildcard/makefile diff --git a/NEWS b/NEWS index b1152ef..95ccd71 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,13 @@ Version 3.1.0 Started Guide as well as examples in the examples/cxx/hybrid/binary/ directory. + * New option, --custom-type, allows customization of the object model + classes. You have the option of either basing your custom implementation + on the generated version or providing your own implementation from + scratch. For details see Section 4.8, "Customizing the Object Model" + in the Getting Started Guide as well as examples in the + examples/cxx/hybrid/custom/ directory. + * New option, --generate-detach, triggers generation of detach functions for elements and attributes of variable-length types. These functions, for example, allow you to move sub-trees in the object model either diff --git a/dist/examples/cxx/hybrid/custom/makefile b/dist/examples/cxx/hybrid/custom/makefile new file mode 100644 index 0000000..029327d --- /dev/null +++ b/dist/examples/cxx/hybrid/custom/makefile @@ -0,0 +1,25 @@ +root := ../../../.. + +include $(root)/build/config.make + +dirs := + +ifeq ($(XSDE_IOSTREAM),y) +ifeq ($(XSDE_EXCEPTIONS),y) + +dirs += wildcard + +endif +endif + +.PHONY: all $(dirs) + +all: $(dirs) + +$(dirs): + @$(MAKE) -C $@ $(MAKECMDGOALS) + +makefile: ; +%.make:: ; + +%:: $(dirs) ; diff --git a/dist/examples/cxx/hybrid/custom/nmakefile b/dist/examples/cxx/hybrid/custom/nmakefile new file mode 100644 index 0000000..df8ad08 --- /dev/null +++ b/dist/examples/cxx/hybrid/custom/nmakefile @@ -0,0 +1,21 @@ +root = ..\..\..\.. + +!include $(root)\build\config.nmake + +dirs = + +!if "$(XSDE_IOSTREAM)" == "y" +!if "$(XSDE_EXCEPTIONS)" == "y" + +dirs = $(dirs) wildcard + +!endif +!endif + +all: + @for %i in ( $(dirs) ) do \ +@cmd /c "cd %i & $(MAKE) /nologo /f nmakefile" + +test clean: + @for %i in ( $(dirs) ) do \ +@cmd /c "cd %i & $(MAKE) /nologo /f nmakefile $@" diff --git a/dist/examples/cxx/hybrid/custom/wildcard/makefile b/dist/examples/cxx/hybrid/custom/wildcard/makefile new file mode 100644 index 0000000..e0a881d --- /dev/null +++ b/dist/examples/cxx/hybrid/custom/wildcard/makefile @@ -0,0 +1,56 @@ +root := ../../../../.. + +include $(root)/build/cxx/rules.make + +# Build. +# +EXTRA_CPPFLAGS := -I$(root)/libxsde + +ifeq ($(XSDE_LONGLONG),n) +EXTRA_XSDFLAGS += --no-long-long +endif + +ifeq ($(XSDE_PARSER_VALIDATION),n) +EXTRA_XSDFLAGS += --suppress-validation +endif + +ifeq ($(XSDE_REUSE_STYLE),mixin) +EXTRA_XSDFLAGS += --reuse-style-mixin +endif + +driver: driver.o email.o body.o email-pskel.o email-pimpl.o \ +email-sskel.o email-simpl.o envelope-pimpl.o envelope-simpl.o \ +$(root)/libxsde/xsde/libxsde.a + +driver.o: driver.cxx email.hxx envelope.hxx body.hxx email-pimpl.hxx email-simpl.hxx +email.o: email.cxx email.hxx envelope.hxx +body.o: body.cxx body.hxx email.hxx +email-pskel.o: email-pskel.cxx +email-pimpl.o: email-pimpl.cxx +email-simpl.o: email-simpl.cxx +email-simpl.o: email-simpl.cxx +envelope-pimpl.o: envelope-pimpl.cxx envelope-pimpl.hxx email.hxx body.hxx +envelope-simpl.o: envelope-simpl.cxx envelope-simpl.hxx email.hxx body.hxx + +.PRECIOUS: %.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx \ +%-sskel.hxx %-sskel.cxx %-simpl.hxx %-simpl.cxx + +%.hxx %.cxx %-pskel.hxx %-pskel.cxx %-pimpl.hxx %-pimpl.cxx \ +%-sskel.hxx %-sskel.cxx %-simpl.hxx %-simpl.cxx: %.xsd + $(root)/bin/xsde cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--options-file options $< + +# Test. +# +.PHONY: test +test: driver email.xml + ./driver email.xml + +# Clean. +# +.PHONY: clean +clean: + rm -f email-pimpl.?xx email-pskel.?xx email-simpl.?xx \ +email-sskel.?xx email.?xx envelope-pimpl.o envelope-simpl.o \ +email-pimpl.o email-pskel.o email-simpl.o email-sskel.o \ +body.o email.o driver.o driver diff --git a/dist/examples/cxx/hybrid/custom/wildcard/nmakefile b/dist/examples/cxx/hybrid/custom/wildcard/nmakefile new file mode 100644 index 0000000..0a88820 --- /dev/null +++ b/dist/examples/cxx/hybrid/custom/wildcard/nmakefile @@ -0,0 +1,53 @@ +root = ..\..\..\..\.. + +!include $(root)\build\cxx\rules.nmake + +# Build. +# +EXTRA_CPPFLAGS = /I$(root)\libxsde + +!if "$(XSDE_LONGLONG)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --no-long-long +!endif + +!if "$(XSDE_PARSER_VALIDATION)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation +!endif + +!if "$(XSDE_REUSE_STYLE)" == "mixin" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin +!endif + +driver.exe: driver.obj email.obj body.obj email-pskel.obj email-pimpl.obj \ +email-sskel.obj email-simpl.obj envelope-pimpl.obj envelope-simpl.obj \ +$(root)\libxsde\xsde\xsde.lib + +driver.obj: driver.cxx email.hxx envelope.hxx body.hxx email-pimpl.hxx email-simpl.hxx +email.obj: email.cxx email.hxx envelope.hxx +body.obj: body.cxx body.hxx email.hxx +email-pskel.obj: email-pskel.cxx +email-pimpl.obj: email-pimpl.cxx +email-simpl.obj: email-simpl.cxx +email-simpl.obj: email-simpl.cxx +envelope-pimpl.obj: envelope-pimpl.cxx envelope-pimpl.hxx email.hxx body.hxx +envelope-simpl.obj: envelope-simpl.cxx envelope-simpl.hxx email.hxx body.hxx + +email.cxx email.hxx \ +email-pskel.cxx email-pskel.hxx email-pimpl.cxx email-pimpl.hxx \ +email-sskel.cxx email-sskel.hxx email-simpl.cxx email-simpl.hxx \ +: email.xsd + $(root)\bin\xsde.exe cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--options-file options email.xsd + +# Test. +# +test: driver.exe email.xml + .\driver.exe email.xml + +# Clean. +# +clean: + -del email-pimpl.?xx email-pskel.?xx email-simpl.?xx \ +email-sskel.?xx email.?xx envelope-pimpl.obj envelope-simpl.obj \ +email-pimpl.obj email-pskel.obj email-simpl.obj email-sskel.obj \ +body.obj email.obj driver.obj driver.exe diff --git a/dist/examples/cxx/hybrid/custom/wildcard/options b/dist/examples/cxx/hybrid/custom/wildcard/options new file mode 100644 index 0000000..688bf0c --- /dev/null +++ b/dist/examples/cxx/hybrid/custom/wildcard/options @@ -0,0 +1,8 @@ +--generate-parser +--generate-serializer +--generate-aggregate +--root-element-all +--custom-type envelope=v//envelope_base/envelope.hxx +--custom-parser envelope=envelope_base_pimpl/envelope-pimpl.hxx +--custom-serializer envelope=envelope_base_simpl/envelope-simpl.hxx +--hxx-epilogue #include "body.hxx" diff --git a/dist/examples/cxx/hybrid/makefile b/dist/examples/cxx/hybrid/makefile index 38ccd04..11af66b 100644 --- a/dist/examples/cxx/hybrid/makefile +++ b/dist/examples/cxx/hybrid/makefile @@ -2,7 +2,7 @@ root := ../../.. include $(root)/build/config.make -dirs := binary compositors +dirs := binary compositors custom ifeq ($(XSDE_IOSTREAM),y) ifeq ($(XSDE_EXCEPTIONS),y) diff --git a/dist/examples/cxx/hybrid/nmakefile b/dist/examples/cxx/hybrid/nmakefile index 5d0b337..d9d791c 100644 --- a/dist/examples/cxx/hybrid/nmakefile +++ b/dist/examples/cxx/hybrid/nmakefile @@ -2,7 +2,7 @@ root = ..\..\.. !include $(root)\build\config.nmake -dirs = compositors +dirs = binary compositors custom !if "$(XSDE_IOSTREAM)" == "y" !if "$(XSDE_EXCEPTIONS)" == "y" diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml index 2aa9a19..3586264 100644 --- a/documentation/cxx/hybrid/guide/index.xhtml +++ b/documentation/cxx/hybrid/guide/index.xhtml @@ -3102,21 +3102,30 @@ main ()

4.8 Customizing the Object Model

-

Sometimes it is desirable to be able to store extra, - application-specific data in some object model classes or - nested compositor classes. Cases where this functionality - may be required include handling of typeless content - matched by XML Schema wildcards as well as a need for - an application to pass extra data as part of the object - model. The C++/Hybrid mapping provides a light-weight - mechanism for storing custom data by allowing you to add - a sequence of opaque objects, stored as void*, - to select generated classes. It is also possible to - customize the parsing and serialization code for such - classes in order to populate the custom data sequence - during parsing and later serialize it to XML. See +

Sometimes it is desirable to add extra, application-specific + data or functionality to some object model classes or + nested compositor classes. Cases where this may be required + include handling of typeless content matched by XML Schema + wildcards as well as a need for an application to pass extra + data or provide custom functions as part of the object model. + The C++/Hybrid mapping provides two mechanisms for accomplishing + this: custom data and custom types. Custom data is a light-weight + mechanism for storing application-specific data by allowing you + to add a sequence of opaque objects, stored as void*, + to select generated classes. Type customization is a more + powerful mechanism that allows you to provide custom implementations + for select object model classes. You have the option of either extending + the generated version of the class (for example, by adding extra data + members and/or functions) or providing your own implementation from + scratch. The latter approach essentially allows you to change the + mapping of XML Schema to C++ on a case by case basis.

+ +

It is also possible to customize the parsing and serialization code, + for example, to populate the custom data sequence or custom data + members during parsing and later serialize them to XML. See Section 6.1, "Customizing Parsers and - Serializers" for details.

+ Serializers" for details. The remainder of this section discusses + the custom data and custom types mechanisms in more detail.

To instruct the XSD/e compiler to include custom data in a specific object model class, we need to use the @@ -3126,12 +3135,12 @@ main () name starting with the XML Schema type, for example type::sequence1. If we would like to add the ability to store custom data in the generated - person class for our person records + person class from our person records vocabulary, we can compile people.xsd like this:

-$ xsde cxx-hybrid --custom-type person people.xsd
+$ xsde cxx-hybrid --custom-data person people.xsd
   

The resulting person class will have the @@ -3336,6 +3345,178 @@ for (person::custom_data_iterator i = cd.begin (); i != cd.end (); ++i) } +

To instruct the XSD/e compiler to use a custom implementation + for a specific object model class, we need to use the + --custom-type option. The argument format for this + option is name[=[flags][/[type][/[base][/include]]]]. + The name component is the XML Schema type name being + customized. Optional flags allow you to specify whether + the custom class is fixed or variable-length since customization can + alter this property, normally from fixed-length to + variable-length. The f flag indicates the type is + fixed-length and the v flag indicates the type is + variable-length. If omitted, the default rules are used to determine + the type length (see Section 4.2, "Memory Management"). + + Optional type is a C++ type name, potentially qualified, + that should be used as a custom implementation. If specified, the + object model type is defined as a typedef alias for + this C++ type. Optional base is a C++ name that should + be given to the generated version. It is normally used as a base for + the custom implementation. Optional include is the header + file that defines the custom implementation. It is #include'ed + into the generated code immediately after (if base is + specified) or instead of the generated version. The following + examples show how we can use this option:

+ +
+--custom-type foo
+--custom-type foo=///foo.hxx
+--custom-type foo=v///foo.hxx
+--custom-type foo=f/int
+--custom-type foo=//foo_base/my/foo.hxx
+--custom-type foo=v/wrapper<foo_base>/foo_base
+  
+ +

The first version instructs the XSD/e compiler not to generate + the object model class for the foo XML Schema + type. The generated code simply forward-declares foo + as a class and leaves it to you to provide the implementation. + + The second version is similar to the first, except now we specify + the header file which defines the custom implementation. + This file is automatically included into the generated header + file instead of the standard implementation. + + The third version is similar to the second, except now we specify + that the foo type is variable-length. In the previous + two cases the type length was determined automatically based on the + type definition in the schema. + + In the fourth version we specify that schema type foo + is fixed-length and should be mapped to int. + + The fifth version instructs the XSD/e compiler to generate + the object model class for type foo but call it + foo_base. It also tells the compiler to generate + the #include directive with the my/foo.hxx + file (which presumably defines foo) right after the + foo_base class. + + Finally, the last version specifies that schema type foo + is variable-length and should be mapped to wrapper<foo_base>. + The compiler is also instructed to generate the standard object + model class for type foo but call it foo_base. + + If you omit the last component (include), as in the + final version, then you can provide the custom type definitions using + one of the prologue or epilogue XSD/e compiler options. See the + XSD/e + Compiler Command Line Manual for details.

+ +

Note also that if the type length you specified with the + --custom-type option differs from the default type + length that would have been determined by the XSD/e compiler, + then you need to specify this --custom-type option + when compiling every schema file that includes or imports the + schema that defines the type being customized.

+ +

As an example, let us add a flag to the person class + from our person records vocabulary. This flag can be used by the + application to keep track of whether a particular person record + has been verified. To customize the person type we + can compile people.xsd like this:

+ +
+$ xsde cxx-hybrid --custom-type person=//person_base/person.hxx \
+people.xsd
+  
+ +

The relevant code fragment from the generated header file + looks like this:

+ +
+// person_base (fixed-length)
+//
+class person_base
+{
+  ...
+};
+
+#include "person.hxx"
+
+// people (variable-length)
+//
+class people
+{
+  ...
+
+  // person
+  //
+  typedef xsde::fix_sequence<person> person_sequence;
+  typedef person_sequence::iterator person_iterator;
+  typedef person_sequence::const_iterator person_const_iterator;
+
+  const person_sequence&
+  person () const;
+
+  person_sequence&
+  person ();
+
+private:
+  ...
+};
+  
+ +

We base our custom implementation of the person + class on generated person_base and save it to + person.hxx:

+ +
+class person: public person_base
+{
+public:
+  person ()
+    : verified_ (false)
+  {
+  }
+
+  bool
+  verified () const
+  {
+    return verified_;
+  }
+
+  void
+  verified (bool v)
+  {
+    verified_ = v;
+  }
+
+private:
+  bool verified_;
+};
+  
+ +

The client code can use our custom implementation as if the + flag was part of the vocabulary:

+ +
+people::person_sequence& ps = ...;
+
+for (people::person_iterator i = ps.begin (); i != ps.end (); ++i)
+{
+  if (!i->verified ())
+  {
+    // Verify the record.
+
+    ...
+
+    i->verified (true);
+  }
+}
+  
+ @@ -4868,13 +5049,13 @@ hello_s.post (); implementation, you will need to specify the --custom-parser or --custom-serializer option, respectively. The argument format for these two options - is type[=base[/include]]. The type + is name[=[base][/include]]]. The name component is the XML Schema type name being customized. Optional - base is a C++ name that should be given to the + base is a C++ name that should be given to the generated version. It is normally used as a base for the custom - implementation. Optional include is the header file + implementation. Optional include is the header file that defines the custom implementation. It is #include'ed - into the generated code immediately after (if base + into the generated code immediately after (if base is specified) or instead of the generated version. The following examples show how we can use these options:

@@ -4896,7 +5077,8 @@ hello_s.post (); foo_base_pimpl class. The last version instructs the XSD/e compiler to include foo/foo-custom.hxx instead of generating the parser implementation for - foo. If you omit the last component, then + foo. If you omit the last component + (include), then you can include the custom parser/serializer definitions using one of the prologue or epilogue XSD/e compiler options. See the XSD/e diff --git a/documentation/xsde.1 b/documentation/xsde.1 index e66dcaa..f9fe998 100644 --- a/documentation/xsde.1 +++ b/documentation/xsde.1 @@ -1021,10 +1021,36 @@ name starting from the XML Schema type containing the compositor, for example, .BR foo::sequence::choise1 . -.IP "\fB\--custom-parser \fItype\fR[\fB=\fIbase\fR[\fB/\fIinclude\fR]]" +.IP "\fB\--custom-type \fIname\fR[\fB=\fR[\fIflags\fR][\fB/\fR[\fIbase\fR][\fB/\fR[\fItype\fR][\fB/\fIinclude\fR]]]]" +Use a custom type implementation instead of the generated version. The +.I name +component is the XML Schema type name being customized. Optional +.I flags +allow you to specify whether the custom type is fixed or variable-length. The +.B f +flag indicates the type is fixed-length and the +.B v +flag indicates the type is variable-length. If omitted, the default rules +are used to determine the type length. Optional +.I type +is a C++ type name that should be used instead. If specified, the object +model type is defined as a +.B typedef +alias for this C++ type. Optional +.I base +is a C++ name that should be given to the generated version. It is normally +used as a base for the custom implementation. Optional +.I include +is the header file that defines the custom implementation. It is +.BR #include 'ed +into the generated code immediately after (if +.I base +is specified) or instead of the generated version. + +.IP "\fB\--custom-parser \fIname\fR[\fB=\fR[\fIbase\fR][\fB/\fIinclude\fR]]" Use a custom parser implementation instead of the generated version. The -.I type +.I name component is the XML Schema type name being customized. Optional .I base is a C++ name that should be given to the generated version. It is @@ -1033,13 +1059,13 @@ normally used as a base for the custom implementation. Optional is the header file that defines the custom implementation. It is .BR #include 'ed into the generated code immediately after (if -.B base +.I base is specified) or instead of the generated version. -.IP "\fB\--custom-serializer \fItype\fR[\fB=\fIbase\fR[\fB/\fIinclude\fR]]" +.IP "\fB\--custom-serializer \fIname\fR[\fB=\fR[\fIbase\fR][\fB/\fIinclude\fR]]" Use a custom serializer implementation instead of the generated version. The -.I type +.I name component is the XML Schema type name being customized. Optional .I base is a C++ name that should be given to the generated version. It is @@ -1048,7 +1074,7 @@ normally used as a base for the custom implementation. Optional is the header file that defines the custom implementation. It is .BR #include 'ed into the generated code immediately after (if -.B base +.I base is specified) or instead of the generated version. .IP "\fB\--root-element-first\fR" diff --git a/documentation/xsde.xhtml b/documentation/xsde.xhtml index 330bb96..312d5f9 100644 --- a/documentation/xsde.xhtml +++ b/documentation/xsde.xhtml @@ -885,10 +885,30 @@ starting from the XML Schema type containing the compositor, for example, foo::sequence::choise1. +
--custom-type + name[=[flags][/[type][/[base][/include]]]]
+
Use a custom type implementation instead of the generated version. + The name component is the XML Schema type name + being customized. Optional flags allow you to + specify whether the custom type is fixed or variable-length. The + f flag indicates the type is fixed-length and + the v flag indicates the type is variable-length. + If omitted, the default rules are used to determine the type length. + Optional type is a C++ type name that should + be used instead. If specified, the object model type is defined + as a typedef alias for this C++ type. Optional + base is a C++ name that should be given to the + generated version. It is normally used as a base for the custom + implementation. Optional include is the header + file that defines the custom implementation. It is + #include'ed into the generated code immediately + after (if base is specified) or instead of the + generated version.
+
--custom-parser - type[=base[/include]]
+ name[=[base][/include]]
Use a custom parser implementation instead of the generated version. - The type component is the XML Schema type name + The name component is the XML Schema type name being customized. Optional base is a C++ name that should be given to the generated version. It is normally used as a base for the custom implementation. Optional @@ -898,9 +918,9 @@ is specified) or instead of the generated version.
--custom-serializer - type[=base[/include]]
+ name[=[base][/include]]
Use a custom serializer implementation instead of the generated version. - The type component is the XML Schema type name + The name component is the XML Schema type name being customized. Optional base is a C++ name that should be given to the generated version. It is normally used as a base for the custom implementation. Optional diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README index 2008450..d23c10d 100644 --- a/examples/cxx/hybrid/README +++ b/examples/cxx/hybrid/README @@ -36,6 +36,12 @@ compositors Shows how to create, access, and modify object models with complex nested choice and sequence compositors. +custom/ + A collection of examples that show how to customize the C++/Hybrid + object model by using custom C++ classes instead of or in addition + to the generated ones. See the accompanying README file for an + overview of each example in this directory. + binary/ A collection of examples that show how to serialize the object model into a number of predefined and custom binary formats. diff --git a/examples/cxx/hybrid/custom/README b/examples/cxx/hybrid/custom/README new file mode 100644 index 0000000..bf0bfac --- /dev/null +++ b/examples/cxx/hybrid/custom/README @@ -0,0 +1,7 @@ +This directory contains a number of examples that show how to customize +the C++/Hybrid object model. The following list gives an overview of +each example: + +wildcard + Shows how to parse, store in the object model, and serialize XML data + matched by XML Schema wildcards (any and anyAttribute). diff --git a/examples/cxx/hybrid/custom/makefile b/examples/cxx/hybrid/custom/makefile new file mode 100644 index 0000000..856a9fe --- /dev/null +++ b/examples/cxx/hybrid/custom/makefile @@ -0,0 +1,45 @@ +# file : examples/cxx/hybrid/custom/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 + +all_examples := wildcard +build_examples := + +ifeq ($(xsde_iostream),y) +ifeq ($(xsde_exceptions),y) + +build_examples += wildcard + +endif +endif + +default := $(out_base)/ +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean := $(out_base)/.clean + +.PHONY: $(default) $(dist) $(dist-win) $(clean) + +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(build_examples))) +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(build_examples))) + +# Dist. +# +$(dist) $(dist-win): path := $(subst $(src_root)/,,$(src_base)) + +$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(all_examples))) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(addprefix $(out_base)/,$(addsuffix /.dist-win,$(all_examples))) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) + $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt) + + +ifneq ($(filter $(MAKECMDGOALS),dist dist-win),) +$(foreach e,$(all_examples),$(call import,$(src_base)/$e/makefile)) +else +$(foreach e,$(build_examples),$(call import,$(src_base)/$e/makefile)) +endif diff --git a/examples/cxx/hybrid/custom/wildcard/README b/examples/cxx/hybrid/custom/wildcard/README new file mode 100644 index 0000000..e8ef1b8 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/README @@ -0,0 +1,83 @@ +This example shows how to parse, store in the object model, and serialize +XML data matched by XML Schema wildcards (any and anyAttribute) using the +Embedded C++/Hybrid. + +This example uses the object model as well as parser and serializer +customization mechanisms provided by the C++/Hybrid mapping. For more +information, see Section 4.8, "Customizing the Object Model" and Section +6.1, "Customizing Parsers and Serializers" in the Embedded C++/Hybrid +Mapping Getting Started Guide. + +The example consists of the following files: + +email.xsd + XML Schema which describes a simple email format with the + extensible envelope type. + +email.xml + Sample email message. + +email.hxx +email.cxx + +email-pskel.hxx +email-pskel.cxx +email-pimpl.hxx +email-pimpl.cxx + +email-pskel.hxx +email-pskel.cxx +email-pimpl.hxx +email-pimpl.cxx + Object model (the first pair of files), parser skeletons (the + second pair), parser implementations (the third pair), serializer + skeletons (the fourth pair), and serializer implementations (the + fifth pair). These files are generated by the XSD/e compiler from + email.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation of + the parsing and serialization code. The --custom-type option was + used to customize the the envelope class in the object model. The + --custom-parser option was used to customize the envelope_pimpl + parser implementation. The --custom-serializer option was used to + customize the envelope_simpl serializer implementation. Finally, + the --hxx-epilogue option was used to include body.hxx (see below) + at the end of the generated object model header file. + +body.hxx +body.cxx + Implementation of the body class. It is used to store the wildcard + data in the body sequence of the customized envelope class. + +envelope.hxx +envelope.cxx + Custom envelope type. It uses the generated version as a base and + adds a data member as well as accessor and modifier functions for + the wildcard content. + +envelope-pimpl.hxx +envelope-pimpl.cxx + Custom envelope parser implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the wildcard + callbacks to parse the wildcard content and store in the body sequence + of the customized envelope object. + +envelope-simpl.hxx +envelope-simpl.cxx + Custom envelope serializer implementation. It uses the implementation + generated by the XSD/e compiler as a base and overrides the wildcard + callbacks to serialize the wildcard content stored in the body sequence + of the customized envelope object. + +driver.cxx + Driver for the example. It first calls the parser that constructs the + email object from the input XML file. It then prints the content of + the email to STDERR. Finally, the driver creates a reply email and + calls the serializer to serialize it to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver email.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver +// copyright : not copyrighted - public domain + +#include "body.hxx" + +namespace email +{ + void body:: + body_type (body::type t) + { + if (body_type_ == type_binary) + { + delete binary_; + binary_ = 0; + } + + body_type_ = t; + } +} diff --git a/examples/cxx/hybrid/custom/wildcard/body.hxx b/examples/cxx/hybrid/custom/wildcard/body.hxx new file mode 100644 index 0000000..504e3ca --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/body.hxx @@ -0,0 +1,76 @@ +// file : examples/cxx/hybrid/custom/wildcard/body.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef BODY_HXX +#define BODY_HXX + +#include "email.hxx" + +namespace email +{ + // Custom email body type which can hold text or binary. + // + class body + { + public: + enum type + { + type_none, + type_text, + type_binary + }; + + body () + : body_type_ (type_none), binary_ (0) + { + } + + ~body () + { + body_type (type_none); + } + + type + body_type () const + { + return body_type_; + } + + const std::string& + text () const + { + return text_; + } + + void + text (const std::string& t) + { + body_type (type_text); + text_ = t; + } + + const email::binary& + binary () const + { + return *binary_; + } + + void + binary (email::binary* b) + { + body_type (type_binary); + binary_ = b; + } + + private: + void + body_type (type t); + + type body_type_; + std::string text_; + email::binary* binary_; + }; +} + +#endif // BODY_HXX diff --git a/examples/cxx/hybrid/custom/wildcard/driver.cxx b/examples/cxx/hybrid/custom/wildcard/driver.cxx new file mode 100644 index 0000000..02870fa --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/driver.cxx @@ -0,0 +1,185 @@ +// file : examples/cxx/hybrid/custom/wildcard/driver.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#include // memcpy +#include // std::auto_ptr +#include + +#include "email.hxx" + +#include "email-pimpl.hxx" +#include "email-simpl.hxx" + +using namespace std; + +// Extended parser and serializer aggregates for the message +// element. They add parser/serializer aggregates for the +// wildcard elements. +// +namespace email +{ + class message_paggr_ex: public message_paggr + { + public: + message_paggr_ex () + { + envelope_p_.text_parser (text_p_.root_parser ()); + envelope_p_.binary_parser (binary_p_.root_parser ()); + } + + public: + text_paggr text_p_; + binary_paggr binary_p_; + }; + + class message_saggr_ex: public message_saggr + { + public: + message_saggr_ex () + { + envelope_s_.text_serializer (text_s_.root_serializer ()); + envelope_s_.binary_serializer (binary_s_.root_serializer ()); + } + + public: + text_saggr text_s_; + binary_saggr binary_s_; + }; +} + +int +main (int argc, char* argv[]) +{ + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + using namespace email; + + // Parse. + // + message_paggr_ex message_p; + + xml_schema::document_pimpl doc_p ( + message_p.root_parser (), + message_p.root_namespace (), + message_p.root_name ()); + + message_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr msg (message_p.post ()); + + // Print what we've got. + // + cerr << "To: " << msg->to () << endl + << "From: " << msg->from () << endl + << "Subject: " << msg->subject () << endl; + + envelope::body_sequence& body_seq (msg->body ()); + + for (envelope::body_iterator i = body_seq.begin (); + i != body_seq.end (); + ++i) + { + body& b = *i; + + switch (b.body_type ()) + { + case body::type_text: + { + cerr << b.text () << endl + << endl; + break; + } + case body::type_binary: + { + const binary& bin = b.binary (); + cerr << "binary: " << bin.name () << " " + << "type: " << bin.mime () << endl + << endl; + break; + } + default: + { + cerr << "unexpected body type" << endl; + break; + } + } + } + + // Create a reply message. + // + auto_ptr reply (new envelope); + reply->to (msg->from ()); + reply->from (msg->to ()); + reply->subject ("Re: " + msg->subject ()); + + // Add a text body. + // + auto_ptr b (new body); + b->text ("Hi!\n\n" + "Indeed nice pictures. Check out mine.\n\n" + "Jane"); + reply->body ().push_back (b.release ()); + + // Add a (fake) image. + // + auto_ptr pic (new binary); + pic->name ("pic.jpg"); + pic->mime ("image/jpeg"); + pic->size (3); + memcpy (pic->data (), "123", 3); + + b = auto_ptr (new body); + b->binary (pic.release ()); + reply->body ().push_back (b.release ()); + + // Serialize. + // + message_saggr_ex message_s; + + xml_schema::document_simpl doc_s ( + message_s.root_serializer (), + message_s.root_namespace (), + message_s.root_name ()); + + doc_s.add_prefix ("lib", "http://www.codesynthesis.com/email"); + doc_s.add_schema ("http://www.codesynthesis.com/email", "email.xsd"); + + message_s.pre (*reply); + doc_s.serialize (cout); + message_s.post (); + } + catch (const xml_schema::parser_exception& e) + { + cerr << input << ":" << e.line () << ":" << e.column () << ": " + << e.text () << endl; + return 1; + } + catch (const xml_schema::serializer_exception& e) + { + cerr << "error: " << e.text () << endl; + return 1; + } + catch (const std::ios_base::failure&) + { + cerr << input << ": unable to open or read/write failure" << endl; + return 1; + } + + return 0; +} diff --git a/examples/cxx/hybrid/custom/wildcard/email.xml b/examples/cxx/hybrid/custom/wildcard/email.xml new file mode 100644 index 0000000..4385d15 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/email.xml @@ -0,0 +1,31 @@ + + + + + + + Jane Doe <jane@doe.com> + John Doe <john@doe.com> + Surfing pictures + + +Hi Jane, + +Here are cool pictures of me surfing. + +Cheers, +John + + + YmFzZTY0IGJpbmFyeQ== + YmFzZTY0IGJpbmFyeQ== + + diff --git a/examples/cxx/hybrid/custom/wildcard/email.xsd b/examples/cxx/hybrid/custom/wildcard/email.xsd new file mode 100644 index 0000000..310f287 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/email.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.cxx b/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.cxx new file mode 100644 index 0000000..eee573f --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.cxx @@ -0,0 +1,100 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope-pimpl.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#include // std::auto_ptr + +#include "body.hxx" + +// Include email-pimpl.hxx (which includes envelope-pimpl.hxx) +// instead of envelope-pimpl.hxx. +// +#include "email-pimpl.hxx" + +namespace email +{ + void envelope_pimpl:: +#ifndef XSDE_POLYMORPHIC + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name) +#else + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char*) +#endif + { + // We use the depth_ counter to filter out nested elements + // and attributes for the content matched by the wildcard + // but which we don't know how to handle. + // + if (depth_++ == 0) + { + // Top-level (relative to this type) element matched by the + // any wildcard. + // + xml_schema::parser_base* p = 0; + + if (ns == "http://www.codesynthesis.com/email") + { + if (name == "text") + p = text_p_; + else if (name == "binary") + p = binary_p_; + + if (p != 0) + { + // If you are not using exceptions then you will need to add + // error propagation code. For more information on how to do + // this see the wildcard example for the C++/Parser mapping + // (examples/parser/ directory). + // + xml_schema::parser_context& ctx = _context (); + p->pre (); + p->_pre_impl (ctx); + } + } + } + } + + void envelope_pimpl:: + _end_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name) + { + if (--depth_ == 0) + { + if (ns == "http://www.codesynthesis.com/email") + { + // Note that we don't call _post_impl() (corresponding to + // _pre_impl()) here. It is called automatically by the + // infrastructure. + // + envelope* env = envelope_base_pimpl_state_.envelope_; + + if (name == "text") + { + std::auto_ptr b (new body); + b->text (text_p_->post_string ()); + env->body ().push_back (b.release ()); + } + else if (name == "binary") + { + std::auto_ptr b (new body); + b->binary (binary_p_->post_binary ()); + env->body ().push_back (b.release ()); + } + } + } + } + + void envelope_pimpl:: + _reset () + { + // Note that we always need to call _reset() from the base. + // + envelope_base_pimpl::_reset (); + + depth_ = 0; + text_p_->_reset (); + binary_p_->_reset (); + } +} diff --git a/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.hxx b/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.hxx new file mode 100644 index 0000000..5443ee1 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope-pimpl.hxx @@ -0,0 +1,78 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope-pimpl.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef ENVELOPE_PIMPL_HXX +#define ENVELOPE_PIMPL_HXX + +namespace email +{ + // Customized envelope parser implementation. All wildcard events are + // routed to the _start_any_element, _end_any_element, _any_attribute, + // and _any_characters functions. We can dynamically select a parser + // from the _start_any_element after which all inner content will be + // automatically routed to this parser. At the end we will get a call + // to _end_any_element in which we can call post() and save the data. + // + class envelope_pimpl: public envelope_base_pimpl + { + public: + envelope_pimpl () + : depth_ (0), text_p_ (0), binary_p_ (0) + { + } + + // Additional parsers for the wildcard content. + // + void + text_parser (xml_schema::string_pskel& p) + { + text_p_ = &p; + } + + void + binary_parser (binary_pskel& p) + { + binary_p_ = &p; + } + + public: + // If the XSD runtime library was configured with polymorphism + // support, then _start_any_element has a third argument which + // is a dynamic type id that comes from xsi:type or substitution + // groups. + // +#ifndef XSDE_POLYMORPHIC + virtual void + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); +#else + virtual void + _start_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name, + const char*); +#endif + + virtual void + _end_any_element (const xml_schema::ro_string& ns, + const xml_schema::ro_string& name); + + // If we need to be able to reset and reuse the parser after + // an error then we also need to override _reset() and reset + // the parsers that are used to handle wildcards. + // + virtual void + _reset (); + + private: + std::size_t depth_; + + // Parsers for the text and binary elements. + // + private: + xml_schema::string_pskel* text_p_; + binary_pskel* binary_p_; + }; +} + +#endif // ENVELOPE_PIMPL_HXX diff --git a/examples/cxx/hybrid/custom/wildcard/envelope-simpl.cxx b/examples/cxx/hybrid/custom/wildcard/envelope-simpl.cxx new file mode 100644 index 0000000..b6d9f89 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope-simpl.cxx @@ -0,0 +1,137 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope-simpl.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#include "body.hxx" + +// Include email-simpl.hxx (which includes envelope-simpl.hxx) +// instead of envelope-simpl.hxx. +// +#include "email-simpl.hxx" + +namespace email +{ + void envelope_simpl:: + _pre () + { + // Initialize the body iterator. + // + i_ = envelope_base_simpl_state_.envelope_->body ().begin (); + } + + bool envelope_simpl:: + any_next () + { + envelope::body_const_iterator end ( + envelope_base_simpl_state_.envelope_->body ().end ()); + + // See if there is a body that we know how to serialize. + // + for (; i_ != end; ++i_) + { + body::type t = i_->body_type (); + + if (t == body::type_text || t == body::type_binary) + break; + } + + return i_ != end; + } + + void envelope_simpl:: + any (std::string& ns, std::string& name) + { + ns = "http://www.codesynthesis.com/email"; + + switch (i_->body_type ()) + { + case body::type_text: + { + name = "text"; + break; + } + case body::type_binary: + { + name = "binary"; + break; + } + default: + break; + } + } + + void envelope_simpl:: + serialize_any () + { + xml_schema::serializer_base* s = 0; + const body& b = *i_++; + + // If you are not using exceptions then you will need to add + // error propagation code. For more information on how to do + // this see the wildcard example for the C++/Parser mapping + // (examples/parser/ directory). + // + switch (b.body_type ()) + { + case body::type_text: + { + text_s_->pre (b.text ()); + s = text_s_; + break; + } + case body::type_binary: + { + binary_s_->pre (b.binary ()); + s = binary_s_; + break; + } + default: + break; + } + + if (s != 0) + { + // If XML Schema validation is enabled then we need to check + // for error conditions. + // + xml_schema::serializer_context& ctx = _context (); + + s->_pre_impl (ctx); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_serialize_attributes (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_serialize_content (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->_post_impl (); + +#ifdef XSDE_SERIALIZER_VALIDATION + if (ctx.error_type ()) + return; +#endif + s->post (); + } + } + + void envelope_simpl:: + _reset () + { + text_s_->_reset (); + binary_s_->_reset (); + + // Note that we always need to call _reset() from the base. + // + envelope_base_simpl::_reset (); + } +} diff --git a/examples/cxx/hybrid/custom/wildcard/envelope-simpl.hxx b/examples/cxx/hybrid/custom/wildcard/envelope-simpl.hxx new file mode 100644 index 0000000..bb2f546 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope-simpl.hxx @@ -0,0 +1,67 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope-simpl.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef ENVELOPE_SIMPL_HXX +#define ENVELOPE_SIMPL_HXX + +namespace email +{ + // Customized envelope serializer implementation. Here we implement + // the any_next, any, and serialize_any callbacks to serialize the + // wildcard content. + // + class envelope_simpl: public envelope_base_simpl + { + public: + envelope_simpl () + : text_s_ (0), binary_s_ (0) + { + } + + // Additional serializers for the wildcard content. + // + void + text_serializer (xml_schema::string_sskel& s) + { + text_s_ = &s; + } + + void + binary_serializer (binary_sskel& s) + { + binary_s_ = &s; + } + + public: + virtual void + _pre (); + + virtual bool + any_next (); + + virtual void + any (std::string& ns, std::string& name); + + virtual void + serialize_any (); + + // If we need to be able to reset and reuse the serializer + // after an error then we also need to override _reset() and + // reset the serializers that are used to handle wildcards. + // + virtual void + _reset (); + + private: + envelope::body_const_iterator i_; + + // Serializers for the text and binary elements. + // + private: + xml_schema::string_sskel* text_s_; + binary_sskel* binary_s_; + }; +} + +#endif // ENVELOPE_SIMPL_HXX diff --git a/examples/cxx/hybrid/custom/wildcard/envelope.cxx b/examples/cxx/hybrid/custom/wildcard/envelope.cxx new file mode 100644 index 0000000..bec57a3 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope.cxx @@ -0,0 +1,11 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +// Include email.hxx (which includes envelope.hxx) instead of envelope.hxx. +// +#include "email.hxx" + +namespace email +{ +} diff --git a/examples/cxx/hybrid/custom/wildcard/envelope.hxx b/examples/cxx/hybrid/custom/wildcard/envelope.hxx new file mode 100644 index 0000000..56abedd --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/envelope.hxx @@ -0,0 +1,39 @@ +// file : examples/cxx/hybrid/custom/wildcard/envelope.hxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#ifndef ENVELOPE_HXX +#define ENVELOPE_HXX + +namespace email +{ + // Customized envelope type. It adds a sequence of body objects + // to the generated version. + // + class body; + + class envelope: public envelope_base + { + public: + typedef xml_schema::var_seq body_sequence; + typedef body_sequence::iterator body_iterator; + typedef body_sequence::const_iterator body_const_iterator; + + const body_sequence& + body () const + { + return body_; + } + + body_sequence& + body () + { + return body_; + } + + private: + body_sequence body_; + }; +} + +#endif // ENVELOPE_HXX diff --git a/examples/cxx/hybrid/custom/wildcard/makefile b/examples/cxx/hybrid/custom/wildcard/makefile new file mode 100644 index 0000000..dd32b82 --- /dev/null +++ b/examples/cxx/hybrid/custom/wildcard/makefile @@ -0,0 +1,124 @@ +# file : examples/cxx/hybrid/custom/wildcard/makefile +# author : Boris Kolpackov +# copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := email.xsd +cxx := driver.cxx body.cxx envelope-pimpl.cxx envelope-simpl.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 +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): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --root-element-all \ +--custom-type envelope=v//envelope_base/envelope.hxx \ +--custom-parser envelope=envelope_base_pimpl/envelope-pimpl.hxx \ +--custom-serializer envelope=envelope_base_simpl/envelope-simpl.hxx \ +--hxx-epilogue '\\\#include "body.hxx"' + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Dist. +# +dist-common := $(out_base)/.dist-common + +.PHONY: $(dist) $(dist-win) $(dist-common) + +$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base)) + +$(dist-common): + $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx) + $(call install-data,$(src_base)/body.hxx,$(dist_prefix)/$(path)/body.hxx) + $(call install-data,$(src_base)/body.cxx,$(dist_prefix)/$(path)/body.cxx) + $(call install-data,$(src_base)/envelope.hxx,$(dist_prefix)/$(path)/envelope.hxx) + $(call install-data,$(src_base)/envelope.cxx,$(dist_prefix)/$(path)/envelope.cxx) + $(call install-data,$(src_base)/envelope-pimpl.hxx,$(dist_prefix)/$(path)/envelope-pimpl.hxx) + $(call install-data,$(src_base)/envelope-pimpl.cxx,$(dist_prefix)/$(path)/envelope-pimpl.cxx) + $(call install-data,$(src_base)/envelope-simpl.hxx,$(dist_prefix)/$(path)/envelope-simpl.hxx) + $(call install-data,$(src_base)/envelope-simpl.cxx,$(dist_prefix)/$(path)/envelope-simpl.cxx) + $(call install-data,$(src_base)/email.xsd,$(dist_prefix)/$(path)/email.xsd) + $(call install-data,$(src_base)/email.xml,$(dist_prefix)/$(path)/email.xml) + +$(dist): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README) + +$(dist-win): $(dist-common) + $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt) + $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt) + + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/install.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/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile index 06a0ffa..2ee1d25 100644 --- a/examples/cxx/hybrid/makefile +++ b/examples/cxx/hybrid/makefile @@ -5,8 +5,8 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make -all_examples := binary compositors hello multiroot streaming library \ -wildcard filter minimal +all_examples := binary compositors custom hello multiroot streaming \ +library wildcard filter minimal build_examples := binary compositors diff --git a/examples/cxx/hybrid/wildcard/README b/examples/cxx/hybrid/wildcard/README index d54b081..e185492 100644 --- a/examples/cxx/hybrid/wildcard/README +++ b/examples/cxx/hybrid/wildcard/README @@ -2,11 +2,14 @@ This example shows how to parse, store in the object model, and serialize XML data matched by XML Schema wildcards (any and anyAttribute) using the Embedded C++/Hybrid mapping. -This example uses the object model as well as parser and serializer -customization mechanisms provided by the C++/Hybrid mapping. For more -information, see Section 4.8, "Customizing the Object Model" and Section -6.1, "Customizing Parsers and Serializers" in the Embedded C++/Hybrid -Mapping Getting Started Guide. +This example uses the custom data mechanism to store the wildcard data +in the object model as well as parser and serializer customization to +parse and serialize the wildcard data. For more information, see Section +4.8, "Customizing the Object Model" and Section 6.1, "Customizing Parsers +and Serializers" in the Embedded C++/Hybrid Mapping Getting Started Guide. + +The 'wildcard' example in the examples/cxx/hybrid/custom/ directory shows +how to do the same but using type customization instead of custom data. The example consists of the following files: diff --git a/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx b/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx index 06eb26c..d783cc9 100644 --- a/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx +++ b/examples/cxx/hybrid/wildcard/envelope-pimpl.hxx @@ -12,7 +12,7 @@ namespace email // and _any_characters functions. We can dynamically select a parser // from the _start_any_element after which all inner content will be // automatically routed to this parser. At the end we will get a call - // to _end_any_element in which we can call post(), and save the data. + // to _end_any_element in which we can call post() and save the data. // class envelope_pimpl: public envelope_base_pimpl { diff --git a/xsde/cxx/hybrid/cli.hxx b/xsde/cxx/hybrid/cli.hxx index 343e53b..0d1ec70 100644 --- a/xsde/cxx/hybrid/cli.hxx +++ b/xsde/cxx/hybrid/cli.hxx @@ -43,6 +43,7 @@ namespace CXX extern Key suppress_reset; extern Key reuse_style_mixin; extern Key custom_data; + extern Key custom_type; extern Key custom_parser; extern Key custom_serializer; extern Key root_element_first; @@ -124,6 +125,7 @@ namespace CXX suppress_reset, Boolean, reuse_style_mixin, Boolean, custom_data, Cult::Containers::Vector, + custom_type, Cult::Containers::Vector, custom_parser, Cult::Containers::Vector, custom_serializer, Cult::Containers::Vector, root_element_first, Boolean, diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx index 68bc0c2..a28dfc1 100644 --- a/xsde/cxx/hybrid/elements.cxx +++ b/xsde/cxx/hybrid/elements.cxx @@ -375,12 +375,19 @@ namespace CXX p->contained_compositor ().container ())); if (!r) - r = fq ? fq_name (t) : ename (t); + r = fq ? fq_name (t) : ename_custom (t); else { String tmp; tmp.swap (r); - r = fq ? fq_name (t) : ename (t); + + if (fq) + { + r += fq_name (t.scope ()); + r += L"::"; + } + + r = ename_custom (t); r += L"::"; r += tmp; } @@ -405,7 +412,10 @@ namespace CXX using SemanticGraph::Complex; Complex& t (dynamic_cast (a.scope ())); - return fq ? fq_name (t) : ename (t); + + return fq + ? fq_name (t.scope ()) + L"::" + ename_custom (t) + : ename_custom (t); } Void Context:: @@ -474,7 +484,25 @@ namespace CXX Void TypeForward:: traverse (SemanticGraph::Type& t) { - os << "class " << ename (t) << ";"; + SemanticGraph::Context& ctx (t.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 (t) << ";"; + } + else + os << "class " << ename (t) << ";"; } Void Includes:: diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx index cd1a40f..d324b04 100644 --- a/xsde/cxx/hybrid/elements.hxx +++ b/xsde/cxx/hybrid/elements.hxx @@ -94,6 +94,17 @@ namespace CXX } static String const& + ename_custom (SemanticGraph::Type& t) + { + SemanticGraph::Context& c (t.context ()); + + if (!c.count ("name-base")) + return c.get ("name"); + else + return c.get ("name-base"); + } + + static String const& etype (SemanticGraph::Compositor& c) { return c.context ().get ("type"); diff --git a/xsde/cxx/hybrid/extraction-header.cxx b/xsde/cxx/hybrid/extraction-header.cxx index 8b7490f..dc729f6 100644 --- a/xsde/cxx/hybrid/extraction-header.cxx +++ b/xsde/cxx/hybrid/extraction-header.cxx @@ -24,7 +24,13 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + String const& name (ename_custom (l)); + + // 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) @@ -47,7 +53,13 @@ namespace CXX virtual Void traverse (Type& u) { - String name (ename (u)); + String const& name (ename_custom (u)); + + // 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) @@ -195,24 +207,27 @@ namespace CXX virtual Void traverse (Type& c) { - if (!restriction_p (c)) - { - String name (ename (c)); + String const& name (ename_custom (c)); - for (Streams::ConstIterator i (istreams.begin ()); - i != istreams.end (); ++i) - { - os << (exceptions ? "void" : "bool") << endl - << "operator>> (" << istream (*i) << "&," << endl - << name << "&);" - << endl; - } + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; - // Operators for nested classes. - // - if (c.contains_compositor_p ()) - Complex::contains_compositor (c, contains_compositor_); + for (Streams::ConstIterator i (istreams.begin ()); + i != istreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator>> (" << istream (*i) << "&," << endl + << name << "&);" + << endl; } + + // Operators for nested classes. + // + if (!restriction_p (c) && c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); } private: diff --git a/xsde/cxx/hybrid/extraction-source.cxx b/xsde/cxx/hybrid/extraction-source.cxx index 44af7e0..5945ce3 100644 --- a/xsde/cxx/hybrid/extraction-source.cxx +++ b/xsde/cxx/hybrid/extraction-source.cxx @@ -24,7 +24,13 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + String const& name (ename_custom (l)); + + // 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) @@ -56,7 +62,14 @@ namespace CXX virtual Void traverse (Type& u) { - String name (ename (u)); + String const& name (ename_custom (u)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + String const& value (u.context ().get ("value")); for (Streams::ConstIterator i (istreams.begin ()); @@ -930,9 +943,15 @@ namespace CXX virtual Void traverse (Type& c) { - Boolean restriction (restriction_p (c)); + String const& name (ename_custom (c)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; - String name (ename (c)); + Boolean restriction (restriction_p (c)); for (Streams::ConstIterator i (istreams.begin ()); i != istreams.end (); ++i) diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx index 28d851b..14afad6 100644 --- a/xsde/cxx/hybrid/generator.cxx +++ b/xsde/cxx/hybrid/generator.cxx @@ -131,6 +131,7 @@ namespace CXX extern Key suppress_reset = "suppress-reset"; extern Key reuse_style_mixin = "reuse-style-mixin"; extern Key custom_data = "custom-data"; + extern Key custom_type = "custom-type"; extern Key custom_parser = "custom-parser"; extern Key custom_serializer = "custom-serializer"; extern Key root_element_first = "root-element-first"; @@ -294,20 +295,34 @@ namespace CXX << " XML Schema type ." << endl; + e << "--custom-type " << endl + << " Use a custom type implementation instead of the\n" + << " generated version. The argument is in the\n" + << " form name[=[flags][/[type][/[base][/include]]]],\n" + << " where is an XML Schema type name,\n" + << " optional specify whether the custom type\n" + << " is fixed or variable-length, optional is\n" + << " a C++ type name that should be used instead,\n" + << " optional is a C++ name that should be\n" + << " given to the generated version, and optional\n" + << " is the header file that defines the\n" + << " custom implementation." + << endl; + e << "--custom-parser " << endl << " Use a custom parser implementation instead of the\n" << " generated version. The argument is in the\n" - << " form type[=base[/include]], where is an XML\n" - << " Schema type name, optional is a C++ name\n" - << " that should be given to the generated version,\n" - << " and optional is the header file that\n" - << " defines the custom implementation." + << " form name[=[base][/include]], where is an\n" + << " XML Schema type name, optional is a C++\n" + << " name that should be given to the generated\n" + << " version, and optional is the header\n" + << " file that defines the custom implementation." << endl; e << "--custom-serializer " << endl << " Use a custom serializer implementation instead of\n" << " the generated version. The argument is in\n" - << " the form type[=base[/include]], where is\n" + << " the form name[=[base][/include]], where is\n" << " an XML Schema type name, optional is a C++\n" << " name that should be given to the generated\n" << " version, and optional is the header\n" @@ -914,7 +929,9 @@ namespace CXX // Determine which types are fixed/variable-sized. // TreeSizeProcessor proc; - proc.process (ops, schema, file); + + if (!proc.process (ops, schema, file)) + throw Failed (); } namespace diff --git a/xsde/cxx/hybrid/insertion-header.cxx b/xsde/cxx/hybrid/insertion-header.cxx index 050b58f..4898c02 100644 --- a/xsde/cxx/hybrid/insertion-header.cxx +++ b/xsde/cxx/hybrid/insertion-header.cxx @@ -24,7 +24,13 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + String const& name (ename_custom (l)); + + // 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) @@ -47,7 +53,13 @@ namespace CXX virtual Void traverse (Type& u) { - String name (ename (u)); + String const& name (ename_custom (u)); + + // 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) @@ -195,24 +207,27 @@ namespace CXX virtual Void traverse (Type& c) { - if (!restriction_p (c)) - { - String name (ename (c)); + String const& name (ename_custom (c)); - for (Streams::ConstIterator i (ostreams.begin ()); - i != ostreams.end (); ++i) - { - os << (exceptions ? "void" : "bool") << endl - << "operator<< (" << ostream (*i) << "&," << endl - << "const " << name << "&);" - << endl; - } + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; - // Operators for nested classes. - // - if (c.contains_compositor_p ()) - Complex::contains_compositor (c, contains_compositor_); + for (Streams::ConstIterator i (ostreams.begin ()); + i != ostreams.end (); ++i) + { + os << (exceptions ? "void" : "bool") << endl + << "operator<< (" << ostream (*i) << "&," << endl + << "const " << name << "&);" + << endl; } + + // Operators for nested classes. + // + if (!restriction_p (c) && c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); } private: diff --git a/xsde/cxx/hybrid/insertion-source.cxx b/xsde/cxx/hybrid/insertion-source.cxx index 58fe9f5..b0b89c9 100644 --- a/xsde/cxx/hybrid/insertion-source.cxx +++ b/xsde/cxx/hybrid/insertion-source.cxx @@ -24,7 +24,13 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + String const& name (ename_custom (l)); + + // 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) @@ -57,7 +63,14 @@ namespace CXX virtual Void traverse (Type& u) { - String name (ename (u)); + String const& name (ename_custom (u)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + String const& value (u.context ().get ("value")); for (Streams::ConstIterator i (ostreams.begin ()); @@ -590,9 +603,15 @@ namespace CXX virtual Void traverse (Type& c) { - Boolean restriction (restriction_p (c)); + String const& name (ename_custom (c)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; - String name (ename (c)); + Boolean restriction (restriction_p (c)); for (Streams::ConstIterator i (ostreams.begin ()); i != ostreams.end (); ++i) diff --git a/xsde/cxx/hybrid/parser-name-processor.cxx b/xsde/cxx/hybrid/parser-name-processor.cxx index c913766..740cf36 100644 --- a/xsde/cxx/hybrid/parser-name-processor.cxx +++ b/xsde/cxx/hybrid/parser-name-processor.cxx @@ -357,12 +357,6 @@ namespace CXX virtual Void traverse (Type& c) { - Boolean restriction (false); - - if (c.inherits_p ()) - restriction = c.inherits ().is_a () && - !c.inherits ().base ().is_a (); - SemanticGraph::Context& cc (c.context ()); // In case of customization use p:impl-base instead of p:impl. @@ -371,10 +365,17 @@ namespace CXX String const& base (cc.count ("p:impl-base") ? cc.get ("p:impl-base") : cc.get ("p:impl")); - if (!base) return; + // + // + Boolean restriction (false); + + if (c.inherits_p ()) + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + // Use skeleton's name set to make sure we don't clash // with callbacks which we are overriding. // diff --git a/xsde/cxx/hybrid/parser-source.cxx b/xsde/cxx/hybrid/parser-source.cxx index f9c1855..4c4237c 100644 --- a/xsde/cxx/hybrid/parser-source.cxx +++ b/xsde/cxx/hybrid/parser-source.cxx @@ -904,7 +904,7 @@ namespace CXX // // - struct Complex : Traversal::Complex, Context + struct Complex: Traversal::Complex, Context { Complex (Context& c) : Context (c), diff --git a/xsde/cxx/hybrid/serializer-name-processor.cxx b/xsde/cxx/hybrid/serializer-name-processor.cxx index b6ab09b..ba4a268 100644 --- a/xsde/cxx/hybrid/serializer-name-processor.cxx +++ b/xsde/cxx/hybrid/serializer-name-processor.cxx @@ -371,12 +371,6 @@ namespace CXX virtual Void traverse (Type& c) { - Boolean restriction (false); - - if (c.inherits_p ()) - restriction = c.inherits ().is_a () && - !c.inherits ().base ().is_a (); - SemanticGraph::Context& cc (c.context ()); // In case of customization use s:impl-base instead of s:impl. @@ -388,6 +382,14 @@ namespace CXX if (!base) return; + // + // + Boolean restriction (false); + + if (c.inherits_p ()) + restriction = c.inherits ().is_a () && + !c.inherits ().base ().is_a (); + // Use skeleton's name set to make sure we don't clash // with callbacks which we are overriding. // diff --git a/xsde/cxx/hybrid/tree-forward.cxx b/xsde/cxx/hybrid/tree-forward.cxx index 32f1180..451f129 100644 --- a/xsde/cxx/hybrid/tree-forward.cxx +++ b/xsde/cxx/hybrid/tree-forward.cxx @@ -24,7 +24,25 @@ namespace CXX virtual Void traverse (Type& l) { - os << "class " << ename (l) << ";"; + SemanticGraph::Context& ctx (l.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 (l) << ";"; + } + else + os << "class " << ename (l) << ";"; } }; @@ -38,7 +56,25 @@ namespace CXX virtual Void traverse (Type& u) { - os << "class " << ename (u) << ";"; + SemanticGraph::Context& ctx (u.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 (u) << ";"; + } + else + os << "class " << ename (u) << ";"; } }; @@ -52,7 +88,25 @@ namespace CXX virtual Void traverse (Type& c) { - os << "class " << ename (c) << ";"; + SemanticGraph::Context& ctx (c.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 (c) << ";"; + } + else + os << "class " << ename (c) << ";"; } }; diff --git a/xsde/cxx/hybrid/tree-header.cxx b/xsde/cxx/hybrid/tree-header.cxx index dc378fe..207b35f 100644 --- a/xsde/cxx/hybrid/tree-header.cxx +++ b/xsde/cxx/hybrid/tree-header.cxx @@ -24,66 +24,86 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + SemanticGraph::Context& lc (l.context ()); + String const& name (ename_custom (l)); - os << "// " << comment (l.name ()) << " (variable-length)" << endl - << "//" << endl; - - os << "class " << name << ": public "; - - base_name_.dispatch (l.argumented ().type ()); - - os << "{" - << "private:" << endl - << name << " (const " << name << "&);" - << name << "& operator= (const " << name << "&);" - << endl; - - // c-tor + // We may not need to generate the class if this type is + // being customized. // - os << "public:" << endl - << name << " ();"; - - // Custom data. - // - if (l.context ().count ("cd-name")) + if (name) { - String const& name (ecd_name (l)); - String const& sequence (ecd_sequence (l)); - String const& iterator (ecd_iterator (l)); - String const& const_iterator (ecd_const_iterator (l)); - - os << endl - << "// Custom data." << endl + os << "// " << comment (l.name ()) << " (variable-length)" << endl << "//" << endl; - // sequence & iterators - // - os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" - << "typedef " << sequence << "::iterator " << iterator << ";" - << "typedef " << sequence << "::const_iterator " << - const_iterator << ";" + os << "class " << name << ": public "; + + base_name_.dispatch (l.argumented ().type ()); + + os << "{" + << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" << endl; - // const seq& - // name () const + // c-tor // - os << "const " << sequence << "&" << endl - << name << " () const;" - << endl; + os << "public:" << endl + << name << " ();"; - // seq& - // name () + // Custom data. // - os << sequence << "&" << endl - << name << " ();" - << endl; + if (lc.count ("cd-name")) + { + String const& name (ecd_name (l)); + String const& sequence (ecd_sequence (l)); + String const& iterator (ecd_iterator (l)); + String const& const_iterator (ecd_const_iterator (l)); - os << "private:" << endl - << sequence << " " << ecd_member (l) << ";"; + os << endl + << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::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; + + os << "private:" << endl + << sequence << " " << ecd_member (l) << ";"; + } + + os << "};"; } - os << "};"; + // Generate include for custom type. + // + if (lc.count ("name-include")) + { + close_ns (); + + os << "#include " << process_include_path ( + lc.get ("name-include")) << endl + << endl; + + open_ns (); + } } private: @@ -101,147 +121,166 @@ namespace CXX traverse (Type& u) { SemanticGraph::Context& uc (u.context ()); + String const& name (ename_custom (u)); - String name (ename (u)); - Boolean cd (uc.count ("cd-name")); + // We may not need to generate the class if this type is + // being customized. + // + if (name) + { + Boolean cd (uc.count ("cd-name")); - os << "// " << comment (u.name ()) << " (variable-length)" << endl - << "//" << endl; + os << "// " << comment (u.name ()) << " (variable-length)" << endl + << "//" << endl; - os << "class " << name - << "{"; + os << "class " << name + << "{"; - if (!fixed_length (u)) - os << "private:" << endl - << name << " (const " << name << "&);" - << name << "& operator= (const " << name << "&);" - << endl; + if (!fixed_length (u)) + os << "private:" << endl + << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; - os << "public:" << endl; + os << "public:" << endl; - // c-tor - // - os << name << " ();"; + // c-tor + // + os << name << " ();"; - String const& value (uc.get ("value")); - String const& member (uc.get ("value-member")); + String const& value (uc.get ("value")); + String const& member (uc.get ("value-member")); - if (stl) - { - os << endl; + if (stl) + { + os << endl; - // const std::string& - // name () const - // - os << "const ::std::string&" << endl - << value << " () const;" - << endl; + // const std::string& + // name () const + // + os << "const ::std::string&" << endl + << value << " () const;" + << endl; - // std::string& - // name () - // - os << "::std::string&" << endl - << value << " ();" - << endl; + // std::string& + // name () + // + os << "::std::string&" << endl + << value << " ();" + << endl; - // void - // name (const std::string&) - // - os << "void" << endl - << value << " (const ::std::string&);" - << endl; - } - else - { - // d-tor - // - os << "~" << name << " ();" - << endl; + // void + // name (const std::string&) + // + os << "void" << endl + << value << " (const ::std::string&);" + << endl; + } + else + { + // d-tor + // + os << "~" << name << " ();" + << endl; - // const char* - // name () const - // - os << "const char*" << endl - << value << " () const;" - << endl; + // const char* + // name () const + // + os << "const char*" << endl + << value << " () const;" + << endl; - // char* - // name () - // - os << "char*" << endl - << value << " ();" - << endl; + // char* + // name () + // + os << "char*" << endl + << value << " ();" + << endl; - // void - // name (char*) - // - os << "void" << endl - << value << " (char*);" - << endl; + // void + // name (char*) + // + os << "void" << endl + << value << " (char*);" + << endl; - // char* - // detach () + // char* + // detach () + // + if (detach) + { + os << "char*" << endl + << uc.get ("value-detach") << " ();" + << endl; + } + } + + // Custom data. // - if (detach) + if (cd) { - os << "char*" << endl - << uc.get ("value-detach") << " ();" + String const& name (ecd_name (u)); + String const& sequence (ecd_sequence (u)); + String const& iterator (ecd_iterator (u)); + String const& const_iterator (ecd_const_iterator (u)); + + os << "// Custom data." << endl + << "//" << endl; + + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" << endl; - } - } - // Custom data. - // - if (cd) - { - String const& name (ecd_name (u)); - String const& sequence (ecd_sequence (u)); - String const& iterator (ecd_iterator (u)); - String const& const_iterator (ecd_const_iterator (u)); + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; - os << "// Custom data." << endl - << "//" << endl; + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } - // sequence & iterators - // - os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" - << "typedef " << sequence << "::iterator " << iterator << ";" - << "typedef " << sequence << "::const_iterator " << - const_iterator << ";" - << endl; + if (stl) + { + os << "private:" << endl + << "::std::string " << member << ";"; + } + else + { + os << "private:" << endl + << "char* " << member << ";"; + } - // const seq& - // name () const + // Custom data. // - os << "const " << sequence << "&" << endl - << name << " () const;" - << endl; + if (cd) + os << ecd_sequence (u) << " " << ecd_member (u) << ";"; - // seq& - // name () - // - os << sequence << "&" << endl - << name << " ();" - << endl; + os << "};"; } - if (stl) - { - os << "private:" << endl - << "::std::string " << member << ";"; - } - else + // Generate include for custom type. + // + if (uc.count ("name-include")) { - os << "private:" << endl - << "char* " << member << ";"; - } + close_ns (); - // Custom data. - // - if (cd) - os << ecd_sequence (u) << " " << ecd_member (u) << ";"; + os << "#include " << process_include_path ( + uc.get ("name-include")) << endl + << endl; - os << "};"; + open_ns (); + } } }; @@ -2313,109 +2352,130 @@ namespace CXX virtual Void traverse (Type& c) { - String name (ename (c)); - Boolean fl (fixed_length (c)); - Boolean restriction (restriction_p (c)); - Boolean cd (c.context ().count ("cd-name")); + SemanticGraph::Context& cc (c.context ()); + String const& name (ename_custom (c)); - os << "// " << comment (c.name ()) << " (" << - (fl ? "fixed-length" : "variable-length") << ")" << endl - << "//" << endl; - - os << "class " << name; - - if (c.inherits_p ()) + // We may not need to generate the class if this type is + // being customized. + // + if (name) { - os << ": public "; - base_name_.dispatch (c.inherits ().base ()); - } + Boolean fl (fixed_length (c)); + Boolean restriction (restriction_p (c)); + Boolean cd (cc.count ("cd-name")); - os << "{"; + os << "// " << comment (c.name ()) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl + << "//" << endl; - // c-tor - // - os << "public:" << endl - << name << " ();"; + os << "class " << name; - // d-tor - // - if (!restriction) - os << "~" << name << " ();"; + if (c.inherits_p ()) + { + os << ": public "; + base_name_.dispatch (c.inherits ().base ()); + } - // copy c-tor & operator= - // - if (!fl) - os << endl - << "private:" << endl; + os << "{"; - if (!fl || !restriction) - os << name << " (const " << name << "&);" - << name << "& operator= (const " << name << "&);" - << endl; + // c-tor + // + os << "public:" << endl + << name << " ();"; - if ((!restriction && !fl) || cd) - os << "public:" << endl; + // d-tor + // + if (!restriction) + os << "~" << name << " ();"; - if (!restriction) - { - Complex::names (c, attribute_names_); + // copy c-tor & operator= + // + if (!fl) + os << endl + << "private:" << endl; - if (c.contains_compositor_p ()) - Complex::contains_compositor (c, contains_compositor_); - } + if (!fl || !restriction) + os << name << " (const " << name << "&);" + << name << "& operator= (const " << name << "&);" + << endl; - // Custom data. - // - if (cd) - { - String const& name (ecd_name (c)); - String const& sequence (ecd_sequence (c)); - String const& iterator (ecd_iterator (c)); - String const& const_iterator (ecd_const_iterator (c)); + if ((!restriction && !fl) || cd) + os << "public:" << endl; - os << "// Custom data." << endl - << "//" << endl; + if (!restriction) + { + Complex::names (c, attribute_names_); - // sequence & iterators - // - os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" - << "typedef " << sequence << "::iterator " << iterator << ";" - << "typedef " << sequence << "::const_iterator " << - const_iterator << ";" - << endl; + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_); + } - // const seq& - // name () const + // Custom data. // - os << "const " << sequence << "&" << endl - << name << " () const;" - << endl; + if (cd) + { + String const& name (ecd_name (c)); + String const& sequence (ecd_sequence (c)); + String const& iterator (ecd_iterator (c)); + String const& const_iterator (ecd_const_iterator (c)); - // seq& - // name () - // - os << sequence << "&" << endl - << name << " ();" - << endl; - } + os << "// Custom data." << endl + << "//" << endl; - if (!restriction || cd) - os << "private:" << endl; + // sequence & iterators + // + os << "typedef ::xsde::cxx::hybrid::data_seq " << sequence << ";" + << "typedef " << sequence << "::iterator " << iterator << ";" + << "typedef " << sequence << "::const_iterator " << + const_iterator << ";" + << endl; - if (!restriction) - { - Complex::names (c, attribute_names_data_); + // const seq& + // name () const + // + os << "const " << sequence << "&" << endl + << name << " () const;" + << endl; - if (c.contains_compositor_p ()) - Complex::contains_compositor (c, contains_compositor_data_); + // seq& + // name () + // + os << sequence << "&" << endl + << name << " ();" + << endl; + } + + if (!restriction || cd) + os << "private:" << endl; + + if (!restriction) + { + Complex::names (c, attribute_names_data_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_data_); + } + + // Custom data. + // + if (cd) + os << ecd_sequence (c) << " " << ecd_member (c) << ";"; + + os << "};"; } - // Custom data. + // Generate include for custom type. // - if (cd) - os << ecd_sequence (c) << " " << ecd_member (c) << ";"; + if (cc.count ("name-include")) + { + close_ns (); - os << "};"; + os << "#include " << process_include_path ( + cc.get ("name-include")) << endl + << endl; + + open_ns (); + } } private: @@ -2499,7 +2559,7 @@ namespace CXX Traversal::Sources sources; Traversal::Names names_ns, names; - Namespace ns (ctx); + Namespace ns (ctx, true); List list (ctx); Union union_ (ctx); diff --git a/xsde/cxx/hybrid/tree-inline.cxx b/xsde/cxx/hybrid/tree-inline.cxx index 34d0cc3..b1c60e6 100644 --- a/xsde/cxx/hybrid/tree-inline.cxx +++ b/xsde/cxx/hybrid/tree-inline.cxx @@ -24,7 +24,13 @@ namespace CXX virtual Void traverse (Type& l) { - String name (ename (l)); + String const& name (ename_custom (l)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; os << "// " << comment (l.name ()) << endl << "//" << endl @@ -82,7 +88,13 @@ namespace CXX virtual Void traverse (Type& u) { - String name (ename (u)); + String const& name (ename_custom (u)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; os << "// " << comment (u.name ()) << endl << "//" << endl @@ -1810,12 +1822,20 @@ namespace CXX virtual Void traverse (Type& c) { + String const& scope (ename_custom (c)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!scope) + return; + + os << "// " << comment (c.name ()) << endl + << "//" << endl + << endl; + if (!restriction_p (c)) { - os << "// " << comment (c.name ()) << endl - << "//" << endl - << endl; - Complex::names (c, attribute_names_func_); if (c.contains_compositor_p ()) @@ -1831,7 +1851,6 @@ namespace CXX // if (c.context ().count ("cd-name")) { - String const& scope (ename (c)); String const& name (ecd_name (c)); String const& member (ecd_member (c)); String const& sequence (ecd_sequence (c)); diff --git a/xsde/cxx/hybrid/tree-name-processor.cxx b/xsde/cxx/hybrid/tree-name-processor.cxx index 7783ba5..a3a1dd3 100644 --- a/xsde/cxx/hybrid/tree-name-processor.cxx +++ b/xsde/cxx/hybrid/tree-name-processor.cxx @@ -52,6 +52,7 @@ namespace CXX stl (!ops.value ()), detach (ops.value ()), custom_data_map (custom_data_map_), + custom_type_map (custom_type_map_), global_type_names (global_type_names_) { // Translate the type names with custom data. @@ -93,6 +94,82 @@ namespace CXX } while (true); } } + + // Custom type mapping. + // + { + typedef Containers::Vector Vector; + Vector const& v (ops.value ()); + + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); + i != e; ++i) + { + String s (*i); + + if (s.empty ()) + continue; + + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); + + // If no delimiter found type, base, and include are empty. + // + if (pos == String::npos) + { + custom_type_map_[s].type.clear (); + custom_type_map_[s].base.clear (); + custom_type_map_[s].include.clear (); + continue; + } + + String name (s, 0, pos); + + // Skip the flags component. + // + pos = s.find ('/', pos + 1); + + if (pos == String::npos) + { + custom_type_map_[name].type.clear (); + custom_type_map_[name].base.clear (); + custom_type_map_[name].include.clear (); + continue; + } + + String bi (s, pos + 1); + + // See if we've got the base/include part after '/'. + // + pos = bi.find ('/'); + + String type, base, include; + + if (pos != String::npos) + { + type.assign (bi, 0, pos); + String i (bi, pos + 1); + + // See if we've got the include part after '/'. + // + pos = i.find ('/'); + + if (pos != String::npos) + { + base.assign (i, 0, pos); + include.assign (i, pos + 1, String::npos); + } + else + base = i; + } + else + type = bi; + + custom_type_map_[name].type = type; + custom_type_map_[name].base = base; + custom_type_map_[name].include = include; + } + } } protected: @@ -103,6 +180,7 @@ namespace CXX stl (c.stl), detach (c.detach), custom_data_map (c.custom_data_map), + custom_type_map (c.custom_type_map), global_type_names (c.global_type_names) { } @@ -168,10 +246,31 @@ namespace CXX { }; + public: + struct CustomType + { + CustomType (String const& t = L"", + String const& b = L"", + String const& i = L"") + : type (t), base (b), include (i) + { + } + + String type; + String base; + String include; + }; + + typedef + Cult::Containers::Map + CustomTypeMap; + private: SemanticGraph::Path const schema_path_; CustomDataMap custom_data_map_; + CustomTypeMap custom_type_map_; + Cult::Containers::Map global_type_names_; public: @@ -182,6 +281,8 @@ namespace CXX Boolean detach; CustomDataMap& custom_data_map; + CustomTypeMap& custom_type_map; + Cult::Containers::Map& global_type_names; }; @@ -197,6 +298,17 @@ namespace CXX virtual Void traverse (Type& l) { + SemanticGraph::Context& lc (l.context ()); + + // In case of customization use name-base instead of name. + // If name is empty then we are not generating anything. + // + String const& name (lc.count ("name-base") + ? lc.get ("name-base") + : lc.get ("name")); + if (!name) + return; + if (!data_members_) { // Check if this type has custom data. @@ -206,12 +318,6 @@ namespace CXX if (i != custom_data_map.end () && i->second->find (L"") != i->second->end ()) { - SemanticGraph::Context& lc (l.context ()); - - // Use processed name. - // - String const& name (lc.get ("name")); - lc.set (member_set_key, NameSet ()); NameSet& set (lc.get (member_set_key)); set.insert (name); @@ -229,8 +335,6 @@ namespace CXX } else { - SemanticGraph::Context& lc (l.context ()); - // Custom data. // if (lc.count ("cd-name")) @@ -260,12 +364,17 @@ namespace CXX { SemanticGraph::Context& uc (u.context ()); + // In case of customization use name-base instead of name. + // If name is empty then we are not generating anything. + // + String const& name (uc.count ("name-base") + ? uc.get ("name-base") + : uc.get ("name")); + if (!name) + return; + if (!data_members_) { - // Use processed name. - // - String const& name (uc.get ("name")); - uc.set (member_set_key, NameSet ()); NameSet& set (uc.get (member_set_key)); set.insert (name); @@ -1173,6 +1282,15 @@ namespace CXX { SemanticGraph::Context& cc (c.context ()); + // In case of customization use name-base instead of name. + // If name is empty then we are not generating anything. + // + String const& name (cc.count ("name-base") + ? cc.get ("name-base") + : cc.get ("name")); + if (!name) + return; + // Check if this type or any of its nested types have // custom data. // @@ -1183,10 +1301,6 @@ namespace CXX map = i->second.get (); } - // Use processed name. - // - String const& name (cc.get ("name")); - cc.set (member_set_key, NameSet ()); NameSet& member_set (cc.get (member_set_key)); @@ -1207,8 +1321,14 @@ namespace CXX if (!bc.count (member_set_key)) dispatch (b); - NameSet const& bset (bc.get (member_set_key)); - member_set.insert (bset.begin (), bset.end ()); + // We may still not have the set if this type is being + // customized. + // + if (bc.count (member_set_key)) + { + NameSet const& bset (bc.get (member_set_key)); + member_set.insert (bset.begin (), bset.end ()); + } } // Inheritance by restriction from anyType is a special case. @@ -1335,6 +1455,18 @@ namespace CXX assign_data (Type& c) { SemanticGraph::Context& cc (c.context ()); + + // In case of customization use name-base instead of name. + // If name is empty then we are not generating anything. + // + String const& name (cc.count ("name-base") + ? cc.get ("name-base") + : cc.get ("name")); + if (!name) + return; + + // + // Boolean restriction (false); if (c.inherits_p ()) @@ -1421,8 +1553,30 @@ namespace CXX virtual Void traverse (SemanticGraph::Type& t) { - String name (find_name (t.name (), set_)); - t.context ().set ("name", name); + String const& name (t.name ()); + SemanticGraph::Context& tc (t.context ()); + + tc.set ("name", find_name (name, set_)); + + // See if this parser is being customized. + // + CustomTypeMap::ConstIterator i (custom_type_map.find (name)); + + if (i != custom_type_map.end ()) + { + if (i->second.type) + tc.set ("name-typedef", i->second.type); + + // The empty name-base indicates that we don't need to + // generate anything. + // + tc.set ("name-base", i->second.base + ? find_name (i->second.base, set_) + : i->second.base); + + if (i->second.include) + tc.set ("name-include", i->second.include); + } } private: diff --git a/xsde/cxx/hybrid/tree-size-processor.cxx b/xsde/cxx/hybrid/tree-size-processor.cxx index d492b24..a3b2231 100644 --- a/xsde/cxx/hybrid/tree-size-processor.cxx +++ b/xsde/cxx/hybrid/tree-size-processor.cxx @@ -9,9 +9,14 @@ #include #include +#include #include #include +#include + +using std::wcerr; + namespace CXX { namespace Hybrid @@ -20,6 +25,15 @@ namespace CXX { typedef Cult::Containers::Set TypeSet; + + struct CustomType + { + Boolean fixed; + String base; + }; + + typedef Cult::Containers::Map CustomTypeMap; + Boolean test (SemanticGraph::Type& t) { @@ -225,8 +239,14 @@ namespace CXX Traversal::Union, Traversal::Complex { - Type (TypeSet& custom_data, Boolean stl_) - : custom_data_ (custom_data), stl (stl_) + Type (Boolean& valid, + TypeSet& custom_data, + CustomTypeMap& custom_type_map, + Boolean stl_) + : valid_ (valid), + custom_data_ (custom_data), + custom_type_map_ (custom_type_map), + stl (stl_) { } @@ -263,7 +283,9 @@ namespace CXX if (ctx.count ("recurse")) { - set (c, false); + if (!test (c)) + set (c, false); + ctx.set ("recursive", true); // Mark all the types involved in the cycle as recursive. @@ -339,7 +361,35 @@ namespace CXX } private: + Void + set (SemanticGraph::Type& t, Boolean v) + { + // Check if this is a custom type. + // + CustomTypeMap::Iterator i = custom_type_map_.find (t.name ()); + + if (i != custom_type_map_.end ()) + { + if (i->second.base && i->second.fixed && !v) + { + wcerr << t.file () << ":" << t.line () << ":" << t.column () + << ": error: generated base type '" << i->second.base + << "' is variable-length while the custom type is " + << "declared fixed-length" << endl; + + valid_ = false; + } + + Hybrid::set (t, i->second.fixed); + } + else + Hybrid::set (t, v); + } + + private: + Boolean& valid_; TypeSet& custom_data_; + CustomTypeMap& custom_type_map_; Boolean stl; typedef Containers::Vector Path; @@ -751,11 +801,12 @@ namespace CXX } }; - Void + Boolean process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, SemanticGraph::Path const&) { + Boolean valid (true); Boolean stl (!ops.value ()); // Root schema in the file-per-type mode is just a bunch @@ -826,34 +877,111 @@ namespace CXX } } - Traversal::Schema schema; - Uses uses; + // Prepare a map of types custom types that specify type + // size. + // + CustomTypeMap custom_type_map; + + { + typedef Containers::Vector Vector; + Vector const& v (ops.value ()); - schema >> uses >> schema; + for (Vector::ConstIterator i (v.begin ()), e (v.end ()); + i != e; ++i) + { + String s (*i); - Traversal::Names schema_names; - Traversal::Namespace ns; - Traversal::Names ns_names; - Type type (custom_data_types, stl); + if (s.empty ()) + continue; - schema >> schema_names >> ns >> ns_names >> type; + // Split the string in two parts at the last '='. + // + Size pos (s.rfind ('=')); - // Some twisted schemas do recusive self-inclusion. - // - tu.context ().set ("cxx-hybrid-size-processor-seen", true); + if (pos == String::npos) + continue; - schema.dispatch (tu); + String name (s, 0, pos); + String fb (s, pos + 1); + + pos = fb.find ('/'); + + String flags, base; + + if (pos != String::npos) + { + flags.assign (fb, 0, pos); + + // Skip the type component. + // + pos = fb.find ('/', pos + 1); + + if (pos != String::npos) + { + String b (fb, pos + 1); + + // See if we've got the include component. + // + pos = b.find ('/'); + + if (pos != String::npos) + base.assign (b, 0, pos); + else + base = b; + } + } + else + flags = fb; + + if (!flags) + continue; + + if (flags != L"f" && flags != L"v") + { + wcerr << "error: invalid custom type flag: '" << + flags << "'" << endl; + + valid = false; + } + + custom_type_map[name].base = base; + custom_type_map[name].fixed = (flags == L"f"); + } + } + + if (valid) + { + Traversal::Schema schema; + Uses uses; + + schema >> uses >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + Type type (valid, custom_data_types, custom_type_map, stl); + + schema >> schema_names >> ns >> ns_names >> type; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set ("cxx-hybrid-size-processor-seen", true); + + schema.dispatch (tu); + } } } + + return valid; } } - Void TreeSizeProcessor:: + Boolean TreeSizeProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, SemanticGraph::Path const& file) { - process_impl (ops, tu, file); + return process_impl (ops, tu, file); } } } diff --git a/xsde/cxx/hybrid/tree-size-processor.hxx b/xsde/cxx/hybrid/tree-size-processor.hxx index 130451f..d9257a1 100644 --- a/xsde/cxx/hybrid/tree-size-processor.hxx +++ b/xsde/cxx/hybrid/tree-size-processor.hxx @@ -21,7 +21,7 @@ namespace CXX class TreeSizeProcessor { public: - Void + Boolean process (CLI::Options const& options, XSDFrontend::SemanticGraph::Schema&, XSDFrontend::SemanticGraph::Path const& file); diff --git a/xsde/cxx/hybrid/tree-source.cxx b/xsde/cxx/hybrid/tree-source.cxx index d6c3672..6de3e35 100644 --- a/xsde/cxx/hybrid/tree-source.cxx +++ b/xsde/cxx/hybrid/tree-source.cxx @@ -1456,9 +1456,15 @@ namespace CXX virtual Void traverse (Type& c) { - Boolean restriction (restriction_p (c)); + String const& name (ename_custom (c)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; - String name (ename (c)); + Boolean restriction (restriction_p (c)); os << "// " << comment (c.name ()) << endl << "//" << endl diff --git a/xsde/xsde.cxx b/xsde/xsde.cxx index acbc5db..97224ca 100644 --- a/xsde/xsde.cxx +++ b/xsde/xsde.cxx @@ -704,7 +704,16 @@ main (Int argc, Char* argv[]) // Calculate type sizes. // if (gen_hybrid) - CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, tu); + { + try + { + CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, tu); + } + catch (CXX::Hybrid::Generator::Failed const&) + { + return 1; // Diagnostic has already been issued. + } + } // Try to rearrange definitions so that there is no forward // inheritance. @@ -913,7 +922,16 @@ main (Int argc, Char* argv[]) // Calculate type sizes. // if (gen_hybrid) - CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, ""); + { + try + { + CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, ""); + } + catch (CXX::Hybrid::Generator::Failed const&) + { + return 1; // Diagnostic has already been issued. + } + } // Normalize and annotate complex content restrictions. // -- cgit v1.1