From e4c22d3686da0e973e21eae0561c1169c0eeff36 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 26 Mar 2009 17:09:53 +0200 Subject: Implement support for XML Schema polymorphism in C++/Hybrid examples/cxx/hybrid/polyroot/ examples/cxx/hybrid/polymorphism/: new examples tests/cxx/hybrid/polymorphism/: new tests --- NEWS | 9 + build/xsde/hybrid/xsd-cxx.make | 6 +- dist/examples/cxx/hybrid/binary/cdr/makefile | 4 + dist/examples/cxx/hybrid/binary/cdr/nmakefile | 4 + dist/examples/cxx/hybrid/binary/custom/makefile | 4 + dist/examples/cxx/hybrid/binary/custom/nmakefile | 4 + dist/examples/cxx/hybrid/binary/xdr/makefile | 4 + dist/examples/cxx/hybrid/binary/xdr/nmakefile | 4 + dist/examples/cxx/hybrid/compositors/makefile | 4 + dist/examples/cxx/hybrid/compositors/nmakefile | 4 + dist/examples/cxx/hybrid/custom/wildcard/makefile | 4 + dist/examples/cxx/hybrid/custom/wildcard/nmakefile | 4 + dist/examples/cxx/hybrid/filter/makefile | 4 + dist/examples/cxx/hybrid/filter/nmakefile | 4 + dist/examples/cxx/hybrid/hello/makefile | 4 + dist/examples/cxx/hybrid/hello/nmakefile | 4 + dist/examples/cxx/hybrid/library/makefile | 4 + dist/examples/cxx/hybrid/library/nmakefile | 4 + dist/examples/cxx/hybrid/makefile | 4 + dist/examples/cxx/hybrid/minimal/makefile | 4 + dist/examples/cxx/hybrid/minimal/nmakefile | 4 + dist/examples/cxx/hybrid/multiroot/makefile | 4 + dist/examples/cxx/hybrid/multiroot/nmakefile | 4 + dist/examples/cxx/hybrid/nmakefile | 4 + dist/examples/cxx/hybrid/polymorphism/makefile | 56 +++ dist/examples/cxx/hybrid/polymorphism/nmakefile | 53 +++ dist/examples/cxx/hybrid/polyroot/makefile | 58 +++ dist/examples/cxx/hybrid/polyroot/nmakefile | 55 +++ dist/examples/cxx/hybrid/streaming/makefile | 4 + dist/examples/cxx/hybrid/streaming/nmakefile | 4 + dist/examples/cxx/hybrid/wildcard/makefile | 4 + dist/examples/cxx/hybrid/wildcard/nmakefile | 4 + dist/libxsde/xsde/makefile | 6 + dist/libxsde/xsde/nmakefile | 6 + documentation/cxx/hybrid/guide/index.xhtml | 397 ++++++++++++++++++++- documentation/cxx/parser/guide/index.xhtml | 4 +- documentation/cxx/serializer/guide/index.xhtml | 2 +- documentation/xsde.1 | 37 ++ documentation/xsde.xhtml | 34 +- examples/cxx/hybrid/README | 8 + examples/cxx/hybrid/binary/xdr/driver.cxx | 1 - examples/cxx/hybrid/custom/wildcard/driver.cxx | 1 - examples/cxx/hybrid/filter/driver.cxx | 1 - examples/cxx/hybrid/library/driver.cxx | 1 - examples/cxx/hybrid/makefile | 8 +- examples/cxx/hybrid/minimal/driver.cxx | 1 - examples/cxx/hybrid/polymorphism/README | 57 +++ examples/cxx/hybrid/polymorphism/driver.cxx | 202 +++++++++++ examples/cxx/hybrid/polymorphism/makefile | 113 ++++++ examples/cxx/hybrid/polymorphism/supermen.xml | 26 ++ examples/cxx/hybrid/polymorphism/supermen.xsd | 49 +++ examples/cxx/hybrid/polyroot/README | 60 ++++ examples/cxx/hybrid/polyroot/batman.xml | 17 + examples/cxx/hybrid/polyroot/driver.cxx | 322 +++++++++++++++++ examples/cxx/hybrid/polyroot/makefile | 115 ++++++ examples/cxx/hybrid/polyroot/person.xml | 16 + examples/cxx/hybrid/polyroot/superman.xml | 17 + examples/cxx/hybrid/polyroot/supermen.xsd | 40 +++ examples/cxx/hybrid/streaming/driver.cxx | 1 - examples/cxx/hybrid/wildcard/driver.cxx | 1 - examples/cxx/parser/README | 16 +- examples/cxx/parser/polymorphism/README | 6 +- examples/cxx/serializer/README | 16 +- examples/cxx/serializer/polymorphism/README | 6 +- libxsde/xsde/cxx/hybrid/any-type.cxx | 53 +++ libxsde/xsde/cxx/hybrid/any-type.hxx | 28 ++ libxsde/xsde/cxx/hybrid/parser-map.cxx | 59 +++ libxsde/xsde/cxx/hybrid/parser-map.hxx | 52 +++ libxsde/xsde/cxx/hybrid/serializer-map.cxx | 61 ++++ libxsde/xsde/cxx/hybrid/serializer-map.hxx | 52 +++ libxsde/xsde/cxx/parser/map.cxx | 8 + libxsde/xsde/cxx/parser/map.hxx | 1 + libxsde/xsde/cxx/parser/map.ixx | 2 +- libxsde/xsde/cxx/serializer/map.cxx | 8 + libxsde/xsde/cxx/serializer/map.hxx | 1 + libxsde/xsde/cxx/serializer/map.ixx | 2 +- libxsde/xsde/makefile | 6 + tests/cxx/hybrid/makefile | 2 +- tests/cxx/hybrid/polymorphism/any-type/driver.cxx | 59 +++ tests/cxx/hybrid/polymorphism/any-type/makefile | 99 +++++ tests/cxx/hybrid/polymorphism/any-type/test.xml | 7 + tests/cxx/hybrid/polymorphism/any-type/test.xsd | 37 ++ tests/cxx/hybrid/polymorphism/makefile | 24 ++ .../cxx/hybrid/polymorphism/multischema/driver.cxx | 60 ++++ tests/cxx/hybrid/polymorphism/multischema/makefile | 100 ++++++ tests/cxx/hybrid/polymorphism/multischema/output | 1 + tests/cxx/hybrid/polymorphism/multischema/test.xml | 7 + tests/cxx/hybrid/polymorphism/multischema/test.xsd | 28 ++ tests/cxx/hybrid/polymorphism/multischema/type.xsd | 26 ++ xsde/cxx/elements.cxx | 9 +- xsde/cxx/hybrid/aggregate-elements.hxx | 31 ++ xsde/cxx/hybrid/aggregate-include.hxx | 223 ++++++++++++ xsde/cxx/hybrid/cli.hxx | 10 + xsde/cxx/hybrid/elements.cxx | 7 +- xsde/cxx/hybrid/elements.hxx | 12 +- xsde/cxx/hybrid/generator.cxx | 130 ++++++- xsde/cxx/hybrid/generator.hxx | 63 +++- xsde/cxx/hybrid/parser-aggregate-header.cxx | 315 ++++++++++++---- xsde/cxx/hybrid/parser-aggregate-source.cxx | 162 ++++++++- xsde/cxx/hybrid/parser-header.cxx | 35 ++ xsde/cxx/hybrid/parser-name-processor.cxx | 11 +- xsde/cxx/hybrid/parser-name-processor.hxx | 3 +- xsde/cxx/hybrid/parser-source.cxx | 52 +++ xsde/cxx/hybrid/serializer-aggregate-header.cxx | 330 +++++++++++++---- xsde/cxx/hybrid/serializer-aggregate-source.cxx | 169 ++++++++- xsde/cxx/hybrid/serializer-header.cxx | 35 ++ xsde/cxx/hybrid/serializer-name-processor.cxx | 13 +- xsde/cxx/hybrid/serializer-name-processor.hxx | 3 +- xsde/cxx/hybrid/serializer-source.cxx | 100 ++++++ xsde/cxx/hybrid/tree-header.cxx | 94 ++++- xsde/cxx/hybrid/tree-inline.cxx | 9 - xsde/cxx/hybrid/tree-name-processor.cxx | 13 +- xsde/cxx/hybrid/tree-name-processor.hxx | 3 +- xsde/cxx/hybrid/tree-size-processor.cxx | 274 ++++++++++++-- xsde/cxx/hybrid/tree-size-processor.hxx | 5 +- xsde/cxx/hybrid/tree-source.cxx | 225 +++++++++++- xsde/cxx/hybrid/validator.cxx | 9 +- xsde/cxx/parser/generator.cxx | 10 +- xsde/cxx/parser/generator.hxx | 17 +- xsde/cxx/parser/name-processor.cxx | 11 +- xsde/cxx/parser/name-processor.hxx | 5 +- xsde/cxx/parser/validator.cxx | 2 + xsde/cxx/serializer/generator.cxx | 10 +- xsde/cxx/serializer/generator.hxx | 17 +- xsde/cxx/serializer/name-processor.cxx | 11 +- xsde/cxx/serializer/name-processor.hxx | 5 +- xsde/cxx/serializer/validator.cxx | 2 + xsde/xsde.cxx | 202 +++++++++-- 128 files changed, 4985 insertions(+), 363 deletions(-) create mode 100644 dist/examples/cxx/hybrid/polymorphism/makefile create mode 100644 dist/examples/cxx/hybrid/polymorphism/nmakefile create mode 100644 dist/examples/cxx/hybrid/polyroot/makefile create mode 100644 dist/examples/cxx/hybrid/polyroot/nmakefile create mode 100644 examples/cxx/hybrid/polymorphism/README create mode 100644 examples/cxx/hybrid/polymorphism/driver.cxx create mode 100644 examples/cxx/hybrid/polymorphism/makefile create mode 100644 examples/cxx/hybrid/polymorphism/supermen.xml create mode 100644 examples/cxx/hybrid/polymorphism/supermen.xsd create mode 100644 examples/cxx/hybrid/polyroot/README create mode 100644 examples/cxx/hybrid/polyroot/batman.xml create mode 100644 examples/cxx/hybrid/polyroot/driver.cxx create mode 100644 examples/cxx/hybrid/polyroot/makefile create mode 100644 examples/cxx/hybrid/polyroot/person.xml create mode 100644 examples/cxx/hybrid/polyroot/superman.xml create mode 100644 examples/cxx/hybrid/polyroot/supermen.xsd create mode 100644 libxsde/xsde/cxx/hybrid/any-type.cxx create mode 100644 libxsde/xsde/cxx/hybrid/parser-map.cxx create mode 100644 libxsde/xsde/cxx/hybrid/parser-map.hxx create mode 100644 libxsde/xsde/cxx/hybrid/serializer-map.cxx create mode 100644 libxsde/xsde/cxx/hybrid/serializer-map.hxx create mode 100644 tests/cxx/hybrid/polymorphism/any-type/driver.cxx create mode 100644 tests/cxx/hybrid/polymorphism/any-type/makefile create mode 100644 tests/cxx/hybrid/polymorphism/any-type/test.xml create mode 100644 tests/cxx/hybrid/polymorphism/any-type/test.xsd create mode 100644 tests/cxx/hybrid/polymorphism/makefile create mode 100644 tests/cxx/hybrid/polymorphism/multischema/driver.cxx create mode 100644 tests/cxx/hybrid/polymorphism/multischema/makefile create mode 100644 tests/cxx/hybrid/polymorphism/multischema/output create mode 100644 tests/cxx/hybrid/polymorphism/multischema/test.xml create mode 100644 tests/cxx/hybrid/polymorphism/multischema/test.xsd create mode 100644 tests/cxx/hybrid/polymorphism/multischema/type.xsd create mode 100644 xsde/cxx/hybrid/aggregate-elements.hxx create mode 100644 xsde/cxx/hybrid/aggregate-include.hxx diff --git a/NEWS b/NEWS index 95ccd71..c4c7628 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,15 @@ Version 3.1.0 C++/Hybrid + * Support for XML Schema polymorphism. The new --generate-polymorphic + option triggers generation of polymorphism-aware code. This option + should be used on XML vocabularies which use xsi:type and/or + substitution groups. For more information see Section 3.7, "Support + for Polymorphism" and Section 4.9, "Polymorphic Object Models" in + the Embedded C++/Parser Mapping Getting Started Guide we well as + the polymorphism and polyroot examples in the examples/cxx/hybrid/ + directory. + * Support for saving the object model to and loading it from binary representations. The new --generate--insertion and --generate-extraction options trigger generation of data representation stream insertion and diff --git a/build/xsde/hybrid/xsd-cxx.make b/build/xsde/hybrid/xsd-cxx.make index b221d7a..a4e9eeb 100644 --- a/build/xsde/hybrid/xsd-cxx.make +++ b/build/xsde/hybrid/xsd-cxx.make @@ -81,9 +81,9 @@ ifeq ($(xsde_serializer_validation),n) ops += --suppress-serializer-val endif -#ifeq ($(xsde_polymorphic),y) -#ops += --runtime-polymorphic -#endif +ifeq ($(xsde_polymorphic),y) +ops += --runtime-polymorphic +endif ifeq ($(xsde_reuse_style),mixin) ops += --reuse-style-mixin diff --git a/dist/examples/cxx/hybrid/binary/cdr/makefile b/dist/examples/cxx/hybrid/binary/cdr/makefile index 96c6274..6814623 100644 --- a/dist/examples/cxx/hybrid/binary/cdr/makefile +++ b/dist/examples/cxx/hybrid/binary/cdr/makefile @@ -24,6 +24,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o library.o library-pskel.o library-pimpl.o \ library-sskel.o library-simpl.o $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/binary/cdr/nmakefile b/dist/examples/cxx/hybrid/binary/cdr/nmakefile index a87ded2..f08cd4c 100644 --- a/dist/examples/cxx/hybrid/binary/cdr/nmakefile +++ b/dist/examples/cxx/hybrid/binary/cdr/nmakefile @@ -24,6 +24,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj library.obj library-pskel.obj library-pimpl.obj \ library-sskel.obj library-simpl.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/binary/custom/makefile b/dist/examples/cxx/hybrid/binary/custom/makefile index c0e57ad..39ba93c 100644 --- a/dist/examples/cxx/hybrid/binary/custom/makefile +++ b/dist/examples/cxx/hybrid/binary/custom/makefile @@ -22,6 +22,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o library.o library-pskel.o library-pimpl.o \ library-sskel.o library-simpl.o exceptions.o orawstream.o \ irawstream.o $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/binary/custom/nmakefile b/dist/examples/cxx/hybrid/binary/custom/nmakefile index b53db8e..c99b887 100644 --- a/dist/examples/cxx/hybrid/binary/custom/nmakefile +++ b/dist/examples/cxx/hybrid/binary/custom/nmakefile @@ -22,6 +22,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj library.obj library-pskel.obj library-pimpl.obj \ library-sskel.obj library-simpl.obj exceptions.obj orawstream.obj \ irawstream.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/binary/xdr/makefile b/dist/examples/cxx/hybrid/binary/xdr/makefile index 95ceade..ede26ea 100644 --- a/dist/examples/cxx/hybrid/binary/xdr/makefile +++ b/dist/examples/cxx/hybrid/binary/xdr/makefile @@ -24,6 +24,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o library.o library-pskel.o library-pimpl.o \ library-sskel.o library-simpl.o $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/binary/xdr/nmakefile b/dist/examples/cxx/hybrid/binary/xdr/nmakefile index f71e178..2930de2 100644 --- a/dist/examples/cxx/hybrid/binary/xdr/nmakefile +++ b/dist/examples/cxx/hybrid/binary/xdr/nmakefile @@ -22,6 +22,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj library.obj library-pskel.obj library-pimpl.obj \ library-sskel.obj library-simpl.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/compositors/makefile b/dist/examples/cxx/hybrid/compositors/makefile index fbc44f9..d030bf4 100644 --- a/dist/examples/cxx/hybrid/compositors/makefile +++ b/dist/examples/cxx/hybrid/compositors/makefile @@ -30,6 +30,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o compositors.o $(root)/libxsde/xsde/libxsde.a driver.o: driver.cxx compositors.hxx diff --git a/dist/examples/cxx/hybrid/compositors/nmakefile b/dist/examples/cxx/hybrid/compositors/nmakefile index 9bc77b7..b51cbe3 100644 --- a/dist/examples/cxx/hybrid/compositors/nmakefile +++ b/dist/examples/cxx/hybrid/compositors/nmakefile @@ -30,6 +30,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj compositors.obj $(root)\libxsde\xsde\xsde.lib driver.obj: driver.cxx compositors.hxx diff --git a/dist/examples/cxx/hybrid/custom/wildcard/makefile b/dist/examples/cxx/hybrid/custom/wildcard/makefile index e0a881d..71283bb 100644 --- a/dist/examples/cxx/hybrid/custom/wildcard/makefile +++ b/dist/examples/cxx/hybrid/custom/wildcard/makefile @@ -18,6 +18,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +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 diff --git a/dist/examples/cxx/hybrid/custom/wildcard/nmakefile b/dist/examples/cxx/hybrid/custom/wildcard/nmakefile index 0a88820..33f3570 100644 --- a/dist/examples/cxx/hybrid/custom/wildcard/nmakefile +++ b/dist/examples/cxx/hybrid/custom/wildcard/nmakefile @@ -18,6 +18,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!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 diff --git a/dist/examples/cxx/hybrid/filter/makefile b/dist/examples/cxx/hybrid/filter/makefile index f1ea235..f9137fc 100644 --- a/dist/examples/cxx/hybrid/filter/makefile +++ b/dist/examples/cxx/hybrid/filter/makefile @@ -18,6 +18,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o people.o people-pskel.o people-pimpl.o people-sskel.o \ people-simpl.o people-custom-pimpl.o people-custom-simpl.o \ $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/filter/nmakefile b/dist/examples/cxx/hybrid/filter/nmakefile index b93ac66..0343a90 100644 --- a/dist/examples/cxx/hybrid/filter/nmakefile +++ b/dist/examples/cxx/hybrid/filter/nmakefile @@ -18,6 +18,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj people.obj people-pskel.obj people-pimpl.obj \ people-sskel.obj people-simpl.obj people-custom-pimpl.obj \ people-custom-simpl.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/hello/makefile b/dist/examples/cxx/hybrid/hello/makefile index f184264..3a6f645 100644 --- a/dist/examples/cxx/hybrid/hello/makefile +++ b/dist/examples/cxx/hybrid/hello/makefile @@ -22,6 +22,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o hello.o hello-pskel.o hello-pimpl.o \ $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/hello/nmakefile b/dist/examples/cxx/hybrid/hello/nmakefile index 4044cb1..2e5730f 100644 --- a/dist/examples/cxx/hybrid/hello/nmakefile +++ b/dist/examples/cxx/hybrid/hello/nmakefile @@ -22,6 +22,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj hello.obj hello-pskel.obj hello-pimpl.obj \ $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/library/makefile b/dist/examples/cxx/hybrid/library/makefile index 8610879..be92939 100644 --- a/dist/examples/cxx/hybrid/library/makefile +++ b/dist/examples/cxx/hybrid/library/makefile @@ -18,6 +18,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o library.o library-pskel.o library-pimpl.o \ library-sskel.o library-simpl.o $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/library/nmakefile b/dist/examples/cxx/hybrid/library/nmakefile index 5585416..b5a622b 100644 --- a/dist/examples/cxx/hybrid/library/nmakefile +++ b/dist/examples/cxx/hybrid/library/nmakefile @@ -18,6 +18,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj library.obj library-pskel.obj library-pimpl.obj \ library-sskel.obj library-simpl.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/makefile b/dist/examples/cxx/hybrid/makefile index 11af66b..3a9ddaa 100644 --- a/dist/examples/cxx/hybrid/makefile +++ b/dist/examples/cxx/hybrid/makefile @@ -13,6 +13,10 @@ ifeq ($(XSDE_STL),y) dirs += library wildcard filter endif +ifeq ($(XSDE_POLYMORPHIC),y) +dirs += polymorphism polyroot +endif + endif endif diff --git a/dist/examples/cxx/hybrid/minimal/makefile b/dist/examples/cxx/hybrid/minimal/makefile index 87e5325..14b7008 100644 --- a/dist/examples/cxx/hybrid/minimal/makefile +++ b/dist/examples/cxx/hybrid/minimal/makefile @@ -24,6 +24,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o people.o people-pskel.o people-pimpl.o \ people-sskel.o people-simpl.o $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/minimal/nmakefile b/dist/examples/cxx/hybrid/minimal/nmakefile index 6a1c736..f3faf72 100644 --- a/dist/examples/cxx/hybrid/minimal/nmakefile +++ b/dist/examples/cxx/hybrid/minimal/nmakefile @@ -24,6 +24,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj people.obj people-pskel.obj people-pimpl.obj \ people-sskel.obj people-simpl.obj $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/multiroot/makefile b/dist/examples/cxx/hybrid/multiroot/makefile index 28423c1..d427726 100644 --- a/dist/examples/cxx/hybrid/multiroot/makefile +++ b/dist/examples/cxx/hybrid/multiroot/makefile @@ -22,6 +22,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o protocol.o protocol-pskel.o protocol-pimpl.o \ $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/multiroot/nmakefile b/dist/examples/cxx/hybrid/multiroot/nmakefile index a647e50..bd3ffe3 100644 --- a/dist/examples/cxx/hybrid/multiroot/nmakefile +++ b/dist/examples/cxx/hybrid/multiroot/nmakefile @@ -22,6 +22,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj protocol.obj protocol-pskel.obj protocol-pimpl.obj \ $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/nmakefile b/dist/examples/cxx/hybrid/nmakefile index d9d791c..70d4dfe 100644 --- a/dist/examples/cxx/hybrid/nmakefile +++ b/dist/examples/cxx/hybrid/nmakefile @@ -13,6 +13,10 @@ dirs = $(dirs) hello multiroot streaming dirs = $(dirs) library wildcard filter !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +dirs = $(dirs) polymorphism polyroot +!endif + !endif !endif diff --git a/dist/examples/cxx/hybrid/polymorphism/makefile b/dist/examples/cxx/hybrid/polymorphism/makefile new file mode 100644 index 0000000..353e692 --- /dev/null +++ b/dist/examples/cxx/hybrid/polymorphism/makefile @@ -0,0 +1,56 @@ +root := ../../../.. + +include $(root)/build/cxx/rules.make + +# Build. +# +EXTRA_CPPFLAGS := -I$(root)/libxsde + +ifeq ($(XSDE_STL),n) +EXTRA_XSDFLAGS += --no-stl +endif + +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 supermen.o supermen-pskel.o supermen-pimpl.o \ +supermen-sskel.o supermen-simpl.o $(root)/libxsde/xsde/libxsde.a + +driver.o: driver.cxx supermen.hxx supermen-pimpl.hxx supermen-simpl.hxx +supermen.o: supermen.cxx supermen.hxx +supermen-pskel.o: supermen-pskel.cxx +supermen-pimpl.o: supermen-pimpl.cxx +supermen-simpl.o: supermen-simpl.cxx +supermen-simpl.o: supermen-simpl.cxx + +.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) \ +--generate-parser --generate-serializer --generate-aggregate \ +--generate-polymorphic --generate-typeinfo --root-element supermen $< + +# Test. +# +.PHONY: test +test: driver supermen.xml + ./driver supermen.xml + +# Clean. +# +.PHONY: clean +clean: + rm -f supermen-pimpl.?xx supermen-pskel.?xx supermen-simpl.?xx \ +supermen-sskel.?xx supermen.?xx supermen-pimpl.o supermen-pskel.o \ +supermen-simpl.o supermen-sskel.o supermen.o driver.o driver diff --git a/dist/examples/cxx/hybrid/polymorphism/nmakefile b/dist/examples/cxx/hybrid/polymorphism/nmakefile new file mode 100644 index 0000000..479a557 --- /dev/null +++ b/dist/examples/cxx/hybrid/polymorphism/nmakefile @@ -0,0 +1,53 @@ +root = ..\..\..\.. + +!include $(root)\build\cxx\rules.nmake + +# Build. +# +EXTRA_CPPFLAGS = /I$(root)\libxsde + +!if "$(XSDE_STL)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --no-stl +!endif + +!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 supermen.obj supermen-pskel.obj supermen-pimpl.obj \ +supermen-sskel.obj supermen-simpl.obj $(root)\libxsde\xsde\xsde.lib + +driver.obj: driver.cxx supermen.hxx supermen-pimpl.hxx supermen-simpl.hxx +supermen.obj: supermen.cxx +supermen-pskel.obj: supermen-pskel.cxx +supermen-pimpl.obj: supermen-pimpl.cxx +supermen-sskel.obj: supermen-sskel.cxx +supermen-simpl.obj: supermen-simpl.cxx + +supermen.cxx supermen.hxx \ +supermen-pskel.cxx supermen-pskel.hxx supermen-pimpl.cxx supermen-pimpl.hxx \ +supermen-sskel.cxx supermen-sskel.hxx supermen-simpl.cxx supermen-simpl.hxx \ +: supermen.xsd + $(root)\bin\xsde.exe cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--generate-parser --generate-serializer --generate-aggregate \ +--generate-polymorphic --generate-typeinfo --root-element supermen supermen.xsd + +# Test. +# +test: driver.exe supermen.xml + .\driver.exe supermen.xml + +# Clean. +# +clean: + -del supermen-pimpl.?xx supermen-pskel.?xx supermen-simpl.?xx \ +supermen-sskel.?xx supermen.?xx supermen-pimpl.obj supermen-pskel.obj \ +supermen-simpl.obj supermen-sskel.obj supermen.obj driver.obj driver.exe diff --git a/dist/examples/cxx/hybrid/polyroot/makefile b/dist/examples/cxx/hybrid/polyroot/makefile new file mode 100644 index 0000000..d38f04c --- /dev/null +++ b/dist/examples/cxx/hybrid/polyroot/makefile @@ -0,0 +1,58 @@ +root := ../../../.. + +include $(root)/build/cxx/rules.make + +# Build. +# +EXTRA_CPPFLAGS := -I$(root)/libxsde + +ifeq ($(XSDE_STL),n) +EXTRA_XSDFLAGS += --no-stl +endif + +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 supermen.o supermen-pskel.o supermen-pimpl.o \ +supermen-sskel.o supermen-simpl.o $(root)/libxsde/xsde/libxsde.a + +driver.o: driver.cxx supermen.hxx supermen-pimpl.hxx supermen-simpl.hxx +supermen.o: supermen.cxx supermen.hxx +supermen-pskel.o: supermen-pskel.cxx +supermen-pimpl.o: supermen-pimpl.cxx +supermen-simpl.o: supermen-simpl.cxx +supermen-simpl.o: supermen-simpl.cxx + +.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) \ +--generate-parser --generate-serializer --generate-aggregate \ +--generate-polymorphic --generate-typeinfo --root-element person $< + +# Test. +# +.PHONY: test +test: driver person.xml batman.xml superman.xml + ./driver person.xml + ./driver batman.xml + ./driver superman.xml + +# Clean. +# +.PHONY: clean +clean: + rm -f supermen-pimpl.?xx supermen-pskel.?xx supermen-simpl.?xx \ +supermen-sskel.?xx supermen.?xx supermen-pimpl.o supermen-pskel.o \ +supermen-simpl.o supermen-sskel.o supermen.o driver.o driver diff --git a/dist/examples/cxx/hybrid/polyroot/nmakefile b/dist/examples/cxx/hybrid/polyroot/nmakefile new file mode 100644 index 0000000..8d098bb --- /dev/null +++ b/dist/examples/cxx/hybrid/polyroot/nmakefile @@ -0,0 +1,55 @@ +root = ..\..\..\.. + +!include $(root)\build\cxx\rules.nmake + +# Build. +# +EXTRA_CPPFLAGS = /I$(root)\libxsde + +!if "$(XSDE_STL)" == "n" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --no-stl +!endif + +!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 supermen.obj supermen-pskel.obj supermen-pimpl.obj \ +supermen-sskel.obj supermen-simpl.obj $(root)\libxsde\xsde\xsde.lib + +driver.obj: driver.cxx supermen.hxx supermen-pimpl.hxx supermen-simpl.hxx +supermen.obj: supermen.cxx +supermen-pskel.obj: supermen-pskel.cxx +supermen-pimpl.obj: supermen-pimpl.cxx +supermen-sskel.obj: supermen-sskel.cxx +supermen-simpl.obj: supermen-simpl.cxx + +supermen.cxx supermen.hxx \ +supermen-pskel.cxx supermen-pskel.hxx supermen-pimpl.cxx supermen-pimpl.hxx \ +supermen-sskel.cxx supermen-sskel.hxx supermen-simpl.cxx supermen-simpl.hxx \ +: supermen.xsd + $(root)\bin\xsde.exe cxx-hybrid $(XSDFLAGS) $(EXTRA_XSDFLAGS) \ +--generate-parser --generate-serializer --generate-aggregate \ +--generate-polymorphic --generate-typeinfo --root-element person supermen.xsd + +# Test. +# +test: driver.exe person.xml batman.xml superman.xml + .\driver person.xml + .\driver batman.xml + .\driver superman.xml + +# Clean. +# +clean: + -del supermen-pimpl.?xx supermen-pskel.?xx supermen-simpl.?xx \ +supermen-sskel.?xx supermen.?xx supermen-pimpl.obj supermen-pskel.obj \ +supermen-simpl.obj supermen-sskel.obj supermen.obj driver.obj driver.exe diff --git a/dist/examples/cxx/hybrid/streaming/makefile b/dist/examples/cxx/hybrid/streaming/makefile index b4bff7a..7a7a440 100644 --- a/dist/examples/cxx/hybrid/streaming/makefile +++ b/dist/examples/cxx/hybrid/streaming/makefile @@ -22,6 +22,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +endif + driver: driver.o position.o position-pskel.o position-pimpl.o \ position-sskel.o position-simpl.o object-pimpl.o object-simpl.o \ $(root)/libxsde/xsde/libxsde.a diff --git a/dist/examples/cxx/hybrid/streaming/nmakefile b/dist/examples/cxx/hybrid/streaming/nmakefile index c3ae34a..a981d82 100644 --- a/dist/examples/cxx/hybrid/streaming/nmakefile +++ b/dist/examples/cxx/hybrid/streaming/nmakefile @@ -22,6 +22,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!endif + driver.exe: driver.obj position.obj position-pskel.obj position-pimpl.obj \ position-sskel.obj position-simpl.obj object-pimpl.obj object-simpl.obj \ $(root)\libxsde\xsde\xsde.lib diff --git a/dist/examples/cxx/hybrid/wildcard/makefile b/dist/examples/cxx/hybrid/wildcard/makefile index 9d4dfa2..876003f 100644 --- a/dist/examples/cxx/hybrid/wildcard/makefile +++ b/dist/examples/cxx/hybrid/wildcard/makefile @@ -18,6 +18,10 @@ ifeq ($(XSDE_REUSE_STYLE),mixin) EXTRA_XSDFLAGS += --reuse-style-mixin endif +ifeq ($(XSDE_POLYMORPHIC),y) +EXTRA_XSDFLAGS += --runtime-polymorphic +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 diff --git a/dist/examples/cxx/hybrid/wildcard/nmakefile b/dist/examples/cxx/hybrid/wildcard/nmakefile index acdb033..83e3ba0 100644 --- a/dist/examples/cxx/hybrid/wildcard/nmakefile +++ b/dist/examples/cxx/hybrid/wildcard/nmakefile @@ -18,6 +18,10 @@ EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --suppress-validation EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --reuse-style-mixin !endif +!if "$(XSDE_POLYMORPHIC)" == "y" +EXTRA_XSDFLAGS = $(EXTRA_XSDFLAGS) --runtime-polymorphic +!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 diff --git a/dist/libxsde/xsde/makefile b/dist/libxsde/xsde/makefile index eb1abb3..142c269 100644 --- a/dist/libxsde/xsde/makefile +++ b/dist/libxsde/xsde/makefile @@ -49,6 +49,12 @@ endif ## src += cxx/hybrid/sequence.cxx +ifeq ($(XSDE_POLYMORPHIC),y) +src += \ +cxx/hybrid/parser-map.cxx \ +cxx/hybrid/serializer-map.cxx +endif + ifeq ($(XSDE_CDR),y) src += \ cxx/hybrid/cdr/exceptions.cxx \ diff --git a/dist/libxsde/xsde/nmakefile b/dist/libxsde/xsde/nmakefile index fb2789a..888ca15 100644 --- a/dist/libxsde/xsde/nmakefile +++ b/dist/libxsde/xsde/nmakefile @@ -51,6 +51,12 @@ src = $(src) cxx\xml\char-table.cxx cxx\xml\ncname.cxx ## src = $(src) cxx\hybrid\sequence.cxx +!if "$(XSDE_POLYMORPHIC)" == "y" +src = $(src) \ +cxx\hybrid\parser-map.cxx \ +cxx\hybrid\serializer-map.cxx +!endif + !if "$(XSDE_CDR)" == "y" src = $(src) \ cxx\hybrid\cdr\exceptions.cxx \ diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml index 62603dc..5871593 100644 --- a/documentation/cxx/hybrid/guide/index.xhtml +++ b/documentation/cxx/hybrid/guide/index.xhtml @@ -256,6 +256,7 @@ 3.4XML Schema Validation 3.564-bit Integer Type 3.6Parser and Serializer Reuse + 3.7Support for Polymorphism @@ -271,6 +272,7 @@ 4.6Modifying the Object Model 4.7Creating the Object Model from Scratch 4.8Customizing the Object Model + 4.9Polymorphic Object Models @@ -560,7 +562,7 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </hello> @@ -910,7 +912,7 @@ main (int argc, char* argv[]) <hello> <greeting>Hi</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> <name>mars</name> </hello> @@ -1410,6 +1412,154 @@ namespace xml_schema "Serializer Reuse" in the Embedded C++/Serializer Mapping Getting Started Guide for details.

+

3.7 Support for Polymorphism

+ +

By default the XSD/e compiler generates non-polymorphic code. If your + vocabulary uses XML Schema polymorphism in the form of xsi:type + and/or substitution groups, then you will need to configure the XSD/e + runtime with support for polymorphism, compile your schemas with the + --generate-polymorphic option to produce polymorphism-aware + code, as well as pass true as the last argument to the + xml_schema::document_pimpl and + xml_schema::document_simpl constructors (see + Chapter 6, "Parsing and Serialization" for details). + If some of your schemas do not require support for polymorphism then + you can compile them with the --runtime-polymorphic option + and still use the XSD/e runtime configured with polymorphism support. +

+ +

The XSD/e compiler can often automatically determine which types are + polymorphic based on the substitution group declarations. However, + if your XML vocabulary is not using substitution groups or if + substitution groups are defined in a separate schema, then you will + need to use the --polymorphic-type option to specify + which types are polymorphic. When using this option you only need + to specify the root of a polymorphic type hierarchy and the XSD/e + compiler will assume that all the derived types are also polymorphic. + Also note that you need to specify this option when compiling every + schema file that references the polymorphic type. Consider the following + two schemas as an example:

+ +
+<!-- base.xsd -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <xs:complexType name="base">
+    <xs:sequence>
+      <xs:element name="b" type="xs:int"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <!-- substitution group root -->
+  <xs:element name="base" type="base"/>
+
+</xs:schema>
+  
+ +
+<!-- derived.xsd -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <include schemaLocation="base.xsd"/>
+
+  <xs:complexType name="derived">
+    <xs:complexContent>
+      <xs:extension base="base">
+        <xs:sequence>
+          <xs:element name="d" type="xs:string"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:element name="derived" type="derived" substitutionGroup="base"/>
+
+</xs:schema>
+  
+ +

In this example we need to specify "--polymorphic-type base" + when compiling both schemas because the substitution group is declared + in a schema other than the one defining type base.

+ +

Another issue that may arise when compiling polymorphic schemas is + the situation where the XSD/e compiler is unaware of all the + derivations of a polymorphic type while generating parser and + serializer aggregates. As a result, the generated code may not + be able to parse and serialize these "invisible" to the compiler + types. The following example will help illustrate this case. + Consider a modified version of base.xsd from the + above example:

+ +
+<!-- base.xsd -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <xs:complexType name="base">
+    <xs:sequence>
+      <xs:element name="b" type="xs:int"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <!-- substitution group root -->
+  <xs:element name="base" type="base"/>
+
+  <xs:complexType name="root">
+    <xs:sequence>
+      <xs:element ref="base" maxOccurs="unbounded"/>
+    </xs:sequence>
+  </xs:complexType>
+
+  <!-- document root -->
+  <xs:element name="root" type="root"/>
+
+</xs:schema>
+  
+ +

Suppose we compile this schema as follows:

+ +
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd
+  
+ +

The resulting parser and serializer aggregates for the root + element will not include the parser and serializer for the + derived type that can be used instead of the + base type. This is because the XSD/e compiler + has no knowledge of the derived's existence when + compiling base.xsd.

+ +

There are two ways to overcome this problem. The easier but + potentially slower approach is to compile all your schemas + at once, for example:

+ +
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root base.xsd derived.xsd
+  
+ +

This will make sure the XSD/e compiler "sees" all the derivations + of the polymorphic types. The other approach allows + you to explicitly specify, with the --polymorphic-schema + option, additional schemas that may contain derivations of the + polymorphic types. Using this approach we would compile + base.xsd and derived.xsd like this:

+ +
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base \
+--generate-aggregate --root-element root \
+--polymorphic-schema derived.xsd base.xsd
+
+$ xsde cxx-hybrid --generate-parser --generate-serializer \
+--generate-polymorphic --polymorphic-type base derived.xsd
+  
+ +

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

+ @@ -1672,6 +1822,9 @@ private:
  • it is recursive (that is, one of its elements contains a reference, directly or indirectly, to the type itself)
  • + +
  • it is polymorphic (see Section 4.9, "Polymorphic + Object Models" for details)
  • The following build-in XML Schema types are variable-length: @@ -3536,6 +3689,246 @@ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) +

    4.9 Polymorphic Object Models

    + +

    When generating polymorphism-aware code (see Section + 3.7, "Support for Polymorphism"), some objects + in the resulting object model will be polymorphic. By polymorphic + we mean that the object's (static) type as specified in the + object model's interface may differ from the object's actual + (dynamic) type. Because of this, it may be necessary to discover + the object's actual type at runtime and cast it to this type to + gain access to the object's extended interface. Consider the + following schema as an example:

    + +
    +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    +
    +  <xs:complexType name="person">
    +    <xs:sequence>
    +      <xs:element name="name" type="xs:string"/>
    +    </xs:sequence>
    +  </xs:complexType>
    +
    +  <!-- substitution group root -->
    +  <xs:element name="person" type="person"/>
    +
    +  <xs:complexType name="superman">
    +    <xs:complexContent>
    +      <xs:extension base="person">
    +        <xs:attribute name="can-fly" type="xs:boolean"/>
    +      </xs:extension>
    +    </xs:complexContent>
    +  </xs:complexType>
    +
    +  <xs:element name="superman"
    +              type="superman"
    +              substitutionGroup="person"/>
    +
    +  <xs:complexType name="batman">
    +    <xs:complexContent>
    +      <xs:extension base="superman">
    +        <xs:attribute name="wing-span" type="xs:unsignedInt"/>
    +      </xs:extension>
    +    </xs:complexContent>
    +  </xs:complexType>
    +
    +  <xs:element name="batman"
    +              type="batman"
    +              substitutionGroup="superman"/>
    +
    +  <xs:complexType name="supermen">
    +    <xs:sequence>
    +      <xs:element ref="person" maxOccurs="unbounded"/>
    +    </xs:sequence>
    +  </xs:complexType>
    +
    +  <xs:element name="supermen" type="supermen"/>
    +
    +</xs:schema>
    +  
    + +

    Conforming XML documents can use the superman + and batman types in place of the person + type either by specifying the type with the xsi:type + attributes or by using the elements from the substitution + group, for instance:

    + + +
    +<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    +
    +  <person>
    +    <name>John Doe</name>
    +  </person>
    +
    +  <superman can-fly="false">
    +    <name>James "007" Bond</name>
    +  </superman>
    +
    +  <superman can-fly="true" wing-span="10" xsi:type="batman">
    +    <name>Bruce Wayne</name>
    +  </superman>
    +
    +</supermen>
    +  
    + +

    When compiling the schema above with the + --generate-polymorphic option, the XSD/e compiler + automatically detects that the type hierarchy starting with + the person type is polymorphic. A polymorphic + type is always variable-length which means objects of polymorphic + types are allocated dynamically and are stored and passed around + as pointers or references. A polymorphic type also defines a + virtual destructor which allows you to delete an instance of a + polymorphic type via a pointer to its base. The following code + fragment shows how we can parse, access, modify, and serialize + the above XML document:

    + +
    +// Parse.
    +//
    +supermen_paggr supermen_p;
    +
    +// The last argument to the document's constructor indicates that we
    +// are parsing polymorphic XML documents.
    +//
    +xml_schema::document_pimpl doc_p (
    +  supermen_p.root_parser (),
    +  supermen_p.root_name (),
    +  true);
    +
    +supermen_p.pre ();
    +doc_p.parse ("supermen.xml");
    +auto_ptr<supermen> sm (supermen_p.post ());
    +
    +// Print what we've got.
    +//
    +for (supermen::person_iterator i = sm->person ().begin ();
    +     i != sm->person ().end ();
    +     ++i)
    +{
    +  person& p = *i;
    +
    +  if (batman* b = dynamic_cast<batman*> (&p))
    +  {
    +    cerr << b->name () << ", batman, wing span " <<
    +      b->wing_span () << endl;
    +  }
    +  else if (superman* s = dynamic_cast<superman*> (&p))
    +  {
    +    cerr << s->name () << ", ";
    +
    +    if (s->can_fly ())
    +      cerr << "flying ";
    +
    +    cerr << "superman" << endl;
    +  }
    +  else
    +  {
    +    cerr << p.name () << ", ordinary person" << endl;
    +  }
    +}
    +
    +// Add another superman entry.
    +//
    +auto_ptr<superman> s (new superman);
    +s->name ("Clark Kent");
    +s->can_fly (true);
    +sm->person ().push_back (s.release ());
    +
    +// Serialize.
    +//
    +supermen_saggr supermen_s;
    +
    +// The last argument to the document's constructor indicates that we
    +// are serializing polymorphic XML documents.
    +//
    +xml_schema::document_simpl doc_s (
    +  supermen_s.root_serializer (),
    +  supermen_s.root_name (),
    +  true);
    +
    +doc_s.add_no_namespace_schema ("supermen.xsd");
    +
    +supermen_s.pre (*sm);
    +doc_s.serialize (cout);
    +supermen_s.post ();
    +  
    + +

    In the example above we used the standard C++ RTTI mechanism + to detect the object's actual (dynamic) type. If RTTI is not + available on your platform, then you can request the generation + of custom runtime type information for polymorphic types + with the --generate-typeinfo XSD/e compiler + option. When this option is specified, each polymorphic + type provides the following two public functions:

    + +
    +virtual const std::string&
    +_dynamic_type () const;
    +
    +static const std::string&
    +_static_type ();
    +  
    + +

    Or, if STL is disabled (Section 3.1, "Standard Template + Library"), the following two functions:

    + +
    +virtual const char*
    +_dynamic_type () const;
    +
    +static const char*
    +_static_type ();
    +  
    + +

    The _dynamic_type() function returns the object's + dynamic type id. The _static_type() function + returns the type's static id that can be compared to the + dynamic id. The following code fragment shows how + we can change the previous example to use custom type information + instead of C++ RTTI:

    + +
    +for (supermen::person_iterator i = sm->person ().begin ();
    +     i != sm->person ().end ();
    +     ++i)
    +{
    +  person& p = *i;
    +  const string& dt = p._dynamic_type ();
    +
    +  if (dt == batman::_static_type ())
    +  {
    +    batman& b = static_cast<batman&> (p)
    +    cerr << b.name () << ", batman, wing span " <<
    +      b.wing_span () << endl;
    +  }
    +  else if (dt == superman::_static_type ())
    +  {
    +    superman& s = static_cast<superman&> (p)
    +    cerr << s.name () << ", ";
    +
    +    if (s.can_fly ())
    +      cerr << "flying ";
    +
    +    cerr << "superman" << endl;
    +  }
    +  else
    +  {
    +    cerr << p.name () << ", ordinary person" << endl;
    +  }
    +}
    +  
    + +

    Most of the code presented in this section is taken from the + polymorphism example which can be found in the + examples/cxx/hybrid/ directory of the XSD/e distribution. + Handling of xsi:type and substitution groups when used + on root elements requires a number of special actions as shown in + the polyroot example.

    + + diff --git a/documentation/cxx/parser/guide/index.xhtml b/documentation/cxx/parser/guide/index.xhtml index 85b5092..ac69845 100644 --- a/documentation/cxx/parser/guide/index.xhtml +++ b/documentation/cxx/parser/guide/index.xhtml @@ -522,7 +522,7 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </hello> @@ -2322,7 +2322,7 @@ protected: runtime with support for polymorphism, compile your schemas with the --generate-polymorphic option to produce polymorphism-aware code, as well as pass true as the last argument to the - xml_schema::document's constructors. If some of your + xml_schema::document_pimpl's constructors. If some of your schemas do not require support for polymorphism then you can compile them with the --runtime-polymorphic option and still use the XSD/e runtime configured with polymorphism support. diff --git a/documentation/cxx/serializer/guide/index.xhtml b/documentation/cxx/serializer/guide/index.xhtml index 4deacf0..bd681cc 100644 --- a/documentation/cxx/serializer/guide/index.xhtml +++ b/documentation/cxx/serializer/guide/index.xhtml @@ -529,7 +529,7 @@ <greeting>Hello</greeting> <name>sun</name> - <name>earth</name> + <name>moon</name> <name>world</name> </hello> diff --git a/documentation/xsde.1 b/documentation/xsde.1 index f9fe998..62cc55d 100644 --- a/documentation/xsde.1 +++ b/documentation/xsde.1 @@ -1005,6 +1005,43 @@ Suppress the generation of parser and serializer reset code. Reset support allows you to reuse parsers and serializers after an error. +.IP "\fB\--generate-polymorphic\fR" +Generate polymorphism-aware code. Specify this option if you use substitution +groups or +.BR xsi:type . +Use the +.B --polymorphic-type +option to specify which type hierarchies are polymorphic. + +.IP "\fB\--runtime-polymorphic\fR" +Generate non-polymorphic code that uses the runtime library configured with +polymorphism support. + +.IP "\fB\--polymorphic-type \fItype\fR" +Indicate that +.I type +is a root of a polymorphic type hierarchy. The compiler can often +automatically determine which types are polymorphic based on the +substitution group declarations. However, you may need to use this +option if you are not using substitution groups or if substitution +groups are defined in another schema. You need to specify this option +when compiling every schema file that references +.IR type . + +.IP "\fB\--generate-typeinfo\fR" +Generate custom type information querying functions for polymorphic +object model types. These functions can be used instead of the standard +C++ RTTI mechanism to determine object's type at runtime. + +.IP "\fB\--polymorphic-schema \fIfile\fR" +Indicate that +.I file +contains derivations of polymorphic types that are not otherwise visible +from the schema being compiled. This option is used to make sure that +during the generation of parser and serializer aggregates the compiler +is aware of all possible derivations of polymorphic types. Repeat this +option to specify more than one schema file. + .IP "\fB\--reuse-style-mixin\fR" Generate code that supports the mixin base parser/serializer implementation reuse style. Note that this reuse style diff --git a/documentation/xsde.xhtml b/documentation/xsde.xhtml index 312d5f9..c8f602a 100644 --- a/documentation/xsde.xhtml +++ b/documentation/xsde.xhtml @@ -870,6 +870,39 @@ Reset support allows you to reuse parsers and serializers after an error. +
    --generate-polymorphic
    +
    Generate polymorphism-aware code. Specify this option if you use + substitution groups or xsi:type. Use the + --polymorphic-type option to specify which + type hierarchies are polymorphic.
    + +
    --runtime-polymorphic
    +
    Generate non-polymorphic code that uses the runtime library + configured with polymorphism support.
    + +
    --polymorphic-type type
    +
    Indicate that type is a root of a polymorphic + type hierarchy. The compiler can often automatically determine + which types are polymorphic based on the substitution group + declarations. However, you may need to use this option if you are + not using substitution groups or if substitution groups are defined + in another schema. You need to specify this option when compiling + every schema file that references type.
    + +
    --generate-typeinfo
    +
    Generate custom type information querying functions for + polymorphic object model types. These functions can be used + instead of the standard C++ RTTI mechanism to determine + object's type at runtime.
    + +
    --polymorphic-schema file
    +
    Indicate that file contains derivations of + polymorphic types that are not otherwise visible from the schema + being compiled. This option is used to make sure that during the + generation of parser and serializer aggregates the compiler is + aware of all possible derivations of polymorphic types. Repeat + this option to specify more than one schema file.
    +
    --reuse-style-mixin
    Generate code that supports the mixin base parser/serializer implementation reuse style. Note that this reuse style @@ -877,7 +910,6 @@ object code size increase for large vocabularies. By default the tiein reuse style is used.
    -
    --custom-data type
    Add the ability to store custom data to the C++ class generated for XML Schema type type. To add custom diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README index d23c10d..7d9312d 100644 --- a/examples/cxx/hybrid/README +++ b/examples/cxx/hybrid/README @@ -36,6 +36,14 @@ compositors Shows how to create, access, and modify object models with complex nested choice and sequence compositors. +polymorphism + Shows how to handle XML vocabularies that use XML Schema polymorphism + features such as the xsi:type attribute and substitution groups. + +polyroot + Shows how to handle XML vocabularies with polymorphic document root + elements. + 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 diff --git a/examples/cxx/hybrid/binary/xdr/driver.cxx b/examples/cxx/hybrid/binary/xdr/driver.cxx index e629849..d587817 100644 --- a/examples/cxx/hybrid/binary/xdr/driver.cxx +++ b/examples/cxx/hybrid/binary/xdr/driver.cxx @@ -10,7 +10,6 @@ #include #include "library.hxx" - #include "library-pimpl.hxx" #include "library-simpl.hxx" diff --git a/examples/cxx/hybrid/custom/wildcard/driver.cxx b/examples/cxx/hybrid/custom/wildcard/driver.cxx index 02870fa..f5b05ee 100644 --- a/examples/cxx/hybrid/custom/wildcard/driver.cxx +++ b/examples/cxx/hybrid/custom/wildcard/driver.cxx @@ -7,7 +7,6 @@ #include #include "email.hxx" - #include "email-pimpl.hxx" #include "email-simpl.hxx" diff --git a/examples/cxx/hybrid/filter/driver.cxx b/examples/cxx/hybrid/filter/driver.cxx index 9bc9f64..5c15cef 100644 --- a/examples/cxx/hybrid/filter/driver.cxx +++ b/examples/cxx/hybrid/filter/driver.cxx @@ -6,7 +6,6 @@ #include #include "people.hxx" - #include "people-pimpl.hxx" #include "people-simpl.hxx" diff --git a/examples/cxx/hybrid/library/driver.cxx b/examples/cxx/hybrid/library/driver.cxx index 2bde50d..628831a 100644 --- a/examples/cxx/hybrid/library/driver.cxx +++ b/examples/cxx/hybrid/library/driver.cxx @@ -6,7 +6,6 @@ #include #include "library.hxx" - #include "library-pimpl.hxx" #include "library-simpl.hxx" diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile index 2defdc5..cc886ec 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 custom hello multiroot streaming \ -library wildcard filter minimal +all_examples := binary compositors custom hello multiroot polymorphism \ +polyroot streaming library wildcard filter minimal build_examples := binary compositors custom @@ -19,6 +19,10 @@ ifeq ($(xsde_stl),y) build_examples += library wildcard filter endif +ifeq ($(xsde_polymorphic),y) +build_examples += polymorphism polyroot +endif + endif endif diff --git a/examples/cxx/hybrid/minimal/driver.cxx b/examples/cxx/hybrid/minimal/driver.cxx index e876b6f..e8e8312 100644 --- a/examples/cxx/hybrid/minimal/driver.cxx +++ b/examples/cxx/hybrid/minimal/driver.cxx @@ -5,7 +5,6 @@ #include #include "people.hxx" - #include "people-pimpl.hxx" #include "people-simpl.hxx" diff --git a/examples/cxx/hybrid/polymorphism/README b/examples/cxx/hybrid/polymorphism/README new file mode 100644 index 0000000..2e00636 --- /dev/null +++ b/examples/cxx/hybrid/polymorphism/README @@ -0,0 +1,57 @@ +This example shows how to handle XML vocabularies that use the XML +Schema polymorphism features such as the xsi:type attribute and +substitution groups in the Embedded C++/Hybrid mapping. The case +where xsi:type or substitution groups are used on document root +elements is covered in the polyroot examples. + +The example consists of the following files: + +supermen.xsd + XML Schema which describes supermen instance documents. + +supermen.xml + Sample XML instance document. + +supermen.hxx +supermen.cxx + +supermen-pskel.hxx +supermen-pskel.cxx +supermen-pimpl.hxx +supermen-pimpl.cxx + +supermen-pskel.hxx +supermen-pskel.cxx +supermen-pimpl.hxx +supermen-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 + supermen.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation + of the parsing and serialization code. The --generate-polymorphic + option was used to request the generation of the polymorphism-aware + code. Since our vocabulary uses substitution groups, the XSD/e + compiler is able to automatically determine which type hierarchy is + polymorphic (otherwise we would have had to use the --polymorphic-type + option). The --generate-typeinfo option was used to request the + generation of custom type information for polymorphic object model + types. Finally, the --root-element option was used to specify the + document root element. + +driver.cxx + Driver for the example. It first calls the parser that constructs + the object model from the input XML file. It then prints the content + of the object model to STDERR at which point it determines the actual + (dynamic) types of polymorphic objects. Finally, the driver modifies + the object model by adding another polymorphic instance and calls the + serializer to serialize it back to XML. + +To run the example on the sample XML instance document simply execute: + +$ ./driver supermen.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver +// copyright : not copyrighted - public domain + +#include // std::auto_ptr +#include + +#include "supermen.hxx" +#include "supermen-pimpl.hxx" +#include "supermen-simpl.hxx" + +using namespace std; + +void +check_load (); // Defined after main(). + +int +main (int argc, char* argv[]) +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + check_load (); +#endif + + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Parse. + // + supermen_paggr supermen_p; + + // The last argument to the document's constructor indicates that we + // are parsing polymorphic XML documents. + // + xml_schema::document_pimpl doc_p ( + supermen_p.root_parser (), + supermen_p.root_name (), + true); + + supermen_p.pre (); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr sm (supermen_p.post ()); + + // Print what we've got. + // + for (supermen::person_iterator i = sm->person ().begin (); + i != sm->person ().end (); + ++i) + { + person& p = *i; + + // You can use the standard C++ RTTI or custom type information + // provided by the object model (--generate-typeinfo option) to + // detect the object's actual (dynamic) type. + // + if (p._dynamic_type () == batman::_static_type ()) + { + batman& b = static_cast (p); + cerr << b.name () << ", batman, wing span " << b.wing_span () << endl; + } + else if (superman* s = dynamic_cast (&p)) + { + cerr << s->name () << ", "; + + if (s->can_fly ()) + cerr << "flying "; + + cerr << "superman" << endl; + } + else + { + cerr << p.name () << ", ordinary person" << endl; + } + } + + // Add another superman entry. + // + auto_ptr s (new superman); +#ifdef XSDE_STL + s->name ("Clark Kent"); +#else + s->name (xml_schema::strdupx ("Clark Kent")); +#endif + s->can_fly (true); + sm->person ().push_back (s.release ()); + + // Serialize. + // + supermen_saggr supermen_s; + + // The last argument to the document's constructor indicates that we + // are serializing polymorphic XML documents. + // + xml_schema::document_simpl doc_s ( + supermen_s.root_serializer (), + supermen_s.root_name (), + true); + + doc_s.add_no_namespace_schema ("supermen.xsd"); + + supermen_s.pre (*sm); + doc_s.serialize (cout); + supermen_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; +} + +#ifndef NDEBUG +// Check that the load in substitution and inheritance hashmaps is not +// too high. See the C++/Parser and C++/Serializer Mappings Getting +// Started Guides for details. +// +void +check_load () +{ + // Parser. + // + float load = (float) xml_schema::parser_smap_elements (); + load /= xml_schema::parser_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_SMAP_BUCKETS" << endl; + } + +#ifdef XSDE_PARSER_VALIDATION + load = (float) xml_schema::parser_imap_elements (); + load /= xml_schema::parser_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_IMAP_BUCKETS" << endl; + } +#endif + + // Serializer. + // + load = (float) xml_schema::serializer_smap_elements (); + load /= xml_schema::serializer_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKETS" << endl; + } + + load = (float) xml_schema::serializer_smap_bucket_elements (); + load /= xml_schema::serializer_smap_bucket_buckets (); + + if (load > 0.8) + { + cerr << "substitution inner hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS" << endl; + } + +#ifdef XSDE_SERIALIZER_VALIDATION + load = (float) xml_schema::serializer_imap_elements (); + load /= xml_schema::serializer_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_IMAP_BUCKETS" << endl; + } +#endif +} +#endif diff --git a/examples/cxx/hybrid/polymorphism/makefile b/examples/cxx/hybrid/polymorphism/makefile new file mode 100644 index 0000000..5a137eb --- /dev/null +++ b/examples/cxx/hybrid/polymorphism/makefile @@ -0,0 +1,113 @@ +# file : examples/cxx/hybrid/polymorphism/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 := supermen.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +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 --generate-polymorphic --generate-typeinfo \ +--root-element supermen + +$(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)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd) + $(call install-data,$(src_base)/supermen.xml,$(dist_prefix)/$(path)/supermen.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/polymorphism/supermen.xml b/examples/cxx/hybrid/polymorphism/supermen.xml new file mode 100644 index 0000000..bfc9e00 --- /dev/null +++ b/examples/cxx/hybrid/polymorphism/supermen.xml @@ -0,0 +1,26 @@ + + + + + + + + John Doe + + + + James "007" Bond + + + + Bruce Wayne + + + diff --git a/examples/cxx/hybrid/polymorphism/supermen.xsd b/examples/cxx/hybrid/polymorphism/supermen.xsd new file mode 100644 index 0000000..208d560 --- /dev/null +++ b/examples/cxx/hybrid/polymorphism/supermen.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/cxx/hybrid/polyroot/README b/examples/cxx/hybrid/polyroot/README new file mode 100644 index 0000000..3d690f5 --- /dev/null +++ b/examples/cxx/hybrid/polyroot/README @@ -0,0 +1,60 @@ +This example shows how to handle XML vocabularies with polymorphic document +root elements in the Embedded C++/Hybrid mapping. For general coverage of +XML Schema polymorphism handling see the polymorphism example. + +The example consists of the following files: + +supermen.xsd + XML Schema which describes supermen instance documents. + +person.xml +superman.xml +batman.xml + Sample XML instance documents. + +supermen.hxx +supermen.cxx + +supermen-pskel.hxx +supermen-pskel.cxx +supermen-pimpl.hxx +supermen-pimpl.cxx + +supermen-pskel.hxx +supermen-pskel.cxx +supermen-pimpl.hxx +supermen-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 + supermen.xsd. The --generate-parser, --generate-serializer, and + --generate-aggregate options were used to request the generation + of the parsing and serialization code. The --generate-polymorphic + option was used to request the generation of the polymorphism-aware + code. Since our vocabulary uses substitution groups, the XSD/e + compiler is able to automatically determine which type hierarchy is + polymorphic (otherwise we would have had to use the --polymorphic-type + option). The --generate-typeinfo option was used to request the + generation of custom type information for polymorphic object model + types. Finally, the --root-element option was used to specify the + document root element. + +driver.cxx + Driver for the example. It first calls the parser that constructs + the object model from the input XML file. It then prints the content + of the object model to STDERR at which point it determines the actual + (dynamic) types of polymorphic objects. Finally, the driver calls the + serializer to serialize the object model back to XML. + +To run the example on the sample XML instance documents simply execute: + +$ ./driver person.xml +$ ./driver superman.xml +$ ./driver batman.xml + +The example reads from STDIN if input file is not specified: + +$ ./driver + + + + + + Bruce Wayne + + diff --git a/examples/cxx/hybrid/polyroot/driver.cxx b/examples/cxx/hybrid/polyroot/driver.cxx new file mode 100644 index 0000000..f41422c --- /dev/null +++ b/examples/cxx/hybrid/polyroot/driver.cxx @@ -0,0 +1,322 @@ +// file : examples/cxx/hybrid/polyroot/driver.cxx +// author : Boris Kolpackov +// copyright : not copyrighted - public domain + +#include // std::auto_ptr +#include + +#include "supermen.hxx" +#include "supermen-pimpl.hxx" +#include "supermen-simpl.hxx" + +using namespace std; +using xml_schema::ro_string; + +// Customize the xml_schema::document object to handle a polymorphic +// root element. For more information see the polyroot and multiroot +// examples in the examples/cxx/parser/ directory. +// +class document_pimpl: public xml_schema::document_pimpl +{ +public: + // Passing the root element name to xml_schema::document_pimpl + // constructor indicates that we are doing polymorphic parsing. + // The root element name is used to automatically translate + // substitutions to type information. + // + document_pimpl (person_paggr& paggr) + : xml_schema::document_pimpl (person_paggr::root_name ()), + paggr_ (paggr), + parser_used_ (0) + { + } + + person* + result () + { + return result_.release (); + } + +protected: + // This function is called to obtain the root element type parser. + // If the returned pointer is 0 then the whole document content + // is ignored. The type argument contains the XML Schema type + // if xsi:type attribute or an element that substitutes the root + // was specified and 0 otherwise. + // + virtual xml_schema::parser_base* + start_root_element (const ro_string& ns, + const ro_string& name, + const char* type) + { + if (name != person_paggr::root_name () || + ns != person_paggr::root_namespace ()) + { + // If the runtime and the generated code are built with + // validation enabled then we can also set an XML Schema + // error. + // +#ifdef XSDE_PARSER_VALIDATION + context_.schema_error ( + xml_schema::parser_schema_error::unexpected_element); +#endif + return 0; + } + + // Search for the parser. If type is 0 then there is no xsi:type and + // static type should be used. + // + if (type == 0) + parser_used_ = &paggr_.root_parser (); + else + { + // The map returns a generic parser_base which we will cast to + // person_pskel in order to call the pre() and post_person() + // callbacks. If the runtime and the generated code are built + // with the mixin parser reuse style then we have to use + // dynamic_cast because of the virtual inheritance. + // + xml_schema::parser_base* p = paggr_.root_map ().find (type); + +#ifdef XSDE_REUSE_STYLE_MIXIN + parser_used_ = dynamic_cast (p); +#else + parser_used_ = static_cast (p); +#endif + } + + if (parser_used_ != 0) + parser_used_->pre (); + + return parser_used_; + } + + // This function is called to indicate the completion of document + // parsing. The parser argument contains the pointer returned by + // start_root_element. + // + virtual void + end_root_element (const ro_string& /* ns */, + const ro_string& /* name */, + xml_schema::parser_base* /* parser */) + { + // Instead of caching the current parser in parser_used_, we + // could also cast the parser argument to the person_pskel + // type. + // + if (parser_used_ != 0) + result_.reset (parser_used_->post_person ()); + } + +public: + // 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 parser that was used last. Note that you always need + // to call _reset() from the base. + // + virtual void + reset () + { + xml_schema::document_pimpl::reset (); + + if (parser_used_ != 0) + parser_used_->_reset (); + } + +private: + person_paggr& paggr_; + person_pskel* parser_used_; + std::auto_ptr result_; +}; + +void +check_load (); // Defined after main(). + +int +main (int argc, char* argv[]) +{ + // Check that the load in substitution and inheritance hashmaps + // is not too high. + // +#ifndef NDEBUG + check_load (); +#endif + + const char* input; + + if (argc < 2) + { + input = "STDIN"; + cerr << "XML file not specified, reading from STDIN" << endl; + } + else + input = argv[1]; + + try + { + // Parse. + // + person_paggr person_p; + + // Use our customized document parser. It automatically calls + // pre() and post() on the chosen parser and stores the result. + // + document_pimpl doc_p (person_p); + + if (argc < 2) + doc_p.parse (cin); + else + doc_p.parse (argv[1]); + + auto_ptr p (doc_p.result ()); + + // Print what we've got. You can use the standard C++ RTTI or custom + // type information provided by the object model (--generate-typeinfo + // option) to detect the object's actual (dynamic) type. + // + if (p->_dynamic_type () == batman::_static_type ()) + { + batman& b = static_cast (*p); + cerr << b.name () << ", batman, wing span " << b.wing_span () << endl; + } + else if (superman* s = dynamic_cast (p.get ())) + { + cerr << s->name () << ", "; + + if (s->can_fly ()) + cerr << "flying "; + + cerr << "superman" << endl; + } + else + { + cerr << p->name () << ", ordinary person" << endl; + } + + // Serialize. + // + person_saggr person_s; + person_sskel* ps = 0; + + // Determine the root element serializer to use based on the object's + // dynamic type. + // + const string& dt = p->_dynamic_type (); + + if (dt == person::_static_type ()) + ps = &person_s.root_serializer (); + else + { + // The map returns a generic serializer_base which we will cast to + // person_sskel in order to call the pre() and post() callbacks. If + // the runtime and the generated code are built with the mixin + // serializer reuse style then we have to use dynamic_cast because + // of the virtual inheritance. + // + xml_schema::serializer_base* s = + person_s.root_map ().find (dt.c_str ()); + +#ifdef XSDE_REUSE_STYLE_MIXIN + ps = dynamic_cast (s); +#else + ps = static_cast (s); +#endif + } + + // Create a document serializer for this object. Note that we pass + // true as the third argument to indicate polymorphic serialization + // as well as the root element's static type as the last argument + // which is necessary if the actual root type can differ from its + // static type. + // + xml_schema::document_simpl doc_s ( + *ps, person_s.root_name (), true, person_sskel::_static_type ()); + + doc_s.add_no_namespace_schema ("supermen.xsd"); + + ps->pre (*p); + doc_s.serialize (std::cout); + ps->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; +} + +#ifndef NDEBUG +// Check that the load in substitution and inheritance hashmaps is not +// too high. See the C++/Parser and C++/Serializer Mappings Getting +// Started Guides for details. +// +void +check_load () +{ + // Parser. + // + float load = (float) xml_schema::parser_smap_elements (); + load /= xml_schema::parser_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_SMAP_BUCKETS" << endl; + } + +#ifdef XSDE_PARSER_VALIDATION + load = (float) xml_schema::parser_imap_elements (); + load /= xml_schema::parser_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_PARSER_IMAP_BUCKETS" << endl; + } +#endif + + // Serializer. + // + load = (float) xml_schema::serializer_smap_elements (); + load /= xml_schema::serializer_smap_buckets (); + + if (load > 0.8) + { + cerr << "substitution hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKETS" << endl; + } + + load = (float) xml_schema::serializer_smap_bucket_elements (); + load /= xml_schema::serializer_smap_bucket_buckets (); + + if (load > 0.8) + { + cerr << "substitution inner hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_SMAP_BUCKET_BUCKETS" << endl; + } + +#ifdef XSDE_SERIALIZER_VALIDATION + load = (float) xml_schema::serializer_imap_elements (); + load /= xml_schema::serializer_imap_buckets (); + + if (load > 0.8) + { + cerr << "inheritance hashmap load is " << load << endl; + cerr << "time to increase XSDE_SERIALIZER_IMAP_BUCKETS" << endl; + } +#endif +} +#endif diff --git a/examples/cxx/hybrid/polyroot/makefile b/examples/cxx/hybrid/polyroot/makefile new file mode 100644 index 0000000..6bcc4ee --- /dev/null +++ b/examples/cxx/hybrid/polyroot/makefile @@ -0,0 +1,115 @@ +# file : examples/cxx/hybrid/polyroot/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 := supermen.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +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 --generate-polymorphic --generate-typeinfo \ +--root-element person + +$(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)/supermen.xsd,$(dist_prefix)/$(path)/supermen.xsd) + $(call install-data,$(src_base)/person.xml,$(dist_prefix)/$(path)/person.xml) + $(call install-data,$(src_base)/superman.xml,$(dist_prefix)/$(path)/superman.xml) + $(call install-data,$(src_base)/batman.xml,$(dist_prefix)/$(path)/batman.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/polyroot/person.xml b/examples/cxx/hybrid/polyroot/person.xml new file mode 100644 index 0000000..c6ab1ff --- /dev/null +++ b/examples/cxx/hybrid/polyroot/person.xml @@ -0,0 +1,16 @@ + + + + + + + John Doe + + diff --git a/examples/cxx/hybrid/polyroot/superman.xml b/examples/cxx/hybrid/polyroot/superman.xml new file mode 100644 index 0000000..94a4f0b --- /dev/null +++ b/examples/cxx/hybrid/polyroot/superman.xml @@ -0,0 +1,17 @@ + + + + + + + James "007" Bond + + diff --git a/examples/cxx/hybrid/polyroot/supermen.xsd b/examples/cxx/hybrid/polyroot/supermen.xsd new file mode 100644 index 0000000..9178168 --- /dev/null +++ b/examples/cxx/hybrid/polyroot/supermen.xsd @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/cxx/hybrid/streaming/driver.cxx b/examples/cxx/hybrid/streaming/driver.cxx index ab2cd3a..86d0b87 100644 --- a/examples/cxx/hybrid/streaming/driver.cxx +++ b/examples/cxx/hybrid/streaming/driver.cxx @@ -5,7 +5,6 @@ #include #include "position.hxx" - #include "position-pimpl.hxx" #include "position-simpl.hxx" diff --git a/examples/cxx/hybrid/wildcard/driver.cxx b/examples/cxx/hybrid/wildcard/driver.cxx index eea5bc7..69b6e67 100644 --- a/examples/cxx/hybrid/wildcard/driver.cxx +++ b/examples/cxx/hybrid/wildcard/driver.cxx @@ -8,7 +8,6 @@ #include "email.hxx" #include "body.hxx" - #include "email-pimpl.hxx" #include "email-simpl.hxx" diff --git a/examples/cxx/parser/README b/examples/cxx/parser/README index eaf9342..8afc5f9 100644 --- a/examples/cxx/parser/README +++ b/examples/cxx/parser/README @@ -1,7 +1,7 @@ -This directory contains a number of examples that show how to -use the Embedded C++/Parser mapping. The following list gives -an overview of each example. See the README files in example -directories for more information on each example. +This directory contains a number of examples that show how to use the +Embedded C++/Parser mapping. The following list gives an overview of +each example. See the README files in example directories for more +information on each example. hello A simple "Hello, world!" example that shows how to parse XML @@ -30,3 +30,11 @@ multiroot mixed Shows how to handle raw, "type-less content" such as mixed content models, anyType/anySimpleType, and any/anyAttribute. + +polymorphism + Shows how to handle XML vocabularies that use XML Schema polymorphism + features such as the xsi:type attribute and substitution groups. + +polyroot + Shows how to handle XML vocabularies with polymorphic document root + elements. diff --git a/examples/cxx/parser/polymorphism/README b/examples/cxx/parser/polymorphism/README index 0b3d749..88140de 100644 --- a/examples/cxx/parser/polymorphism/README +++ b/examples/cxx/parser/polymorphism/README @@ -1,7 +1,7 @@ -This example shows how to handle XML Schema polymorphism features such +This example shows how to handle the XML Schema polymorphism features such as xsi:type attributes and substitution groups in the Embedded C++/Parser -mapping. The case when xsi:type or substitution groups are used on root -elements is covered in the polyroot examples. +mapping. The case where xsi:type or substitution groups are used on document +root elements is covered in the polyroot examples. The example consists of the following files: diff --git a/examples/cxx/serializer/README b/examples/cxx/serializer/README index fa71ea3..f65f6b8 100644 --- a/examples/cxx/serializer/README +++ b/examples/cxx/serializer/README @@ -1,7 +1,7 @@ -This directory contains a number of examples that show how to -use the Embedded C++/Serializer mapping. The following list -gives an overview of each example. See the README files in -example directories for more information on each example. +This directory contains a number of examples that show how to use the +Embedded C++/Serializer mapping. The following list gives an overview +of each example. See the README files in example directories for more +information on each example. hello A simple "Hello, world!" example that shows how to serialize @@ -18,3 +18,11 @@ minimal wildcard Shows how to serialize XML data matched by XML Schema wildcards (any and anyAttribute). + +polymorphism + Shows how to handle XML vocabularies that use XML Schema polymorphism + features such as the xsi:type attribute and substitution groups. + +polyroot + Shows how to handle XML vocabularies with polymorphic document root + elements. diff --git a/examples/cxx/serializer/polymorphism/README b/examples/cxx/serializer/polymorphism/README index 0e2c5b8..2d1ff6e 100644 --- a/examples/cxx/serializer/polymorphism/README +++ b/examples/cxx/serializer/polymorphism/README @@ -1,7 +1,7 @@ -This example shows how to handle XML Schema polymorphism features such as +This example shows how to handle the XML Schema polymorphism features such as xsi:type attributes and substitution groups in the Embedded C++/Serializer -mapping. The case when xsi:type or substitution groups are used on root -elements is covered in the polyroot examples. +mapping. The case where xsi:type or substitution groups are used on document +root elements is covered in the polyroot examples. The example consists of the following files: diff --git a/libxsde/xsde/cxx/hybrid/any-type.cxx b/libxsde/xsde/cxx/hybrid/any-type.cxx new file mode 100644 index 0000000..b16356c --- /dev/null +++ b/libxsde/xsde/cxx/hybrid/any-type.cxx @@ -0,0 +1,53 @@ +// file : xsde/cxx/hybrid/any-type.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + // any_type + // +#ifdef XSDE_POLYMORPHIC + any_type:: + ~any_type () + { + } + +#ifdef XSDE_STL + const std::string& any_type:: + _dynamic_type () const + { + return _static_type (); + } + + static const std::string any_type_static_type_ = + "anyType http://www.w3.org/2001/XMLSchema"; + + const std::string& any_type:: + _static_type () + { + return any_type_static_type_; + } +#else + const char* any_type:: + _dynamic_type () const + { + return _static_type (); + } + + const char* any_type:: + _static_type () + { + return "anyType http://www.w3.org/2001/XMLSchema"; + } +#endif +#endif + } + } +} diff --git a/libxsde/xsde/cxx/hybrid/any-type.hxx b/libxsde/xsde/cxx/hybrid/any-type.hxx index db512c2..f94f007 100644 --- a/libxsde/xsde/cxx/hybrid/any-type.hxx +++ b/libxsde/xsde/cxx/hybrid/any-type.hxx @@ -6,6 +6,14 @@ #ifndef XSDE_CXX_HYBRID_ANY_TYPE_HXX #define XSDE_CXX_HYBRID_ANY_TYPE_HXX +#include + +/* +#ifdef XSDE_STL +# include +#endif +*/ + namespace xsde { namespace cxx @@ -14,6 +22,26 @@ namespace xsde { struct any_type { + /* +#ifdef XSDE_POLYMORPHIC + virtual + ~any_type (); + +#ifdef XSDE_STL + virtual const std::string& + _dynamic_type () const; + + static const std::string& + _static_type (); +#else + virtual const char* + _dynamic_type () const; + + static const char* + _static_type (); +#endif +#endif + */ }; struct any_simple_type diff --git a/libxsde/xsde/cxx/hybrid/parser-map.cxx b/libxsde/xsde/cxx/hybrid/parser-map.cxx new file mode 100644 index 0000000..c19325c --- /dev/null +++ b/libxsde/xsde/cxx/hybrid/parser-map.cxx @@ -0,0 +1,59 @@ +// file : xsde/cxx/hybrid/parser-map.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include // strcmp + +#include + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + parser::parser_base* parser_map_impl:: + find (const char* tid) const + { + // Binary search. + // + if (size_ == 0) + return 0; + + size_t l = 0; + size_t h = size_ - 1; + + while (l <= h) + { + size_t m = l + (h - l)/2; + int r = strcmp (entries_[m].type_id, tid); + + if (r > 0) + h = m - 1; + else if (r < 0) + l = m + 1; + else + return entries_[m].parser; + } + + return 0; + } + + void parser_map_impl:: + reset () const + { + if (resetting_) + return; + + bool& r = const_cast (resetting_); + r = true; + + for (const entry* p = entries_; p != entries_ + size_; ++p) + p->parser->_reset (); + + r = false; + } + } + } +} diff --git a/libxsde/xsde/cxx/hybrid/parser-map.hxx b/libxsde/xsde/cxx/hybrid/parser-map.hxx new file mode 100644 index 0000000..df84f22 --- /dev/null +++ b/libxsde/xsde/cxx/hybrid/parser-map.hxx @@ -0,0 +1,52 @@ +// file : xsde/cxx/hybrid/parser-map.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSDE_CXX_HYBRID_PARSER_MAP_HXX +#define XSDE_CXX_HYBRID_PARSER_MAP_HXX + +#include // size_t + +#include + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + class parser_map_impl: public parser::parser_map + { + public: + struct entry + { + const char* type_id; + parser::parser_base* parser; + }; + + parser_map_impl (entry* entries, size_t size) + : entries_ (entries), size_ (size), resetting_ (false) + { + } + + virtual parser::parser_base* + find (const char* type_id) const; + + virtual void + reset () const; + + private: + parser_map_impl (const parser_map_impl&); + parser_map_impl& operator= (const parser_map_impl&); + + private: + entry* entries_; + size_t size_; + bool resetting_; + }; + } + } +} + +#endif // XSDE_CXX_HYBRID_PARSER_MAP_HXX diff --git a/libxsde/xsde/cxx/hybrid/serializer-map.cxx b/libxsde/xsde/cxx/hybrid/serializer-map.cxx new file mode 100644 index 0000000..7fce5fd --- /dev/null +++ b/libxsde/xsde/cxx/hybrid/serializer-map.cxx @@ -0,0 +1,61 @@ +// file : xsde/cxx/hybrid/serializer-map.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include // strcmp + +#include + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + serializer::serializer_base* serializer_map_impl:: + find (const void* v) const + { + const char* tid = static_cast (v); + + // Binary search. + // + if (size_ == 0) + return 0; + + size_t l = 0; + size_t h = size_ - 1; + + while (l <= h) + { + size_t m = l + (h - l)/2; + int r = strcmp (entries_[m].type_id, tid); + + if (r > 0) + h = m - 1; + else if (r < 0) + l = m + 1; + else + return entries_[m].serializer; + } + + return 0; + } + + void serializer_map_impl:: + reset () const + { + if (resetting_) + return; + + bool& r = const_cast (resetting_); + r = true; + + for (const entry* p = entries_; p != entries_ + size_; ++p) + p->serializer->_reset (); + + r = false; + } + } + } +} diff --git a/libxsde/xsde/cxx/hybrid/serializer-map.hxx b/libxsde/xsde/cxx/hybrid/serializer-map.hxx new file mode 100644 index 0000000..5e3fb1a --- /dev/null +++ b/libxsde/xsde/cxx/hybrid/serializer-map.hxx @@ -0,0 +1,52 @@ +// file : xsde/cxx/hybrid/serializer-map.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSDE_CXX_HYBRID_SERIALIZER_MAP_HXX +#define XSDE_CXX_HYBRID_SERIALIZER_MAP_HXX + +#include // size_t + +#include + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + class serializer_map_impl: public serializer::serializer_map + { + public: + struct entry + { + const char* type_id; + serializer::serializer_base* serializer; + }; + + serializer_map_impl (entry* entries, size_t size) + : entries_ (entries), size_ (size), resetting_ (true) + { + } + + virtual serializer::serializer_base* + find (const void* type_id) const; + + virtual void + reset () const; + + private: + serializer_map_impl (const serializer_map_impl&); + serializer_map_impl& operator= (const serializer_map_impl&); + + private: + entry* entries_; + size_t size_; + bool resetting_; + }; + } + } +} + +#endif // XSDE_CXX_HYBRID_SERIALIZER_MAP_HXX diff --git a/libxsde/xsde/cxx/parser/map.cxx b/libxsde/xsde/cxx/parser/map.cxx index b21c41e..1382c8d 100644 --- a/libxsde/xsde/cxx/parser/map.cxx +++ b/libxsde/xsde/cxx/parser/map.cxx @@ -23,12 +23,20 @@ namespace xsde void parser_map_impl:: reset () const { + if (resetting_) + return; + + bool& r = const_cast (resetting_); + r = true; + for (hashmap::const_iterator i (map_.begin ()), e (map_.end ()); i != e; ++i) { parser_base* p = *static_cast (*i); p->_reset (); } + + r = false; } } } diff --git a/libxsde/xsde/cxx/parser/map.hxx b/libxsde/xsde/cxx/parser/map.hxx index 400de27..0a5c99c 100644 --- a/libxsde/xsde/cxx/parser/map.hxx +++ b/libxsde/xsde/cxx/parser/map.hxx @@ -77,6 +77,7 @@ namespace xsde private: hashmap map_; + bool resetting_; }; } } diff --git a/libxsde/xsde/cxx/parser/map.ixx b/libxsde/xsde/cxx/parser/map.ixx index 3a1f931..0f5e477 100644 --- a/libxsde/xsde/cxx/parser/map.ixx +++ b/libxsde/xsde/cxx/parser/map.ixx @@ -19,7 +19,7 @@ namespace xsde inline parser_map_impl:: parser_map_impl (size_t buckets) - : map_ (buckets, sizeof (parser_base*)) + : map_ (buckets, sizeof (parser_base*)), resetting_ (false) { } diff --git a/libxsde/xsde/cxx/serializer/map.cxx b/libxsde/xsde/cxx/serializer/map.cxx index 1ace4ac..f3c88f6 100644 --- a/libxsde/xsde/cxx/serializer/map.cxx +++ b/libxsde/xsde/cxx/serializer/map.cxx @@ -23,12 +23,20 @@ namespace xsde void serializer_map_impl:: reset () const { + if (resetting_) + return; + + bool& r = const_cast (resetting_); + r = true; + for (hashmap::const_iterator i (map_.begin ()), e (map_.end ()); i != e; ++i) { serializer_base* s = *static_cast (*i); s->_reset (); } + + r = false; } } } diff --git a/libxsde/xsde/cxx/serializer/map.hxx b/libxsde/xsde/cxx/serializer/map.hxx index 2cfc755..1fe4eb0 100644 --- a/libxsde/xsde/cxx/serializer/map.hxx +++ b/libxsde/xsde/cxx/serializer/map.hxx @@ -86,6 +86,7 @@ namespace xsde private: hashmap map_; + bool resetting_; }; } } diff --git a/libxsde/xsde/cxx/serializer/map.ixx b/libxsde/xsde/cxx/serializer/map.ixx index 64eb19a..e1c2a28 100644 --- a/libxsde/xsde/cxx/serializer/map.ixx +++ b/libxsde/xsde/cxx/serializer/map.ixx @@ -19,7 +19,7 @@ namespace xsde inline serializer_map_impl:: serializer_map_impl (size_t buckets) - : map_ (buckets, sizeof (serializer_base*)) + : map_ (buckets, sizeof (serializer_base*)), resetting_ (false) { } diff --git a/libxsde/xsde/makefile b/libxsde/xsde/makefile index f7d17ed..64368d0 100644 --- a/libxsde/xsde/makefile +++ b/libxsde/xsde/makefile @@ -45,6 +45,12 @@ endif ## cxx_tun += cxx/hybrid/sequence.cxx +ifeq ($(xsde_polymorphic),y) +cxx_tun += \ +cxx/hybrid/parser-map.cxx \ +cxx/hybrid/serializer-map.cxx +endif + ifeq ($(xsde_cdr),y) cxx_tun += \ cxx/hybrid/cdr/exceptions.cxx \ diff --git a/tests/cxx/hybrid/makefile b/tests/cxx/hybrid/makefile index 2ea9a3d..24ed1f0 100644 --- a/tests/cxx/hybrid/makefile +++ b/tests/cxx/hybrid/makefile @@ -5,7 +5,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make -tests := sequences +tests := polymorphism sequences ifeq ($(xsde_iostream),y) tests += built-in list recursive test-template union diff --git a/tests/cxx/hybrid/polymorphism/any-type/driver.cxx b/tests/cxx/hybrid/polymorphism/any-type/driver.cxx new file mode 100644 index 0000000..555c145 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/any-type/driver.cxx @@ -0,0 +1,59 @@ +// file : tests/cxx/hybrid/polymorphism/any-type/driver.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +// Test polymorphic parsing and serialization of anyType-based hierarchy. +// + +#include + +#include "test.hxx" +#include "test-pimpl.hxx" +#include "test-simpl.hxx" + +using namespace std; +using namespace test; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " test.xml" << endl; + return 1; + } + + // Parse. + // + root_paggr root_p; + + xml_schema::document_pimpl doc_p ( + root_p.root_parser (), + root_p.root_namespace (), + root_p.root_name (), + true); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + // Serialize. + // + root_saggr root_s; + + xml_schema::document_simpl doc_s ( + root_s.root_serializer (), + root_s.root_namespace (), + root_s.root_name (), + true); + + doc_s.add_prefix ("t", "test"); + doc_s.add_prefix ("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + root_s.pre (*r); + doc_s.serialize (cout); + root_s.post (); + + delete r; +} diff --git a/tests/cxx/hybrid/polymorphism/any-type/makefile b/tests/cxx/hybrid/polymorphism/any-type/makefile new file mode 100644 index 0000000..57d58f6 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/any-type/makefile @@ -0,0 +1,99 @@ +# file : tests/cxx/hybrid/polymorphism/any-type/makefile +# author : Boris Kolpackov +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := test.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +test := $(out_base)/.test +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 --generate-polymorphic --generate-typeinfo \ +--root-element root --polymorphic-type anyType + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Test. +# +.PHONY: $(test) + +$(test): driver := $(driver) +$(test): $(driver) $(src_base)/test.xml $(src_base)/output + $(call message,test $$1,$$1 $(src_base)/test.xml | diff -ubB $(src_base)/output -,$(driver)) + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/tests/cxx/hybrid/polymorphism/any-type/test.xml b/tests/cxx/hybrid/polymorphism/any-type/test.xml new file mode 100644 index 0000000..f0a8bcb --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/any-type/test.xml @@ -0,0 +1,7 @@ + + + abcjunk123 + 123abc + 123abc987 + + diff --git a/tests/cxx/hybrid/polymorphism/any-type/test.xsd b/tests/cxx/hybrid/polymorphism/any-type/test.xsd new file mode 100644 index 0000000..33b5251 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/any-type/test.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cxx/hybrid/polymorphism/makefile b/tests/cxx/hybrid/polymorphism/makefile new file mode 100644 index 0000000..921ceae --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/makefile @@ -0,0 +1,24 @@ +# file : tests/cxx/hybrid/polymorphism/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 + +tests := + +ifeq ($(xsde_iostream),y) +tests += multischema +endif + +default := $(out_base)/ +test := $(out_base)/.test +clean := $(out_base)/.clean + +.PHONY: $(default) $(test) $(clean) + +$(default): $(addprefix $(out_base)/,$(addsuffix /,$(tests))) +$(test): $(addprefix $(out_base)/,$(addsuffix /.test,$(tests))) +$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(tests))) + +$(foreach t,$(tests),$(call import,$(src_base)/$t/makefile)) diff --git a/tests/cxx/hybrid/polymorphism/multischema/driver.cxx b/tests/cxx/hybrid/polymorphism/multischema/driver.cxx new file mode 100644 index 0000000..895d600 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/driver.cxx @@ -0,0 +1,60 @@ +// file : tests/cxx/hybrid/polymorphism/multischema/driver.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +// Test polymorphic parsing and serialization with the type hierarchy +// split into several schemas. +// + +#include + +#include "test.hxx" +#include "test-pimpl.hxx" +#include "test-simpl.hxx" + +using namespace std; +using namespace test; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " test.xml" << endl; + return 1; + } + + // Parse. + // + root_paggr root_p; + + xml_schema::document_pimpl doc_p ( + root_p.root_parser (), + root_p.root_namespace (), + root_p.root_name (), + true); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + // Serialize. + // + root_saggr root_s; + + xml_schema::document_simpl doc_s ( + root_s.root_serializer (), + root_s.root_namespace (), + root_s.root_name (), + true); + + doc_s.add_prefix ("t", "test"); + doc_s.add_prefix ("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + root_s.pre (*r); + doc_s.serialize (cout); + root_s.post (); + + delete r; +} diff --git a/tests/cxx/hybrid/polymorphism/multischema/makefile b/tests/cxx/hybrid/polymorphism/multischema/makefile new file mode 100644 index 0000000..c0db0f2 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/makefile @@ -0,0 +1,100 @@ +# file : tests/cxx/hybrid/polymorphism/multischema/makefile +# author : Boris Kolpackov +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := test.xsd type.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +test := $(out_base)/.test +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \ + $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \ + $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \ + $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \ + $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx) + +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --generate-polymorphic --generate-typeinfo \ +--polymorphic-type base --polymorphic-schema $(src_base)/type.xsd \ +--include-regex '%.*/([^/]*)%$$$$1%' + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +.PHONY: $(out_base)/ +$(out_base)/: $(driver) + + +# Test. +# +.PHONY: $(test) + +$(test): driver := $(driver) +$(test): $(driver) $(src_base)/test.xml $(src_base)/output + $(call message,test $$1,$$1 $(src_base)/test.xml | diff -ubB $(src_base)/output -,$(driver)) + +# Clean. +# +.PHONY: $(clean) + +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/tests/cxx/hybrid/polymorphism/multischema/output b/tests/cxx/hybrid/polymorphism/multischema/output new file mode 100644 index 0000000..341775b --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/output @@ -0,0 +1 @@ +abc123abctrueabc123true \ No newline at end of file diff --git a/tests/cxx/hybrid/polymorphism/multischema/test.xml b/tests/cxx/hybrid/polymorphism/multischema/test.xml new file mode 100644 index 0000000..d6e3e43 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/test.xml @@ -0,0 +1,7 @@ + + + abc123 + abctrue + abc123true + + diff --git a/tests/cxx/hybrid/polymorphism/multischema/test.xsd b/tests/cxx/hybrid/polymorphism/multischema/test.xsd new file mode 100644 index 0000000..ed5a666 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/test.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cxx/hybrid/polymorphism/multischema/type.xsd b/tests/cxx/hybrid/polymorphism/multischema/type.xsd new file mode 100644 index 0000000..cb93000 --- /dev/null +++ b/tests/cxx/hybrid/polymorphism/multischema/type.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsde/cxx/elements.cxx b/xsde/cxx/elements.cxx index 6116856..79fd6c5 100644 --- a/xsde/cxx/elements.cxx +++ b/xsde/cxx/elements.cxx @@ -194,8 +194,15 @@ namespace CXX if (schema.used ()) { + // Here we need to detect a special multi-schema compilation + // case where the root schemas are imported into a special + // schema that doesn't have a namespace. + // SemanticGraph::Uses& u (*schema.used_begin ()); - path = u.path (); + SemanticGraph::Schema& s (u.user ()); + + if (s.names_begin () != s.names_end ()) + path = u.path (); } String pair; diff --git a/xsde/cxx/hybrid/aggregate-elements.hxx b/xsde/cxx/hybrid/aggregate-elements.hxx new file mode 100644 index 0000000..aa4c504 --- /dev/null +++ b/xsde/cxx/hybrid/aggregate-elements.hxx @@ -0,0 +1,31 @@ +// file : xsde/cxx/hybrid/aggregate-elements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_AGGREGATE_ELEMENTS_HXX +#define CXX_HYBRID_AGGREGATE_ELEMENTS_HXX + +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + typedef + Cult::Containers::Map + TypeInstanceMap; + + struct InstanceInfo + { + SemanticGraph::Type* type; + String name; + }; + + typedef Cult::Containers::Map TypeIdInstanceMap; + } +} + +#endif // CXX_HYBRID_AGGREGATE_ELEMENTS_HXX diff --git a/xsde/cxx/hybrid/aggregate-include.hxx b/xsde/cxx/hybrid/aggregate-include.hxx new file mode 100644 index 0000000..9bd50bb --- /dev/null +++ b/xsde/cxx/hybrid/aggregate-include.hxx @@ -0,0 +1,223 @@ +// file : xsde/cxx/hybrid/aggregate-include.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CXX_HYBRID_AGGREGATE_INCLUDE_HXX +#define CXX_HYBRID_AGGREGATE_INCLUDE_HXX + +#include + +#include +#include + +#include + +namespace CXX +{ + namespace Hybrid + { + // Parser/serializer implementation includes for additional + // schemas (polymorphic code). + // + + // For base types we only want member's types, but not the + // base itself. + // + struct BaseInclude: Traversal::Complex, Context + { + BaseInclude (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + }; + + struct TypeInclude: Traversal::Type, + Traversal::Complex, + Context + { + TypeInclude (Context& c) + : Context (c), base_ (c) + { + *this >> inherits_ >> base_ >> inherits_; + + *this >> contains_compositor_; + base_ >> contains_compositor_; + + *this >> names_; + base_ >> names_; + + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> particle_; + + names_ >> attribute_; + + particle_ >> belongs_; + attribute_ >> belongs_; + belongs_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (types_.find (&t) != types_.end ()) + return; + + types_.insert (&t); + + if (polymorphic (t)) + collect (t); + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (types_.find (&c) != types_.end ()) + return; + + types_.insert (&c); + + if (polymorphic (c)) + collect (c); + + inherits (c); + + if (!restriction_p (c)) + { + names (c); + contains_compositor (c); + } + } + + private: + virtual Void + collect (SemanticGraph::Type& t) + { + using SemanticGraph::Type; + + for (Type::BegetsIterator i (t.begets_begin ()); + i != t.begets_end (); + ++i) + { + Type& d (i->derived ()); + emit (d); + dispatch (d); + collect (d); + } + } + + virtual Void + emit (SemanticGraph::Type& t) + { + using SemanticGraph::Schema; + + Schema* s (&dynamic_cast (t.scope ().scope ())); + + // If this is not a top-level schema, get one that + // includes/import/sources this schema. Top-level schema + // is either not used by any other schema or is imported + // into a special schema that doesn't have a namespace. + // + for (;;) + { + if (!s->used ()) + break; + + SemanticGraph::Uses& u (*s->used_begin ()); + Schema& us (u.user ()); + + if (us.names_begin () == us.names_end ()) + break; + + s = &us; + } + + + if (s != &schema_root && schemas_.find (s) == schemas_.end ()) + { + schemas_.insert (s); + + SemanticGraph::Path path (s->used_begin ()->path ()); + + // Try to use the portable representation of the path. If that + // fails, fall back to the native representation. + // + NarrowString path_str; + try + { + path_str = path.string (); + } + catch (SemanticGraph::InvalidPath const&) + { + path_str = path.native_file_string (); + } + + String inc_path (hxx_expr->merge (path_str)); + os << "#include " << process_include_path (inc_path) << endl + << endl; + } + } + + private: + Cult::Containers::Set types_; + Cult::Containers::Set schemas_; + + BaseInclude base_; + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + + Traversal::Names names_; + Traversal::Attribute attribute_; + + Traversal::Belongs belongs_; + }; + + struct AggregateInclude: Traversal::Type, + Traversal::Element, + Context + { + AggregateInclude (Context& c, Char const* key) + : Context (c), key_ (key), type_include_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Type& t) + { + if (t.context ().count (key_)) + type_include_.dispatch (t); + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + if (e.context ().count (key_)) + type_include_.dispatch (e.type ()); + } + + private: + Char const* key_; + TypeInclude type_include_; + }; + } +} + +#endif // CXX_HYBRID_AGGREGATE_INCLUDE_HXX diff --git a/xsde/cxx/hybrid/cli.hxx b/xsde/cxx/hybrid/cli.hxx index 0d1ec70..80b91bc 100644 --- a/xsde/cxx/hybrid/cli.hxx +++ b/xsde/cxx/hybrid/cli.hxx @@ -41,6 +41,11 @@ namespace CXX extern Key generate_xml_schema; extern Key extern_xml_schema; extern Key suppress_reset; + extern Key generate_polymorphic; + extern Key runtime_polymorphic; + extern Key polymorphic_type; + extern Key generate_typeinfo; + extern Key polymorphic_schema; extern Key reuse_style_mixin; extern Key custom_data; extern Key custom_type; @@ -123,6 +128,11 @@ namespace CXX generate_xml_schema, Boolean, extern_xml_schema, NarrowString, suppress_reset, Boolean, + generate_polymorphic, Boolean, + runtime_polymorphic, Boolean, + polymorphic_type, Cult::Containers::Vector, + generate_typeinfo, Boolean, + polymorphic_schema, Cult::Containers::Vector, reuse_style_mixin, Boolean, custom_data, Cult::Containers::Vector, custom_type, Cult::Containers::Vector, diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx index 80dc5c4..4edbc06 100644 --- a/xsde/cxx/hybrid/elements.cxx +++ b/xsde/cxx/hybrid/elements.cxx @@ -33,8 +33,7 @@ namespace CXX options (ops), exceptions (!ops.value ()), stl (!ops.value ()), - poly_code (false), - poly_runtime (false), + poly_code (ops.value ()), reset (!ops.value ()), detach (ops.value ()), mixin (ops.value ()), @@ -55,6 +54,10 @@ namespace CXX ixdrstream (ixdrstream_), oxdrstream (oxdrstream_) { + typeinfo = poly_code && + (ops.value () || + ops.value ()); + String xs_ns (xs_ns_name ()); string_type = L"::xsde::cxx::ro_string"; diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx index 7f3ba3a..8452976 100644 --- a/xsde/cxx/hybrid/elements.hxx +++ b/xsde/cxx/hybrid/elements.hxx @@ -42,9 +42,9 @@ namespace CXX exceptions (c.exceptions), stl (c.stl), poly_code (c.poly_code), - poly_runtime (c.poly_runtime), reset (c.reset), detach (c.detach), + typeinfo (c.typeinfo), mixin (c.mixin), tiein (c.tiein), fwd_expr (c.fwd_expr), @@ -71,9 +71,9 @@ namespace CXX exceptions (c.exceptions), stl (c.stl), poly_code (c.poly_code), - poly_runtime (c.poly_runtime), reset (c.reset), detach (c.detach), + typeinfo (c.typeinfo), mixin (c.mixin), tiein (c.tiein), fwd_expr (c.fwd_expr), @@ -534,6 +534,12 @@ namespace CXX return t.context ().count ("recursive"); } + Boolean + polymorphic (SemanticGraph::Type& t) + { + return t.context ().count ("polymorphic"); + } + public: String istream (NarrowString const& is) const; @@ -559,9 +565,9 @@ namespace CXX Boolean exceptions; Boolean stl; Boolean poly_code; - Boolean poly_runtime; Boolean reset; Boolean detach; + Boolean typeinfo; Boolean mixin; Boolean tiein; diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx index 14afad6..3eba4ba 100644 --- a/xsde/cxx/hybrid/generator.cxx +++ b/xsde/cxx/hybrid/generator.cxx @@ -129,6 +129,11 @@ namespace CXX extern Key generate_xml_schema = "generate-xml-schema"; extern Key extern_xml_schema = "extern-xml-schema"; extern Key suppress_reset = "suppress-reset"; + extern Key generate_polymorphic = "generate-polymorphic"; + extern Key runtime_polymorphic = "runtime-polymorphic"; + extern Key polymorphic_type = "polymorphic-type"; + extern Key generate_typeinfo = "generate-typeinfo"; + extern Key polymorphic_schema = "polymorphic-schema"; extern Key reuse_style_mixin = "reuse-style-mixin"; extern Key custom_data = "custom-data"; extern Key custom_type = "custom-type"; @@ -285,6 +290,32 @@ namespace CXX << " reset code." << endl; + e << "--generate-polymorphic" << endl + << " Generate polymorphism-aware code. Specify this\n" + << " option if you use substitution groups or xsi:type." + << endl; + + e << "--runtime-polymorphic" << endl + << " Generate non-polymorphic code that uses the\n" + << " runtime library configured with polymorphism\n" + << " support." + << endl; + + e << "--polymorphic-type " << endl + << " Indicate that is a root of a polymorphic\n" + << " type hierarchy." + << endl; + + e << "--generate-typeinfo" << endl + << " Generate type information functions for\n" + << " polymorphic object model types." + << endl; + + e << "--polymorphic-schema " << endl + << " Indicate that contains derivations of\n" + << " polymorphic types." + << endl; + e << "--reuse-style-mixin" << endl << " Generate code that supports the mixin base\n" << " parser/serializer implementation reuse style." @@ -783,6 +814,8 @@ namespace CXX r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); @@ -862,6 +895,8 @@ namespace CXX r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); + r->value () = h.value (); + r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); @@ -924,16 +959,44 @@ namespace CXX Void Hybrid::Generator:: calculate_size (CLI::Options const& ops, XSDFrontend::SemanticGraph::Schema& schema, - XSDFrontend::SemanticGraph::Path const& file) + XSDFrontend::SemanticGraph::Path const& file, + const WarningSet& disabled_warnings) { // Determine which types are fixed/variable-sized. // TreeSizeProcessor proc; - if (!proc.process (ops, schema, file)) + if (!proc.process (ops, schema, file, disabled_warnings)) throw Failed (); } + Void Hybrid::Generator:: + process_tree_names (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + TreeNameProcessor proc; + proc.process (ops, schema, file, false); + } + + Void Hybrid::Generator:: + process_parser_names (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + ParserNameProcessor proc; + proc.process (ops, schema, file, false); + } + + Void Hybrid::Generator:: + process_serializer_names (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + SerializerNameProcessor proc; + proc.process (ops, schema, file, false); + } + namespace { template @@ -1095,7 +1158,7 @@ namespace CXX // { TreeNameProcessor proc; - proc.process (ops, schema, file_path); + proc.process (ops, schema, file_path, true); } // Generate code. @@ -1819,7 +1882,7 @@ namespace CXX // { ParserNameProcessor proc; - proc.process (ops, schema, file_path); + proc.process (ops, schema, file_path, true); } NarrowString name (file_path.leaf ()); @@ -1976,6 +2039,8 @@ namespace CXX guard_prefix += '_'; + Boolean aggr (ops.value ()); + // HXX // { @@ -2012,6 +2077,14 @@ namespace CXX hxx << "#include " << endl << endl; + // Define omit aggregate macro. + // + hxx << "#ifndef XSDE_OMIT_PAGGR" << endl + << "# define XSDE_OMIT_PAGGR" << endl + << "# define " << guard << "_CLEAR_OMIT_PAGGR" << endl + << "#endif" << endl + << endl; + // Set auto-indentation. // Indentation::Clip hxx_clip (hxx); @@ -2021,9 +2094,24 @@ namespace CXX generate_parser_header (ctx); - if (ops.value ()) + // Clear omit aggregate macro. + // + hxx << "#ifdef " << guard << "_CLEAR_OMIT_PAGGR" << endl + << "# undef XSDE_OMIT_PAGGR" << endl + << "#endif" << endl + << endl; + + if (aggr) + { + hxx << "#ifndef XSDE_OMIT_PAGGR" << endl + << endl; + generate_parser_aggregate_header (ctx); + hxx << "#endif // XSDE_OMIT_PAGGR" << endl + << endl; + } + hxx << "#include " << endl << endl; } @@ -2090,7 +2178,7 @@ namespace CXX generate_parser_source (ctx); - if (ops.value ()) + if (aggr) generate_parser_aggregate_source (ctx); } @@ -2198,7 +2286,7 @@ namespace CXX // { SerializerNameProcessor proc; - proc.process (ops, schema, file_path); + proc.process (ops, schema, file_path, true); } NarrowString name (file_path.leaf ()); @@ -2342,6 +2430,7 @@ namespace CXX if (guard_prefix) guard_prefix += '_'; + Boolean aggr (ops.value ()); // HXX // @@ -2379,6 +2468,14 @@ namespace CXX hxx << "#include " << endl << endl; + // Define omit aggregate macro. + // + hxx << "#ifndef XSDE_OMIT_SAGGR" << endl + << "# define XSDE_OMIT_SAGGR" << endl + << "# define " << guard << "_CLEAR_OMIT_SAGGR" << endl + << "#endif" << endl + << endl; + // Set auto-indentation. // Indentation::Clip hxx_clip (hxx); @@ -2388,9 +2485,24 @@ namespace CXX generate_serializer_header (ctx); - if (ops.value ()) + // Clear omit aggregate macro. + // + hxx << "#ifdef " << guard << "_CLEAR_OMIT_SAGGR" << endl + << "# undef XSDE_OMIT_SAGGR" << endl + << "#endif" << endl + << endl; + + if (aggr) + { + hxx << "#ifndef XSDE_OMIT_SAGGR" << endl + << endl; + generate_serializer_aggregate_header (ctx); + hxx << "#endif // XSDE_OMIT_SAGGR" << endl + << endl; + } + hxx << "#include " << endl << endl; } @@ -2457,7 +2569,7 @@ namespace CXX generate_serializer_source (ctx); - if (ops.value ()) + if (aggr) generate_serializer_aggregate_source (ctx); } diff --git a/xsde/cxx/hybrid/generator.hxx b/xsde/cxx/hybrid/generator.hxx index ff29750..6f506b2 100644 --- a/xsde/cxx/hybrid/generator.hxx +++ b/xsde/cxx/hybrid/generator.hxx @@ -44,42 +44,67 @@ namespace CXX static Serializer::CLI::Options* serializer_options (CLI::Options const&); - struct Failed {}; - + // Calculate type sizes. + // static Void calculate_size ( - CLI::Options const& options, + CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const&, + WarningSet const& disabled_warnings); + + // Assign names to global declarations. + // + static Void + process_tree_names ( + CLI::Options const&, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const&); + + static Void + process_parser_names ( + CLI::Options const&, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const&); + + static Void + process_serializer_names ( + CLI::Options const&, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const&); + + // Generate code. + // + struct Failed {}; static UnsignedLong generate_tree ( - CLI::Options const& options, + CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file, - const WarningSet& disabled_warnings, + XSDFrontend::SemanticGraph::Path const&, + WarningSet const& disabled_warnings, TypeMap::Namespaces& parser_type_map, TypeMap::Namespaces& serializer_type_map, - FileList& file_list, - AutoUnlinks& unlinks); + FileList&, + AutoUnlinks&); static UnsignedLong generate_parser ( - CLI::Options const& options, + CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file, - const WarningSet& disabled_warnings, - FileList& file_list, - AutoUnlinks& unlinks); + XSDFrontend::SemanticGraph::Path const&, + WarningSet const& disabled_warnings, + FileList&, + AutoUnlinks&); static UnsignedLong generate_serializer ( - CLI::Options const& options, + CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file, - const WarningSet& disabled_warnings, - FileList& file_list, - AutoUnlinks& unlinks); + XSDFrontend::SemanticGraph::Path const&, + WarningSet const& disabled_warnings, + FileList&, + AutoUnlinks&); private: Generator (); diff --git a/xsde/cxx/hybrid/parser-aggregate-header.cxx b/xsde/cxx/hybrid/parser-aggregate-header.cxx index a717c68..c75eb54 100644 --- a/xsde/cxx/hybrid/parser-aggregate-header.cxx +++ b/xsde/cxx/hybrid/parser-aggregate-header.cxx @@ -4,11 +4,12 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include +#include +#include #include #include -#include #include namespace CXX @@ -17,10 +18,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map - TypeInstanceMap; - typedef Cult::Containers::Set InstanceSet; // For base types we only want member's types, but not the @@ -108,8 +105,15 @@ namespace CXX Context { - ParserDef (Context& c, TypeInstanceMap& map, InstanceSet& set) - : Context (c), map_ (map), set_ (set), base_ (c) + ParserDef (Context& c, + TypeInstanceMap& map, + TypeIdInstanceMap& tid_map, + InstanceSet& set) + : Context (c), + map_ (map), + tid_map_ (tid_map), + set_ (set), + base_ (c) { *this >> inherits_ >> base_ >> inherits_; @@ -136,8 +140,10 @@ namespace CXX { if (map_.find (&t) == map_.end ()) { - String inst (find_instance_name (t)); - map_[&t] = inst; + map_[&t] = find_instance_name (t); + + if (polymorphic (t)) + collect (t); } } @@ -146,10 +152,12 @@ namespace CXX { if (map_.find (&l) == map_.end ()) { - String inst (find_instance_name (l)); - map_[&l] = inst; + map_[&l] = find_instance_name (l); dispatch (l.argumented ().type ()); + + if (polymorphic (l)) + collect (l); } } @@ -158,8 +166,7 @@ namespace CXX { if (map_.find (&c) == map_.end ()) { - String inst (find_instance_name (c)); - map_[&c] = inst; + map_[&c] = find_instance_name (c); // Use base type's parsers in case of a restriction // since we are not capable of using a derived type @@ -172,6 +179,38 @@ namespace CXX names (c); contains_compositor (c); } + + if (polymorphic (c)) + collect (c); + } + } + + virtual Void + collect (SemanticGraph::Type& t) + { + using SemanticGraph::Type; + + for (Type::BegetsIterator i (t.begets_begin ()); + i != t.begets_end (); + ++i) + { + Type& d (i->derived ()); + + String id (d.name ()); + if (String ns = xml_ns_name (d)) + { + id += L' '; + id += ns; + } + + dispatch (d); + + if (tid_map_.find (id) == tid_map_.end ()) + { + tid_map_[id].type = &d; + tid_map_[id].name = map_.find (&d)->second; + collect (d); + } } } @@ -475,10 +514,7 @@ namespace CXX fund_type (SemanticGraph::Type& t, String const& name) { if (map_.find (&t) == map_.end ()) - { - String inst (find_instance_name (name)); - map_[&t] = inst; - } + map_[&t] = find_instance_name (name); } String @@ -504,6 +540,7 @@ namespace CXX } TypeInstanceMap& map_; + TypeIdInstanceMap& tid_map_; InstanceSet& set_; BaseType base_; @@ -535,37 +572,65 @@ namespace CXX if (!tc.count ("paggr")) return; + Boolean poly (polymorphic (t)); String const& name (tc.get ("paggr")); - String pre (unclash (name, "pre")); - String post (unclash (name, "post")); + String pre; + String post; String root_parser (unclash (name, "root_parser")); + String root_map; String error, reset; + String parser_map, parser_map_entries; InstanceSet set; - set.insert (pre); - set.insert (post); set.insert (name); set.insert (root_parser); - if (!exceptions) + if (poly) + { + root_map = unclash (name, "root_map"); + set.insert (root_map); + } + else + { + pre = unclash (name, "pre"); + post = unclash (name, "post"); + + set.insert (pre); + set.insert (post); + } + + if (!poly && !exceptions) { error = unclash (name, "_error"); set.insert (error); } - if (Context::reset) + if (!poly && Context::reset) { reset = unclash (name, "reset"); set.insert (reset); } + if (poly_code) + { + parser_map = unclash (name, "parser_map_"); + parser_map_entries = unclash (name, "parser_map_entries_"); + + tc.set ("paggr-parser-map", parser_map); + tc.set ("paggr-parser-map-entries", parser_map_entries); + } + tc.set ("paggr-map", TypeInstanceMap ()); TypeInstanceMap& map (tc.get ("paggr-map")); + TypeIdInstanceMap tid_map; - ParserDef def (*this, map, set); + ParserDef def (*this, map, tid_map, set); def.dispatch (t); + if (poly_code && !tid_map.empty ()) + tc.set ("paggr-tid-map", tid_map); + String const& root_member (map.find (&t)->second); os << "// Parser aggregate for the " << comment (t.name ()) << @@ -581,24 +646,27 @@ namespace CXX os << name << " ();" << endl; - // pre () - // - os << "void" << endl - << pre << " ()" - << "{" - << "this->" << root_member << ".pre ();" - << "}"; + if (!poly) + { + // pre () + // + os << "void" << endl + << pre << " ()" + << "{" + << "this->" << root_member << ".pre ();" + << "}"; - // post () - // - String const& ret (pret_type (t)); + // post () + // + String const& ret (pret_type (t)); - os << ret << endl - << post << " ()" - << "{" - << (ret == L"void" ? "" : "return ") << "this->" << - root_member << "." << post_name (t) << " ();" - << "}"; + os << ret << endl + << post << " ()" + << "{" + << (ret == L"void" ? "" : "return ") << "this->" << + root_member << "." << post_name (t) << " ();" + << "}"; + } // root_parser () // @@ -608,9 +676,23 @@ namespace CXX << "return this->" << root_member << ";" << "}"; + if (poly) + { + // root_map () + // + if (poly) + { + os << "const " << xs_ns_name () + L"::parser_map&" << endl + << root_map << " ()" + << "{" + << "return this->" << parser_map << ";" + << "}"; + } + } + // _error () // - if (error) + if (!poly && error) { os << xs_ns_name () << "::parser_error" << endl << error << " ()" @@ -626,8 +708,12 @@ namespace CXX os << "void" << endl << reset << " ()" << "{" - << "this->" << root_member << "._reset ();" - << "}"; + << "this->" << root_member << "._reset ();"; + + if (poly && tid_map.size () > 0) + os << "this->" << parser_map << ".reset ();"; + + os << "}"; } os << "public:" << endl; @@ -636,6 +722,13 @@ namespace CXX i != end; ++i) os << fq_name (*i->first, "p:impl") << " " << i->second << ";"; + if (tid_map.size () > 0) + { + os << endl + << "::xsde::cxx::hybrid::parser_map_impl " << parser_map << ";" + << "::xsde::cxx::hybrid::parser_map_impl::entry " << + parser_map_entries << "[" << tid_map.size () << "UL];"; + } os << "};"; } }; @@ -656,41 +749,70 @@ namespace CXX return; SemanticGraph::Type& t (e.type ()); + Boolean poly (polymorphic (t)); String const& name (ec.get ("paggr")); - String pre (unclash (name, "pre")); - String post (unclash (name, "post")); + String pre; + String post; String root_parser (unclash (name, "root_parser")); + String root_map; String root_name (unclash (name, "root_name")); String root_namespace (unclash (name, "root_namespace")); String error, reset; + String parser_map, parser_map_entries; InstanceSet set; - set.insert (pre); - set.insert (post); set.insert (name); set.insert (root_parser); + + if (poly) + { + root_map = unclash (name, "root_map"); + set.insert (root_map); + } + else + { + pre = unclash (name, "pre"); + post = unclash (name, "post"); + + set.insert (pre); + set.insert (post); + } + set.insert (root_name); set.insert (root_namespace); - if (!exceptions) + if (!poly && !exceptions) { error = unclash (name, "_error"); set.insert (error); } - if (Context::reset) + if (!poly && Context::reset) { reset = unclash (name, "reset"); set.insert (reset); } + if (poly_code) + { + parser_map = unclash (name, "parser_map_"); + parser_map_entries = unclash (name, "parser_map_entries_"); + + ec.set ("paggr-parser-map", parser_map); + ec.set ("paggr-parser-map-entries", parser_map_entries); + } + ec.set ("paggr-map", TypeInstanceMap ()); TypeInstanceMap& map (ec.get ("paggr-map")); + TypeIdInstanceMap tid_map; - ParserDef def (*this, map, set); + ParserDef def (*this, map, tid_map, set); def.dispatch (t); + if (poly_code && !tid_map.empty ()) + ec.set ("paggr-tid-map", tid_map); + String const& root_member (map.find (&t)->second); os << "// Parser aggregate for the " << comment (e.name ()) << @@ -706,24 +828,27 @@ namespace CXX os << name << " ();" << endl; - // pre () - // - os << "void" << endl - << pre << " ()" - << "{" - << "this->" << root_member << ".pre ();" - << "}"; + if (!poly) + { + // pre () + // + os << "void" << endl + << pre << " ()" + << "{" + << "this->" << root_member << ".pre ();" + << "}"; - // post () - // - String const& ret (pret_type (t)); + // post () + // + String const& ret (pret_type (t)); - os << ret << endl - << post << " ()" - << "{" - << (ret == L"void" ? "" : "return ") << "this->" << - root_member << "." << post_name (t) << " ();" - << "}"; + os << ret << endl + << post << " ()" + << "{" + << (ret == L"void" ? "" : "return ") << "this->" << + root_member << "." << post_name (t) << " ();" + << "}"; + } // root_parser () // @@ -733,6 +858,20 @@ namespace CXX << "return this->" << root_member << ";" << "}"; + if (poly) + { + // root_map () + // + if (poly) + { + os << "const " << xs_ns_name () + L"::parser_map&" << endl + << root_map << " ()" + << "{" + << "return this->" << parser_map << ";" + << "}"; + } + } + // root_name () // os << "static const char*" << endl @@ -747,7 +886,7 @@ namespace CXX // _error () // - if (error) + if (!poly && error) { os << xs_ns_name () << "::parser_error" << endl << error << " ()" @@ -763,8 +902,12 @@ namespace CXX os << "void" << endl << reset << " ()" << "{" - << "this->" << root_member << "._reset ();" - << "}"; + << "this->" << root_member << "._reset ();"; + + if (poly && tid_map.size () > 0) + os << "this->" << parser_map << ".reset ();"; + + os << "}"; } os << "public:" << endl; @@ -773,6 +916,14 @@ namespace CXX i != end; ++i) os << fq_name (*i->first, "p:impl") << " " << i->second << ";"; + if (tid_map.size () > 0) + { + os << endl + << "::xsde::cxx::hybrid::parser_map_impl " << parser_map << ";" + << "::xsde::cxx::hybrid::parser_map_impl::entry " << + parser_map_entries << "[" << tid_map.size () << "UL];"; + } + os << "};"; } }; @@ -801,6 +952,10 @@ namespace CXX if (gen) { + if (ctx.poly_code) + ctx.os << "#include " << endl + << endl; + // Emit "weak" header includes that are used in the file-per-type // compilation model. // @@ -813,6 +968,28 @@ namespace CXX schema.dispatch (ctx.schema_root); } + // Emit includes for additional schemas that define derived + // polymorphic types. + // + if (ctx.poly_code) + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateInclude include (ctx, "paggr"); + + schema >> schema_names >> ns >> names >> include; + + schema.dispatch (ctx.schema_root); + } + + // Generate code. + // Traversal::Schema schema; Traversal::Sources sources; diff --git a/xsde/cxx/hybrid/parser-aggregate-source.cxx b/xsde/cxx/hybrid/parser-aggregate-source.cxx index 6e80318..055cffb 100644 --- a/xsde/cxx/hybrid/parser-aggregate-source.cxx +++ b/xsde/cxx/hybrid/parser-aggregate-source.cxx @@ -4,6 +4,7 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include +#include #include #include @@ -16,10 +17,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map - TypeInstanceMap; - // // struct ParticleArg: Traversal::Element, Context @@ -186,6 +183,57 @@ namespace CXX TypeInstanceMap& map_; }; + // + // + struct ParserMapConnect: Traversal::Complex, + Traversal::Element, + Context + { + ParserMapConnect (Context& c, String const& inst, String const& map) + : Context (c), inst_ (inst), map_ (map) + { + *this >> inherits_ >> *this; + + *this >> contains_compositor_; + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + contains_compositor (c); + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + if (polymorphic (t)) + { + os << "this->" << inst_ << "." << + e.context ().get ("p:parser") << " (" << map_ << ");"; + } + } + + private: + String const& inst_; + String const& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + }; + struct GlobalType: Traversal::Type, Context { GlobalType (Context& c) @@ -208,18 +256,67 @@ namespace CXX << "//" << endl << endl; + TypeIdInstanceMap* tid_map (0); + + if (poly_code && tc.count ("paggr-tid-map")) + tid_map = &tc.get ("paggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << tc.get ("paggr-parser-map") << " (" << + tc.get ("paggr-parser-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + // Populate the polymorphic parser map. + // + if (tid_map) + { + String const& entry (tc.get ("paggr-parser-map-entries")); + + Size n (0); + + for (TypeIdInstanceMap::Iterator i (tid_map->begin ()); + i != tid_map->end (); + ++i, ++n) + { + os << entry << "[" << n << "UL].type_id = " << + fq_name (*i->second.type, "p:name") << "::_static_type ();" + << entry << "[" << n << "UL].parser = &this->" << + i->second.name << ";" + << endl; + } + } + + // Connect parsers. + // ParserConnect connect (*this, map); for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); i != end; ++i) connect.dispatch (*i->first); + // Connect the parser map. + // + if (tid_map) + { + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + { + ParserMapConnect t ( + *this, i->second, tc.get ("paggr-parser-map")); + t.dispatch (*i->first); + } + } + os << "}"; } }; @@ -246,18 +343,67 @@ namespace CXX << "//" << endl << endl; + TypeIdInstanceMap* tid_map (0); + + if (poly_code && ec.count ("paggr-tid-map")) + tid_map = &ec.get ("paggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << ec.get ("paggr-parser-map") << " (" << + ec.get ("paggr-parser-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + + // Populate the polymorphic parser map. + // + if (tid_map) + { + String const& entry (ec.get ("paggr-parser-map-entries")); + + Size n (0); + + for (TypeIdInstanceMap::Iterator i (tid_map->begin ()); + i != tid_map->end (); + ++i, ++n) + { + os << entry << "[" << n << "UL].type_id = " << + fq_name (*i->second.type, "p:name") << "::_static_type ();" + << entry << "[" << n << "UL].parser = &this->" << + i->second.name << ";" + << endl; + } + } + // Connect parsers. + // ParserConnect connect (*this, map); for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); i != end; ++i) connect.dispatch (*i->first); + // Connect the parser map. + // + if (tid_map) + { + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + { + ParserMapConnect t ( + *this, i->second, ec.get ("paggr-parser-map")); + t.dispatch (*i->first); + } + } + os << "}"; // root_name () diff --git a/xsde/cxx/hybrid/parser-header.cxx b/xsde/cxx/hybrid/parser-header.cxx index 72cc2e3..6a893c5 100644 --- a/xsde/cxx/hybrid/parser-header.cxx +++ b/xsde/cxx/hybrid/parser-header.cxx @@ -347,6 +347,34 @@ namespace CXX } }; + // + // + struct PostOverride: Traversal::Complex, Context + { + PostOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + os << "virtual " << pret_type (b) << endl + << post_name (b) << " ();" + << endl; + } + } + } + }; // // @@ -354,6 +382,8 @@ namespace CXX { Complex (Context& c) : Context (c), + post_override_ (c), + // State. // compositor_state_ (c), @@ -472,6 +502,9 @@ namespace CXX // post // + if (polymorphic (c)) + post_override_.dispatch (c); + os << "virtual " << ret << endl << post_name (c) << " ();" << endl; @@ -546,6 +579,8 @@ namespace CXX } private: + PostOverride post_override_; + // State. // CompositorState compositor_state_; diff --git a/xsde/cxx/hybrid/parser-name-processor.cxx b/xsde/cxx/hybrid/parser-name-processor.cxx index 740cf36..c635aec 100644 --- a/xsde/cxx/hybrid/parser-name-processor.cxx +++ b/xsde/cxx/hybrid/parser-name-processor.cxx @@ -657,7 +657,8 @@ namespace CXX Void process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { Context ctx (ops, tu, file); @@ -686,6 +687,9 @@ namespace CXX schema.dispatch (tu); } + if (!deep) + return; + // Pass two - assign names inside complex types. Here we don't // need to go into included/imported schemas. // @@ -717,9 +721,10 @@ namespace CXX Void ParserNameProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { - process_impl (ops, tu, file); + process_impl (ops, tu, file, deep); } } } diff --git a/xsde/cxx/hybrid/parser-name-processor.hxx b/xsde/cxx/hybrid/parser-name-processor.hxx index ea3e985..d0e1970 100644 --- a/xsde/cxx/hybrid/parser-name-processor.hxx +++ b/xsde/cxx/hybrid/parser-name-processor.hxx @@ -24,7 +24,8 @@ namespace CXX Void process (CLI::Options const& options, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const& file, + Boolean deep); }; } } diff --git a/xsde/cxx/hybrid/parser-source.cxx b/xsde/cxx/hybrid/parser-source.cxx index 4c4237c..505d661 100644 --- a/xsde/cxx/hybrid/parser-source.cxx +++ b/xsde/cxx/hybrid/parser-source.cxx @@ -904,11 +904,59 @@ namespace CXX // // + struct PostOverride: Traversal::Complex, Context + { + PostOverride (Context& c) + : Context (c), scope_ (0) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + Boolean clear (false); + + if (scope_ == 0) + { + scope_ = &c; + clear = true; + } + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + String const& scope (epimpl_custom (*scope_)); + + os << pret_type (b) << " " << scope << "::" << endl + << post_name (b) << " ()" + << "{" + << "return this->" << post_name (c) << " ();" + << "}"; + } + } + + if (clear) + scope_ = 0; + } + + private: + SemanticGraph::Complex* scope_; + }; + + // + // struct Complex: Traversal::Complex, Context { Complex (Context& c) : Context (c), base_name_ (c, TypeName::base), + post_override_ (c), compositor_callback_ (c), particle_callback_ (c), attribute_callback_ (c) @@ -1253,6 +1301,9 @@ namespace CXX // post // + if (polymorphic (c)) + post_override_.dispatch (c); + os << ret << " " << name << "::" << endl << post_name (c) << " ()" << "{"; @@ -1350,6 +1401,7 @@ namespace CXX private: TypeName base_name_; + PostOverride post_override_; CompositorCallback compositor_callback_; ParticleCallback particle_callback_; diff --git a/xsde/cxx/hybrid/serializer-aggregate-header.cxx b/xsde/cxx/hybrid/serializer-aggregate-header.cxx index b697715..3e3260f 100644 --- a/xsde/cxx/hybrid/serializer-aggregate-header.cxx +++ b/xsde/cxx/hybrid/serializer-aggregate-header.cxx @@ -4,6 +4,8 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include +#include +#include #include #include @@ -17,10 +19,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map - TypeInstanceMap; - typedef Cult::Containers::Set InstanceSet; // For base types we only want member's types, but not the @@ -108,8 +106,15 @@ namespace CXX Context { - SerializerDef (Context& c, TypeInstanceMap& map, InstanceSet& set) - : Context (c), map_ (map), set_ (set), base_ (c) + SerializerDef (Context& c, + TypeInstanceMap& map, + TypeIdInstanceMap& tid_map, + InstanceSet& set) + : Context (c), + map_ (map), + tid_map_ (tid_map), + set_ (set), + base_ (c) { *this >> inherits_ >> base_ >> inherits_; @@ -136,8 +141,10 @@ namespace CXX { if (map_.find (&t) == map_.end ()) { - String inst (find_instance_name (t)); - map_[&t] = inst; + map_[&t] = find_instance_name (t); + + if (polymorphic (t)) + collect (t); } } @@ -146,10 +153,11 @@ namespace CXX { if (map_.find (&l) == map_.end ()) { - String inst (find_instance_name (l)); - map_[&l] = inst; - + map_[&l] = find_instance_name (l); dispatch (l.argumented ().type ()); + + if (polymorphic (l)) + collect (l); } } @@ -158,8 +166,7 @@ namespace CXX { if (map_.find (&c) == map_.end ()) { - String inst (find_instance_name (c)); - map_[&c] = inst; + map_[&c] = find_instance_name (c); // Use base type's serializers in case of a restriction // since we are not capable of using a derived type @@ -172,6 +179,38 @@ namespace CXX names (c); contains_compositor (c); } + + if (polymorphic (c)) + collect (c); + } + } + + virtual Void + collect (SemanticGraph::Type& t) + { + using SemanticGraph::Type; + + for (Type::BegetsIterator i (t.begets_begin ()); + i != t.begets_end (); + ++i) + { + Type& d (i->derived ()); + + String id (d.name ()); + if (String ns = xml_ns_name (d)) + { + id += L' '; + id += ns; + } + + dispatch (d); + + if (tid_map_.find (id) == tid_map_.end ()) + { + tid_map_[id].type = &d; + tid_map_[id].name = map_.find (&d)->second; + collect (d); + } } } @@ -475,10 +514,7 @@ namespace CXX fund_type (SemanticGraph::Type& t, String const& name) { if (map_.find (&t) == map_.end ()) - { - String inst (find_instance_name (name)); - map_[&t] = inst; - } + map_[&t] = find_instance_name (name); } String @@ -504,6 +540,7 @@ namespace CXX } TypeInstanceMap& map_; + TypeIdInstanceMap& tid_map_; InstanceSet& set_; BaseType base_; @@ -535,37 +572,65 @@ namespace CXX if (!tc.count ("saggr")) return; + Boolean poly (polymorphic (t)); String const& name (tc.get ("saggr")); - String pre (unclash (name, "pre")); - String post (unclash (name, "post")); + String pre; + String post; String root_serializer (unclash (name, "root_serializer")); + String root_map; String error, reset; + String serializer_map, serializer_map_entries; InstanceSet set; - set.insert (pre); - set.insert (post); set.insert (name); set.insert (root_serializer); - if (!exceptions) + if (poly) + { + root_map = unclash (name, "root_map"); + set.insert (root_map); + } + else + { + pre = unclash (name, "pre"); + post = unclash (name, "post"); + + set.insert (pre); + set.insert (post); + } + + if (!poly && !exceptions) { error = unclash (name, "_error"); set.insert (error); } - if (Context::reset) + if (!poly && Context::reset) { reset = unclash (name, "reset"); set.insert (reset); } + if (poly_code) + { + serializer_map = unclash (name, "serializer_map_"); + serializer_map_entries = unclash (name, "serializer_map_entries_"); + + tc.set ("saggr-serializer-map", serializer_map); + tc.set ("saggr-serializer-map-entries", serializer_map_entries); + } + tc.set ("saggr-map", TypeInstanceMap ()); TypeInstanceMap& map (tc.get ("saggr-map")); + TypeIdInstanceMap tid_map; - SerializerDef def (*this, map, set); + SerializerDef def (*this, map, tid_map, set); def.dispatch (t); + if (poly_code && !tid_map.empty ()) + tc.set ("saggr-tid-map", tid_map); + String const& root_member (map.find (&t)->second); os << "// Serializer aggregate for the " << comment (t.name ()) << @@ -581,29 +646,32 @@ namespace CXX os << name << " ();" << endl; - // pre () - // - String const& arg (sarg_type (t)); + if (!poly) + { + // pre () + // + String const& arg (sarg_type (t)); - os << "void" << endl - << pre << " ("; + os << "void" << endl + << pre << " ("; - if (arg != L"void") - os << arg << " x"; + if (arg != L"void") + os << arg << " x"; - os <<")" - << "{" - << "this->" << root_member << ".pre (" << - (arg != L"void" ? "x" : "") << ");" - << "}"; + os <<")" + << "{" + << "this->" << root_member << ".pre (" << + (arg != L"void" ? "x" : "") << ");" + << "}"; - // post () - // - os << "void" << endl - << post << " ()" - << "{" - << "this->" << root_member << ".post ();" - << "}"; + // post () + // + os << "void" << endl + << post << " ()" + << "{" + << "this->" << root_member << ".post ();" + << "}"; + } // root_serializer () // @@ -613,9 +681,23 @@ namespace CXX << "return this->" << root_member << ";" << "}"; + if (poly) + { + // root_map () + // + if (poly) + { + os << "const " << xs_ns_name () + L"::serializer_map&" << endl + << root_map << " ()" + << "{" + << "return this->" << serializer_map << ";" + << "}"; + } + } + // _error () // - if (error) + if (!poly && error) { os << xs_ns_name () << "::serializer_error" << endl << error << " ()" @@ -631,8 +713,12 @@ namespace CXX os << "void" << endl << reset << " ()" << "{" - << "this->" << root_member << "._reset ();" - << "}"; + << "this->" << root_member << "._reset ();"; + + if (poly && tid_map.size () > 0) + os << "this->" << serializer_map << ".reset ();"; + + os << "}"; } os << "public:" << endl; @@ -641,6 +727,15 @@ namespace CXX i != end; ++i) os << fq_name (*i->first, "s:impl") << " " << i->second << ";"; + if (tid_map.size () > 0) + { + os << endl + << "::xsde::cxx::hybrid::serializer_map_impl " << + serializer_map << ";" + << "::xsde::cxx::hybrid::serializer_map_impl::entry " << + serializer_map_entries << "[" << tid_map.size () << "UL];"; + } + os << "};"; } }; @@ -661,41 +756,70 @@ namespace CXX return; SemanticGraph::Type& t (e.type ()); + Boolean poly (polymorphic (t)); String const& name (ec.get ("saggr")); - String pre (unclash (name, "pre")); - String post (unclash (name, "post")); + String pre; + String post; String root_serializer (unclash (name, "root_serializer")); + String root_map; String root_name (unclash (name, "root_name")); String root_namespace (unclash (name, "root_namespace")); String error, reset; + String serializer_map, serializer_map_entries; InstanceSet set; - set.insert (pre); - set.insert (post); set.insert (name); set.insert (root_serializer); + + if (poly) + { + root_map = unclash (name, "root_map"); + set.insert (root_map); + } + else + { + pre = unclash (name, "pre"); + post = unclash (name, "post"); + + set.insert (pre); + set.insert (post); + } + set.insert (root_name); set.insert (root_namespace); - if (!exceptions) + if (!poly && !exceptions) { error = unclash (name, "_error"); set.insert (error); } - if (Context::reset) + if (!poly && Context::reset) { reset = unclash (name, "reset"); set.insert (reset); } + if (poly_code) + { + serializer_map = unclash (name, "serializer_map_"); + serializer_map_entries = unclash (name, "serializer_map_entries_"); + + ec.set ("saggr-serializer-map", serializer_map); + ec.set ("saggr-serializer-map-entries", serializer_map_entries); + } + ec.set ("saggr-map", TypeInstanceMap ()); TypeInstanceMap& map (ec.get ("saggr-map")); + TypeIdInstanceMap tid_map; - SerializerDef def (*this, map, set); + SerializerDef def (*this, map, tid_map, set); def.dispatch (t); + if (poly_code && !tid_map.empty ()) + ec.set ("saggr-tid-map", tid_map); + String const& root_member (map.find (&t)->second); os << "// Serializer aggregate for the " << comment (e.name ()) << @@ -711,29 +835,32 @@ namespace CXX os << name << " ();" << endl; - // pre () - // - String const& arg (sarg_type (t)); + if (!poly) + { + // pre () + // + String const& arg (sarg_type (t)); - os << "void" << endl - << pre << " ("; + os << "void" << endl + << pre << " ("; - if (arg != L"void") - os << arg << " x"; + if (arg != L"void") + os << arg << " x"; - os <<")" - << "{" - << "this->" << root_member << ".pre (" << - (arg != L"void" ? "x" : "") << ");" - << "}"; + os <<")" + << "{" + << "this->" << root_member << ".pre (" << + (arg != L"void" ? "x" : "") << ");" + << "}"; - // post () - // - os << "void" << endl - << post << " ()" - << "{" - << "this->" << root_member << ".post ();" - << "}"; + // post () + // + os << "void" << endl + << post << " ()" + << "{" + << "this->" << root_member << ".post ();" + << "}"; + } // root_serializer () // @@ -743,6 +870,20 @@ namespace CXX << "return this->" << root_member << ";" << "}"; + if (poly) + { + // root_map () + // + if (poly) + { + os << "const " << xs_ns_name () + L"::serializer_map&" << endl + << root_map << " ()" + << "{" + << "return this->" << serializer_map << ";" + << "}"; + } + } + // root_name () // os << "static const char*" << endl @@ -757,7 +898,7 @@ namespace CXX // _error () // - if (error) + if (!poly && error) { os << xs_ns_name () << "::serializer_error" << endl << error << " ()" @@ -773,8 +914,12 @@ namespace CXX os << "void" << endl << reset << " ()" << "{" - << "this->" << root_member << "._reset ();" - << "}"; + << "this->" << root_member << "._reset ();"; + + if (poly && tid_map.size () > 0) + os << "this->" << serializer_map << ".reset ();"; + + os << "}"; } os << "public:" << endl; @@ -783,6 +928,15 @@ namespace CXX i != end; ++i) os << fq_name (*i->first, "s:impl") << " " << i->second << ";"; + if (tid_map.size () > 0) + { + os << endl + << "::xsde::cxx::hybrid::serializer_map_impl " << + serializer_map << ";" + << "::xsde::cxx::hybrid::serializer_map_impl::entry " << + serializer_map_entries << "[" << tid_map.size () << "UL];"; + } + os << "};"; } }; @@ -811,6 +965,10 @@ namespace CXX if (gen) { + if (ctx.poly_code) + ctx.os << "#include " << endl + << endl; + // Emit "weak" header includes that are used in the file-per-type // compilation model. // @@ -823,6 +981,28 @@ namespace CXX schema.dispatch (ctx.schema_root); } + // Emit includes for additional schemas that define derived + // polymorphic types. + // + if (ctx.poly_code) + { + Traversal::Schema schema; + Traversal::Sources sources; + + schema >> sources >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names names; + AggregateInclude include (ctx, "saggr"); + + schema >> schema_names >> ns >> names >> include; + + schema.dispatch (ctx.schema_root); + } + + // Generate code. + // Traversal::Schema schema; Traversal::Sources sources; diff --git a/xsde/cxx/hybrid/serializer-aggregate-source.cxx b/xsde/cxx/hybrid/serializer-aggregate-source.cxx index 7e305b6..0422031 100644 --- a/xsde/cxx/hybrid/serializer-aggregate-source.cxx +++ b/xsde/cxx/hybrid/serializer-aggregate-source.cxx @@ -4,6 +4,7 @@ // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include +#include #include #include @@ -16,10 +17,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map - TypeInstanceMap; - // // struct ParticleArg: Traversal::Element, Context @@ -186,6 +183,62 @@ namespace CXX TypeInstanceMap& map_; }; + // + // + struct SerializerMapConnect: Traversal::Complex, + Traversal::Element, + Context + { + SerializerMapConnect (Context& c, + String const& inst, + String const& map) + : Context (c), inst_ (inst), map_ (map) + { + *this >> inherits_ >> *this; + + *this >> contains_compositor_; + contains_compositor_ >> compositor_; + compositor_ >> contains_particle_; + contains_particle_ >> compositor_; + contains_particle_ >> *this; + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + inherits (c); + + if (!restriction_p (c)) + contains_compositor (c); + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + SemanticGraph::Type& t (e.type ()); + + if (polymorphic (t)) + { + os << "this->" << inst_ << "." << + e.context ().get ("s:serializer") << " (" << + map_ << ");"; + } + } + + private: + String const& inst_; + String const& map_; + + Traversal::Inherits inherits_; + + Traversal::Compositor compositor_; + Traversal::Element particle_; + Traversal::ContainsCompositor contains_compositor_; + Traversal::ContainsParticle contains_particle_; + }; + + // + // struct GlobalType: Traversal::Type, Context { GlobalType (Context& c) @@ -208,18 +261,68 @@ namespace CXX << "//" << endl << endl; + TypeIdInstanceMap* tid_map (0); + + if (poly_code && tc.count ("saggr-tid-map")) + tid_map = &tc.get ("saggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << tc.get ("saggr-serializer-map") << " (" << + tc.get ("saggr-serializer-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + // Populate the polymorphic serializer map. + // + if (tid_map) + { + String const& entry ( + tc.get ("saggr-serializer-map-entries")); + + Size n (0); + + for (TypeIdInstanceMap::Iterator i (tid_map->begin ()); + i != tid_map->end (); + ++i, ++n) + { + os << entry << "[" << n << "UL].type_id = " << + fq_name (*i->second.type, "s:name") << "::_static_type ();" + << entry << "[" << n << "UL].serializer = &this->" << + i->second.name << ";" + << endl; + } + } + + // Connect parsers. + // SerializerConnect connect (*this, map); for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); i != end; ++i) connect.dispatch (*i->first); + // Connect the serializer map. + // + if (tid_map) + { + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + { + SerializerMapConnect t ( + *this, i->second, tc.get ("saggr-serializer-map")); + t.dispatch (*i->first); + } + } + os << "}"; } }; @@ -246,18 +349,68 @@ namespace CXX << "//" << endl << endl; + TypeIdInstanceMap* tid_map (0); + + if (poly_code && ec.count ("saggr-tid-map")) + tid_map = &ec.get ("saggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << ec.get ("saggr-serializer-map") << " (" << + ec.get ("saggr-serializer-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + + // Populate the polymorphic serializer map. + // + if (tid_map) + { + String const& entry ( + ec.get ("saggr-serializer-map-entries")); + + Size n (0); + + for (TypeIdInstanceMap::Iterator i (tid_map->begin ()); + i != tid_map->end (); + ++i, ++n) + { + os << entry << "[" << n << "UL].type_id = " << + fq_name (*i->second.type, "s:name") << "::_static_type ();" + << entry << "[" << n << "UL].serializer = &this->" << + i->second.name << ";" + << endl; + } + } + // Connect parsers. + // SerializerConnect connect (*this, map); for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); i != end; ++i) connect.dispatch (*i->first); + // Connect the serializer map. + // + if (tid_map) + { + for (TypeInstanceMap::Iterator i (map.begin ()), end (map.end ()); + i != end; ++i) + { + SerializerMapConnect t ( + *this, i->second, ec.get ("saggr-serializer-map")); + t.dispatch (*i->first); + } + } + os << "}"; // root_name () diff --git a/xsde/cxx/hybrid/serializer-header.cxx b/xsde/cxx/hybrid/serializer-header.cxx index 20f4e15..db0578f 100644 --- a/xsde/cxx/hybrid/serializer-header.cxx +++ b/xsde/cxx/hybrid/serializer-header.cxx @@ -343,10 +343,40 @@ namespace CXX // // + struct PreOverride: Traversal::Complex, Context + { + PreOverride (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + os << "virtual void" << endl + << "pre (" << sarg_type (b) << ");" + << endl; + } + } + } + }; + + // + // struct Complex : Traversal::Complex, Context { Complex (Context& c) : Context (c), + pre_override_ (c), // State. // @@ -422,6 +452,9 @@ namespace CXX // pre // + if (polymorphic (c)) + pre_override_.dispatch (c); + os << "virtual void" << endl << "pre (" << arg << ");" << endl; @@ -522,6 +555,8 @@ namespace CXX } private: + PreOverride pre_override_; + // State. // CompositorState compositor_state_; diff --git a/xsde/cxx/hybrid/serializer-name-processor.cxx b/xsde/cxx/hybrid/serializer-name-processor.cxx index ba4a268..2f7d296 100644 --- a/xsde/cxx/hybrid/serializer-name-processor.cxx +++ b/xsde/cxx/hybrid/serializer-name-processor.cxx @@ -265,7 +265,7 @@ namespace CXX if (!name) return; - String const& skel (lc.get ("p:name")); + String const& skel (lc.get ("s:name")); NameSet set; set.insert (name); @@ -672,7 +672,8 @@ namespace CXX Void process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { Context ctx (ops, tu, file); @@ -701,6 +702,9 @@ namespace CXX schema.dispatch (tu); } + if (!deep) + return; + // Pass two - assign names inside complex types. Here we don't // need to go into included/imported schemas. // @@ -732,9 +736,10 @@ namespace CXX Void SerializerNameProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { - process_impl (ops, tu, file); + process_impl (ops, tu, file, deep); } } } diff --git a/xsde/cxx/hybrid/serializer-name-processor.hxx b/xsde/cxx/hybrid/serializer-name-processor.hxx index f69dfe4..b607c24 100644 --- a/xsde/cxx/hybrid/serializer-name-processor.hxx +++ b/xsde/cxx/hybrid/serializer-name-processor.hxx @@ -24,7 +24,8 @@ namespace CXX Void process (CLI::Options const& options, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const& file, + Boolean deep); }; } } diff --git a/xsde/cxx/hybrid/serializer-source.cxx b/xsde/cxx/hybrid/serializer-source.cxx index 6e82bd0..540d742 100644 --- a/xsde/cxx/hybrid/serializer-source.cxx +++ b/xsde/cxx/hybrid/serializer-source.cxx @@ -783,12 +783,35 @@ namespace CXX << esname (e) << " ()" << "{"; + if (polymorphic (t)) + { + if (stl) + { + os << "const ::std::string& dt = " << access << iter << + "->_dynamic_type ();" + << "if (dt != " << esskel (t) << "::_static_type ())" << endl + << "this->_context ().type_id (dt.c_str ());" + << endl; + } + else + { + os << "const char* dt = " << access << iter << + "->_dynamic_type ();" + << "if (strcmp (dt, " << esskel (t) << + "::_static_type ()) != 0)" << endl + << "this->_context ().type_id (dt);" + << endl; + } + } + if (ret != L"void") { os << "return "; type_pass_.dispatch (t); os << "*" << access << iter << "++;"; } + else + os << access << iter << "++;"; os << "}"; } @@ -807,6 +830,27 @@ namespace CXX << esname (e) << " ()" << "{"; + if (polymorphic (t)) + { + if (stl) + { + os << "const ::std::string& dt = " << access << ename (e) << + " ()._dynamic_type ();" + << "if (dt != " << esskel (t) << "::_static_type ())" << endl + << "this->_context ().type_id (dt.c_str ());" + << endl; + } + else + { + os << "const char* dt = " << access << ename (e) << + " ()._dynamic_type ();" + << "if (strcmp (dt, " << esskel (t) << + "::_static_type ()) != 0)" << endl + << "this->_context ().type_id (dt);" + << endl; + } + } + if (ret != L"void") { os << "return "; @@ -870,11 +914,59 @@ namespace CXX // // + struct PreOverride: Traversal::Complex, Context + { + PreOverride (Context& c) + : Context (c), scope_ (0) + { + } + + virtual Void + traverse (SemanticGraph::Complex& c) + { + Boolean clear (false); + + if (scope_ == 0) + { + scope_ = &c; + clear = true; + } + + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (polymorphic (b)) + { + if (tiein) + dispatch (b); + + String const& scope (esimpl_custom (*scope_)); + + os << "void " << scope << "::" << endl + << "pre (" << sarg_type (b) << " x)" + << "{" + << "this->pre (static_cast< " << sarg_type (c) << " > (x));" + << "}"; + } + } + + if (clear) + scope_ = 0; + } + + private: + SemanticGraph::Complex* scope_; + }; + + // + // struct Complex: Traversal::Complex, Context { Complex (Context& c) : Context (c), type_pass_ (c), + pre_override_ (c), // Initializers. // @@ -961,6 +1053,9 @@ namespace CXX // pre // + if (polymorphic (c)) + pre_override_.dispatch (c); + String const& arg (sarg_type (c)); os << "void " << name << "::" << endl @@ -1136,6 +1231,7 @@ namespace CXX private: TypePass type_pass_; + PreOverride pre_override_; // Initializers. // @@ -1159,6 +1255,10 @@ namespace CXX Void generate_serializer_source (Context& ctx) { + if (ctx.poly_code && !ctx.stl) + ctx.os << "#include " << endl + << endl; + Traversal::Schema schema; Traversal::Sources sources; diff --git a/xsde/cxx/hybrid/tree-header.cxx b/xsde/cxx/hybrid/tree-header.cxx index c2e8bf4..3003e4c 100644 --- a/xsde/cxx/hybrid/tree-header.cxx +++ b/xsde/cxx/hybrid/tree-header.cxx @@ -32,6 +32,9 @@ namespace CXX // if (name) { + Boolean cd (lc.count ("cd-name")); + Boolean poly (polymorphic (l)); + os << "// " << comment (l.name ()) << " (variable-length)" << endl << "//" << endl; @@ -50,17 +53,23 @@ namespace CXX os << "public:" << endl << name << " ();"; + // d-tor + // + if (poly) + os << "virtual ~" << name << " ();"; + + os << endl; + // Custom data. // - if (lc.count ("cd-name")) + if (cd) { 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 << "// Custom data." << endl << "//" << endl; // sequence & iterators @@ -84,9 +93,28 @@ namespace CXX os << sequence << "&" << endl << name << " ();" << endl; + } + + if (poly && typeinfo) + { + os << "// Type information." << endl + << "//" << endl; + os << "static const " << + (stl ? "::std::string&" : "char*") << endl + << "_static_type ();" + << endl; + + os << "virtual const " << + (stl ? "::std::string&" : "char*") << endl + << "_dynamic_type () const;" + << endl; + } + + if (cd) + { os << "private:" << endl - << sequence << " " << ecd_member (l) << ";"; + << ecd_sequence (l) << " " << ecd_member (l) << ";"; } os << "};"; @@ -128,15 +156,18 @@ namespace CXX // if (name) { + Boolean fl (fixed_length (u)); + Boolean poly (polymorphic (u)); Boolean cd (uc.count ("cd-name")); - os << "// " << comment (u.name ()) << " (variable-length)" << endl + os << "// " << comment (u.name ()) << " (" << + (fl ? "fixed-length" : "variable-length") << ")" << endl << "//" << endl; os << "class " << name << "{"; - if (!fixed_length (u)) + if (!fl) os << "private:" << endl << name << " (const " << name << "&);" << name << "& operator= (const " << name << "&);" @@ -148,13 +179,18 @@ namespace CXX // os << name << " ();"; + // d-tor + // + if (!stl || poly) + os << (poly ? "virtual " : "") << "~" << name << " ();"; + + os << endl; + String const& value (uc.get ("value")); String const& member (uc.get ("value-member")); if (stl) { - os << endl; - // const std::string& // name () const // @@ -178,11 +214,6 @@ namespace CXX } else { - // d-tor - // - os << "~" << name << " ();" - << endl; - // const char* // name () const // @@ -250,6 +281,22 @@ namespace CXX << endl; } + if (poly && typeinfo) + { + os << "// Type information." << endl + << "//" << endl; + + os << "static const " << + (stl ? "::std::string&" : "char*") << endl + << "_static_type ();" + << endl; + + os << "virtual const " << + (stl ? "::std::string&" : "char*") << endl + << "_dynamic_type () const;" + << endl; + } + if (stl) { os << "private:" << endl @@ -2337,6 +2384,7 @@ namespace CXX if (name) { Boolean fl (fixed_length (c)); + Boolean poly (polymorphic (c)); Boolean restriction (restriction_p (c)); Boolean cd (cc.count ("cd-name")); @@ -2361,8 +2409,8 @@ namespace CXX // d-tor // - if (!restriction) - os << "~" << name << " ();"; + if (!restriction || poly) + os << (poly ? "virtual " : "") << "~" << name << " ();"; // copy c-tor & operator= // @@ -2421,6 +2469,22 @@ namespace CXX << endl; } + if (poly && typeinfo) + { + os << "// Type information." << endl + << "//" << endl; + + os << "static const " << + (stl ? "::std::string&" : "char*") << endl + << "_static_type ();" + << endl; + + os << "virtual const " << + (stl ? "::std::string&" : "char*") << endl + << "_dynamic_type () const;" + << endl; + } + if (!restriction || cd) os << "private:" << endl; diff --git a/xsde/cxx/hybrid/tree-inline.cxx b/xsde/cxx/hybrid/tree-inline.cxx index b1c60e6..7cb4b2c 100644 --- a/xsde/cxx/hybrid/tree-inline.cxx +++ b/xsde/cxx/hybrid/tree-inline.cxx @@ -150,15 +150,6 @@ namespace CXX } else { - // d-tor - // - os << inl - << name << "::" << endl - << "~" << name << " ()" - << "{" - << "delete[] this->" << member << ";" - << "}"; - // const char* // name () const // diff --git a/xsde/cxx/hybrid/tree-name-processor.cxx b/xsde/cxx/hybrid/tree-name-processor.cxx index a3a1dd3..9308598 100644 --- a/xsde/cxx/hybrid/tree-name-processor.cxx +++ b/xsde/cxx/hybrid/tree-name-processor.cxx @@ -2053,8 +2053,9 @@ namespace CXX Void process_impl (CLI::Options const& ops, - SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Schema& tu, + SemanticGraph::Path const& file, + Boolean deep) { Context ctx (ops, tu, file); @@ -2120,6 +2121,9 @@ namespace CXX schema.dispatch (tu); } + if (!deep) + return; + // Pass three - assign names inside complex types. Here we don't // need to go into included/imported schemas. // @@ -2178,9 +2182,10 @@ namespace CXX Void TreeNameProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { - process_impl (ops, tu, file); + process_impl (ops, tu, file, deep); } } } diff --git a/xsde/cxx/hybrid/tree-name-processor.hxx b/xsde/cxx/hybrid/tree-name-processor.hxx index 4d884bc..17becee 100644 --- a/xsde/cxx/hybrid/tree-name-processor.hxx +++ b/xsde/cxx/hybrid/tree-name-processor.hxx @@ -24,7 +24,8 @@ namespace CXX Void process (CLI::Options const& options, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const& file, + Boolean deep); }; } } diff --git a/xsde/cxx/hybrid/tree-size-processor.cxx b/xsde/cxx/hybrid/tree-size-processor.cxx index a3b2231..33d829a 100644 --- a/xsde/cxx/hybrid/tree-size-processor.cxx +++ b/xsde/cxx/hybrid/tree-size-processor.cxx @@ -242,11 +242,15 @@ namespace CXX Type (Boolean& valid, TypeSet& custom_data, CustomTypeMap& custom_type_map, - Boolean stl_) + TypeSet& poly_types, + Boolean stl_, + Boolean poly_) : valid_ (valid), custom_data_ (custom_data), custom_type_map_ (custom_type_map), - stl (stl_) + poly_types_ (poly_types), + stl (stl_), + poly (poly_) { } @@ -364,9 +368,40 @@ namespace CXX Void set (SemanticGraph::Type& t, Boolean v) { + using SemanticGraph::Complex; + + String const& name (t.name ()); + + // Check if this type is polymorphic. + // + if (poly) + { + SemanticGraph::Context& ctx (t.context ()); + + if (!ctx.count ("polymorphic")) + { + // If our base is polymorphic then we are as well. + // + Boolean pb (false); + if (Complex* c = dynamic_cast (&t)) + { + pb = c->inherits_p () && + c->inherits ().base ().context ().count ("polymorphic"); + } + + if (pb || poly_types_.find (name) != poly_types_.end ()) + { + ctx.set ("polymorphic", true); + v = false; + } + } + else + v = false; + } + // Check if this is a custom type. // - CustomTypeMap::Iterator i = custom_type_map_.find (t.name ()); + CustomTypeMap::Iterator i = custom_type_map_.find (name); if (i != custom_type_map_.end ()) { @@ -390,7 +425,9 @@ namespace CXX Boolean& valid_; TypeSet& custom_data_; CustomTypeMap& custom_type_map_; + TypeSet& poly_types_; Boolean stl; + Boolean poly; typedef Containers::Vector Path; Path path_; @@ -453,8 +490,8 @@ namespace CXX Traversal::Fundamental::Entities { - FundType (Boolean stl_) - : stl (stl_) + FundType (Boolean stl_, TypeSet& poly_types) + : stl (stl_), poly_types_ (poly_types) { } @@ -463,7 +500,18 @@ namespace CXX virtual Void traverse (SemanticGraph::AnyType& t) { - set (t, true); + /* + @@ disabled + // Check if this type is marked polymorphic. + // + if (poly_types_.find (t.name ()) != poly_types_.end ()) + { + t.context ().set ("polymorphic", true); + set (t, false); + } + else + */ + set (t, true); } virtual Void @@ -755,6 +803,130 @@ namespace CXX private: Boolean stl; + TypeSet& poly_types_; + }; + + struct GlobalElement: Traversal::Element + { + GlobalElement (TypeSet& poly_types, + Boolean& valid, + const WarningSet& disabled_warnings) + : poly_types_ (poly_types), valid_ (valid), warning_ (true) + { + if (disabled_warnings.find ("all") != disabled_warnings.end () || + disabled_warnings.find ("H004") != disabled_warnings.end ()) + warning_ = false; + } + + virtual Void + traverse (Type& e) + { + using SemanticGraph::Schema; + + if (!e.substitutes_p ()) + return; + + // If we are a substitution for some element, then mark + // that element's type as polymorphic. + // + Type& r (e.substitutes ().root ()); + SemanticGraph::Type& rt (r.type ()); + SemanticGraph::Context& ctx (rt.context ()); + + if (ctx.count ("polymorphic")) + return; + + // Only user-defined and anyType can be declared polymorphic. + // + /* + @@ disabled + if (rt.is_a () || + rt.is_a ()) + */ + if (rt.is_a () || + rt.is_a () || + rt.is_a ()) + { + wcerr << r.file () << ":" << r.line () << ":" << r.column () + << ": error: built-in type '" << rt.name () << "' " + << "is expected to be polymorphic" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: because type '" << rt.name () << "' is " + << "used in a substitution group declared here" << endl; + + /* + @@ disabled + wcerr << r.file () << ":" << r.line () << ":" << r.column () + << ": info: only user-defined types and anyType can " + << "be polymorphic in this mapping" << endl; + */ + + wcerr << r.file () << ":" << r.line () << ":" << r.column () + << ": info: only user-defined types can " + << "be polymorphic in this mapping" << endl; + + valid_ = false; + return; + } + + ctx.set ("polymorphic", true); + + if (!warning_) + return; + + Schema& es (dynamic_cast (e.scope ().scope ())); + Schema& rts (dynamic_cast (rt.scope ().scope ())); + + // If the root type and this element are in different schemas + // and the root type is not explicitly marked as polymorphic, + // then issue a warning. + // + if (&es != &rts && + !sources_p (es, rts) && + poly_types_.find (rt.name ()) == poly_types_.end ()) + { + wcerr << rt.file () << ":" << rt.line () << ":" << rt.column () + << ": warning H004: assuming type '" << rt.name () << "' " + << "is polymorphic" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: because type '" << rt.name () << "' is " + << "used in a substitution group declared here" << endl; + + wcerr << rt.file () << ":" << rt.line () << ":" << rt.column () + << ": info: use --polymorphic-type to indicate this type " + << "is polymorphic when compiling schemas that " + << "reference it" << endl; + } + } + + private: + // Return true if root sources s. + // + Boolean + sources_p (SemanticGraph::Schema& root, SemanticGraph::Schema& s) + { + using SemanticGraph::Schema; + using SemanticGraph::Sources; + + for (Schema::UsesIterator i (root.uses_begin ()); + i != root.uses_end (); ++i) + { + if (i->is_a ()) + { + if (&i->schema () == &s || sources_p (i->schema (), s)) + return true; + } + } + + return false; + } + + private: + TypeSet& poly_types_; + Boolean& valid_; + Boolean warning_; }; // Go into sourced/included/imported schemas while making sure @@ -764,14 +936,19 @@ namespace CXX Traversal::Includes, Traversal::Imports { + Uses (Char const* seen_key) + : seen_key_ (seen_key) + { + } + virtual Void traverse (SemanticGraph::Sources& sr) { SemanticGraph::Schema& s (sr.schema ()); - if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + if (!s.context ().count (seen_key_)) { - s.context ().set ("cxx-hybrid-size-processor-seen", true); + s.context ().set (seen_key_, true); Traversal::Sources::traverse (sr); } } @@ -781,9 +958,9 @@ namespace CXX { SemanticGraph::Schema& s (i.schema ()); - if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + if (!s.context ().count (seen_key_)) { - s.context ().set ("cxx-hybrid-size-processor-seen", true); + s.context ().set (seen_key_, true); Traversal::Includes::traverse (i); } } @@ -793,21 +970,40 @@ namespace CXX { SemanticGraph::Schema& s (i.schema ()); - if (!s.context ().count ("cxx-hybrid-size-processor-seen")) + if (!s.context ().count (seen_key_)) { - s.context ().set ("cxx-hybrid-size-processor-seen", true); + s.context ().set (seen_key_, true); Traversal::Imports::traverse (i); } } + + private: + Char const* seen_key_; }; + Char const* pass_one_key = "cxx-hybrid-size-processor-seen-one"; + Char const* pass_two_key = "cxx-hybrid-size-processor-seen-two"; + Boolean process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const&) + SemanticGraph::Path const&, + const WarningSet& disabled_warnings) { Boolean valid (true); Boolean stl (!ops.value ()); + Boolean poly (ops.value ()); + + // Prepare a set of polymorphic types. + // + + TypeSet poly_types; + if (poly) + { + poly_types.insert ( + ops.value ().begin (), + ops.value ().end ()); + } // Root schema in the file-per-type mode is just a bunch // of includes without a namespace. @@ -824,7 +1020,7 @@ namespace CXX Traversal::Names schema_names; Traversal::Namespace ns; Traversal::Names ns_names; - FundType fund_type (stl); + FundType fund_type (stl, poly_types); schema >> schema_names >> ns >> ns_names >> fund_type; @@ -832,7 +1028,7 @@ namespace CXX } else { - // Pass one - assign sizes to fundamental types. + // First assign sizes to fundamental types. // { Traversal::Schema schema; @@ -844,7 +1040,7 @@ namespace CXX Traversal::Names xs_schema_names; Traversal::Namespace ns; Traversal::Names ns_names; - FundType fund_type (stl); + FundType fund_type (stl, poly_types); xs_schema >> xs_schema_names >> ns >> ns_names >> fund_type; @@ -855,7 +1051,7 @@ namespace CXX // processed which may happen in the file-per-type compilation // mode. // - if (!tu.context ().count ("cxx-hybrid-size-processor-seen")) + if (!tu.context ().count (pass_two_key)) { // Prepare a set of types with custom data. Here we are // only interested in detecting global types. If a type @@ -877,8 +1073,7 @@ namespace CXX } } - // Prepare a map of types custom types that specify type - // size. + // Prepare a map of custom types that specify type length. // CustomTypeMap custom_type_map; @@ -949,23 +1144,53 @@ namespace CXX } } + // Pass one - check substitution groups. + // + if (valid && poly) + { + Traversal::Schema schema; + Uses uses (pass_one_key); + + schema >> uses >> schema; + + Traversal::Names schema_names; + Traversal::Namespace ns; + Traversal::Names ns_names; + GlobalElement element (poly_types, valid, disabled_warnings); + + schema >> schema_names >> ns >> ns_names >> element; + + // Some twisted schemas do recusive self-inclusion. + // + tu.context ().set (pass_one_key, true); + + schema.dispatch (tu); + } + + // Pass two - process types. + // if (valid) { Traversal::Schema schema; - Uses uses; + Uses uses (pass_two_key); schema >> uses >> schema; Traversal::Names schema_names; Traversal::Namespace ns; Traversal::Names ns_names; - Type type (valid, custom_data_types, custom_type_map, stl); + Type type (valid, + custom_data_types, + custom_type_map, + poly_types, + stl, + poly); schema >> schema_names >> ns >> ns_names >> type; // Some twisted schemas do recusive self-inclusion. // - tu.context ().set ("cxx-hybrid-size-processor-seen", true); + tu.context ().set (pass_two_key, true); schema.dispatch (tu); } @@ -979,9 +1204,10 @@ namespace CXX Boolean TreeSizeProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + const WarningSet& disabled_warnings) { - return process_impl (ops, tu, file); + return process_impl (ops, tu, file, disabled_warnings); } } } diff --git a/xsde/cxx/hybrid/tree-size-processor.hxx b/xsde/cxx/hybrid/tree-size-processor.hxx index d9257a1..d82364f 100644 --- a/xsde/cxx/hybrid/tree-size-processor.hxx +++ b/xsde/cxx/hybrid/tree-size-processor.hxx @@ -12,6 +12,8 @@ #include +#include + namespace CXX { namespace Hybrid @@ -24,7 +26,8 @@ namespace CXX Boolean process (CLI::Options const& options, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const& file, + const WarningSet& disabled_warnings); }; } } diff --git a/xsde/cxx/hybrid/tree-source.cxx b/xsde/cxx/hybrid/tree-source.cxx index 6de3e35..2723046 100644 --- a/xsde/cxx/hybrid/tree-source.cxx +++ b/xsde/cxx/hybrid/tree-source.cxx @@ -14,6 +14,161 @@ namespace CXX { namespace { + struct List : Traversal::List, Context + { + List (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& l) + { + String const& name (ename_custom (l)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + if (polymorphic (l)) + { + os << "// " << comment (l.name ()) << endl + << "//" << endl + << endl; + + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{" + << "}"; + + if (typeinfo) + { + String id (l.name ()); + + if (String ns = xml_ns_name (l)) + { + id += L' '; + id += ns; + } + + if (stl) + { + os << "static const ::std::string _xsde_" << name << + "_static_type_ = " << strlit (id) << ";" + << endl; + + os << "const ::std::string& " << name << "::" << endl + << "_static_type ()" + << "{" + << "return _xsde_" << name << "_static_type_;" + << "}"; + } + else + { + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + } + + os << "const " << (stl ? "::std::string& " : "char* ") << + name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + } + }; + + // + // + struct Union : Traversal::Union, Context + { + Union (Context& c) + : Context (c) + { + } + + virtual Void + traverse (Type& u) + { + String const& name (ename_custom (u)); + + // We may not need to generate the class if this type is + // being customized. + // + if (!name) + return; + + Boolean poly (polymorphic (u)); + + if (!stl || poly) + { + os << "// " << comment (u.name ()) << endl + << "//" << endl + << endl; + + // d-tor + // + os << name << "::" << endl + << "~" << name << " ()" + << "{"; + + if (!stl) + os << "delete[] this->" << + u.context ().get ("value-member") << ";"; + + os << "}"; + + if (poly && typeinfo) + { + String id (u.name ()); + + if (String ns = xml_ns_name (u)) + { + id += L' '; + id += ns; + } + + if (stl) + { + os << "static const ::std::string _xsde_" << name << + "_static_type_ = " << strlit (id) << ";" + << endl; + + os << "const ::std::string& " << name << "::" << endl + << "_static_type ()" + << "{" + << "return _xsde_" << name << "_static_type_;" + << "}"; + } + else + { + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + } + + os << "const " << (stl ? "::std::string& " : "char* ") << + name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + } + } + }; + struct ChoiceParticle: Traversal::Element, Traversal::Compositor, Context @@ -1464,6 +1619,7 @@ namespace CXX if (!name) return; + Boolean poly (polymorphic (c)); Boolean restriction (restriction_p (c)); os << "// " << comment (c.name ()) << endl @@ -1486,22 +1642,27 @@ namespace CXX os << "}"; - - if (!restriction) + // d-tor () + // + if (!restriction || poly) { - // d-tor () - // os << name << "::" << endl << "~" << name << " ()" << "{"; - Complex::names (c, attribute_names_dtor_); + if (!restriction) + { + Complex::names (c, attribute_names_dtor_); - if (c.contains_compositor_p ()) - Complex::contains_compositor (c, contains_compositor_dtor_); + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_dtor_); + } os << "}"; + } + if (!restriction) + { if (fixed_length (c)) { // copy c-tor @@ -1554,7 +1715,49 @@ namespace CXX // if (c.contains_compositor_p ()) Complex::contains_compositor (c, contains_compositor_func_); + } + + if (poly && typeinfo) + { + String id (c.name ()); + + if (String ns = xml_ns_name (c)) + { + id += L' '; + id += ns; + } + + if (stl) + { + os << "static const ::std::string _xsde_" << name << + "_static_type_ = " << strlit (id) << ";" + << endl; + os << "const ::std::string& " << name << "::" << endl + << "_static_type ()" + << "{" + << "return _xsde_" << name << "_static_type_;" + << "}"; + } + else + { + os << "const char* " << name << "::" << endl + << "_static_type ()" + << "{" + << "return " << strlit (id) << ";" + << "}"; + } + + os << "const " << (stl ? "::std::string& " : "char* ") << + name << "::" << endl + << "_dynamic_type () const" + << "{" + << "return _static_type ();" + << "}"; + } + + if (!restriction) + { // Nested c-tors, etc. // if (c.contains_compositor_p ()) @@ -1661,16 +1864,16 @@ namespace CXX Namespace ns (ctx); - //Union union_ (ctx); + List list (ctx); + Union union_ (ctx); Complex complex (ctx); - //Enumeration enumeration (ctx); schema >> sources >> schema; schema >> names_ns >> ns >> names; - //names >> union_; + names >> list; + names >> union_; names >> complex; - //names >> enumeration; schema.dispatch (ctx.schema_root); } diff --git a/xsde/cxx/hybrid/validator.cxx b/xsde/cxx/hybrid/validator.cxx index 65dd3e2..c799563 100644 --- a/xsde/cxx/hybrid/validator.cxx +++ b/xsde/cxx/hybrid/validator.cxx @@ -20,6 +20,9 @@ namespace CXX { namespace { + // H004 is used by tree-size-processor. + // + class ValidationContext: public Context { public: @@ -34,6 +37,8 @@ namespace CXX subst_group_warning_issued (subst_group_warning_issued_), subst_group_warning_issued_ (false) { + if (disabled_warnings_.find ("all") != disabled_warnings_.end ()) + disabled_warnings_all_ = true; } public: @@ -147,7 +152,6 @@ namespace CXX } } - /* virtual Void traverse (SemanticGraph::Element& e) { @@ -165,11 +169,10 @@ namespace CXX << "--generate-polymorphic was not specified" << endl; os << e.file () << ":" << e.line () << ":" << e.column () - << ": info: generated code may not be able to serialize " + << ": info: generated code may not be able to handle " << "some conforming instances" << endl; } } - */ // Return true if root sources s. // diff --git a/xsde/cxx/parser/generator.cxx b/xsde/cxx/parser/generator.cxx index e552c92..aed6e53 100644 --- a/xsde/cxx/parser/generator.cxx +++ b/xsde/cxx/parser/generator.cxx @@ -526,6 +526,14 @@ namespace CXX return spec; } + Void Parser::Generator:: + process_names (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + NameProcessor proc; + proc.process (ops, schema, file, false); + } namespace { @@ -646,7 +654,7 @@ namespace CXX // { NameProcessor proc; - proc.process (ops, schema, file_path); + proc.process (ops, schema, file_path, true); } Boolean validation (!ops.value ()); diff --git a/xsde/cxx/parser/generator.hxx b/xsde/cxx/parser/generator.hxx index a261eca..305d8b1 100644 --- a/xsde/cxx/parser/generator.hxx +++ b/xsde/cxx/parser/generator.hxx @@ -35,17 +35,26 @@ namespace CXX static CLI::OptionsSpec options_spec (); + // Assign names to global declarations. + // + static Void + process_names (CLI::Options const&, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const&); + + // Generate code. + // struct Failed {}; static UnsignedLong - generate (CLI::Options const& options, + generate (CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file, + XSDFrontend::SemanticGraph::Path const&, TypeMap::Namespaces& type_map, Boolean gen_driver, const WarningSet& disabled_warnings, - FileList& file_list, - AutoUnlinks& unlinks); + FileList&, + AutoUnlinks&); private: Generator (); diff --git a/xsde/cxx/parser/name-processor.cxx b/xsde/cxx/parser/name-processor.cxx index bc0e7a5..9c945b3 100644 --- a/xsde/cxx/parser/name-processor.cxx +++ b/xsde/cxx/parser/name-processor.cxx @@ -1224,7 +1224,8 @@ namespace CXX Void process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { Context ctx (ops, tu, file); @@ -1290,6 +1291,9 @@ namespace CXX schema.dispatch (tu); } + if (!deep) + return; + // Pass three - assign names inside complex types. Here we don't // need to go into included/imported schemas. // @@ -1318,9 +1322,10 @@ namespace CXX Void NameProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { - process_impl (ops, tu, file); + process_impl (ops, tu, file, deep); } } } diff --git a/xsde/cxx/parser/name-processor.hxx b/xsde/cxx/parser/name-processor.hxx index 8d55f30..6a7af9f 100644 --- a/xsde/cxx/parser/name-processor.hxx +++ b/xsde/cxx/parser/name-processor.hxx @@ -22,9 +22,10 @@ namespace CXX { public: Void - process (CLI::Options const& options, + process (CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const&, + Boolean deep); }; } } diff --git a/xsde/cxx/parser/validator.cxx b/xsde/cxx/parser/validator.cxx index 570a0bf..842fc4e 100644 --- a/xsde/cxx/parser/validator.cxx +++ b/xsde/cxx/parser/validator.cxx @@ -34,6 +34,8 @@ namespace CXX subst_group_warning_issued (subst_group_warning_issued_), subst_group_warning_issued_ (false) { + if (disabled_warnings_.find ("all") != disabled_warnings_.end ()) + disabled_warnings_all_ = true; } public: diff --git a/xsde/cxx/serializer/generator.cxx b/xsde/cxx/serializer/generator.cxx index c27ef09..5e72d86 100644 --- a/xsde/cxx/serializer/generator.cxx +++ b/xsde/cxx/serializer/generator.cxx @@ -519,6 +519,14 @@ namespace CXX return spec; } + Void Serializer::Generator:: + process_names (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + NameProcessor proc; + proc.process (ops, schema, file, false); + } namespace { @@ -637,7 +645,7 @@ namespace CXX // { NameProcessor proc; - proc.process (ops, schema, file_path); + proc.process (ops, schema, file_path, true); } // diff --git a/xsde/cxx/serializer/generator.hxx b/xsde/cxx/serializer/generator.hxx index a5b8558..eaa378d 100644 --- a/xsde/cxx/serializer/generator.hxx +++ b/xsde/cxx/serializer/generator.hxx @@ -35,17 +35,26 @@ namespace CXX static CLI::OptionsSpec options_spec (); + // Assign names to global declarations. + // + static Void + process_names (CLI::Options const&, + XSDFrontend::SemanticGraph::Schema&, + XSDFrontend::SemanticGraph::Path const&); + + // Generate code. + // struct Failed {}; static UnsignedLong - generate (CLI::Options const& options, + generate (CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file, + XSDFrontend::SemanticGraph::Path const&, TypeMap::Namespaces& type_map, Boolean gen_driver, const WarningSet& disabled_warnings, - FileList& file_list, - AutoUnlinks& unlinks); + FileList&, + AutoUnlinks&); private: Generator (); diff --git a/xsde/cxx/serializer/name-processor.cxx b/xsde/cxx/serializer/name-processor.cxx index d68b823..140ad06 100644 --- a/xsde/cxx/serializer/name-processor.cxx +++ b/xsde/cxx/serializer/name-processor.cxx @@ -1307,7 +1307,8 @@ namespace CXX Void process_impl (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { Context ctx (ops, tu, file); @@ -1373,6 +1374,9 @@ namespace CXX schema.dispatch (tu); } + if (!deep) + return; + // Pass three - assign names inside complex types. Here we don't // need to go into included/imported schemas. // @@ -1401,9 +1405,10 @@ namespace CXX Void NameProcessor:: process (CLI::Options const& ops, SemanticGraph::Schema& tu, - SemanticGraph::Path const& file) + SemanticGraph::Path const& file, + Boolean deep) { - process_impl (ops, tu, file); + process_impl (ops, tu, file, deep); } } } diff --git a/xsde/cxx/serializer/name-processor.hxx b/xsde/cxx/serializer/name-processor.hxx index bf69ba6..f7cd63b 100644 --- a/xsde/cxx/serializer/name-processor.hxx +++ b/xsde/cxx/serializer/name-processor.hxx @@ -22,9 +22,10 @@ namespace CXX { public: Void - process (CLI::Options const& options, + process (CLI::Options const&, XSDFrontend::SemanticGraph::Schema&, - XSDFrontend::SemanticGraph::Path const& file); + XSDFrontend::SemanticGraph::Path const&, + Boolean deep); }; } } diff --git a/xsde/cxx/serializer/validator.cxx b/xsde/cxx/serializer/validator.cxx index d9cc724..189ccac 100644 --- a/xsde/cxx/serializer/validator.cxx +++ b/xsde/cxx/serializer/validator.cxx @@ -34,6 +34,8 @@ namespace CXX subst_group_warning_issued (subst_group_warning_issued_), subst_group_warning_issued_ (false) { + if (disabled_warnings_.find ("all") != disabled_warnings_.end ()) + disabled_warnings_all_ = true; } public: diff --git a/xsde/xsde.cxx b/xsde/xsde.cxx index 97224ca..800db93 100644 --- a/xsde/xsde.cxx +++ b/xsde/xsde.cxx @@ -583,6 +583,11 @@ main (Int argc, Char* argv[]) cmd == "cxx-serializer" || (gen_hybrid && h_ops->value ())); + Boolean poly_aggr ( + gen_hybrid && + h_ops->value () && + h_ops->value ()); + if (!fpt) { // File-per-schema compilation mode. @@ -592,6 +597,15 @@ main (Int argc, Char* argv[]) // Parse schema. // SemanticGraph::Path tu; + SemanticGraph::Paths paths; + + XSDFrontend::Parser parser ( + true, + !common_ops.value (), + loc_translator, + disabled_w); + + Evptr schema; try { @@ -601,30 +615,22 @@ main (Int argc, Char* argv[]) { e << "error: '" << args[i] << "' is not a valid " << "filesystem path" << endl; - return 1; } - XSDFrontend::Parser parser ( - true, - !common_ops.value (), - loc_translator, - disabled_w); - - Evptr schema; + // See if we are generating code for the XML Schema namespace. + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + Boolean gen_xml_schema (false); + NarrowString xml_schema_file; if (cmd == "cxx-parser" || cmd == "cxx-serializer" || cmd == "cxx-hybrid") { - // See if we are generating code for the XML Schema namespace. - // We could be compiling several schemas at once in which case - // handling of the --generate-xml-schema option gets tricky: we - // will need to rely on the presence of the --extern-xml-schema - // to tell us which (fake) schema file corresponds to XML Schema. - // - Boolean gen_xml_schema (false); - if (cmd == "cxx-parser") { gen_xml_schema = @@ -632,10 +638,10 @@ main (Int argc, Char* argv[]) if (gen_xml_schema) { - if (NarrowString name = + if (xml_schema_file = p_ops->value ()) { - if (tu.native_file_string () != name) + if (tu.native_file_string () != xml_schema_file) gen_xml_schema = false; } } @@ -647,10 +653,10 @@ main (Int argc, Char* argv[]) if (gen_xml_schema) { - if (NarrowString name = + if (xml_schema_file = s_ops->value ()) { - if (tu.native_file_string () != name) + if (tu.native_file_string () != xml_schema_file) gen_xml_schema = false; } } @@ -662,22 +668,81 @@ main (Int argc, Char* argv[]) if (gen_xml_schema) { - if (NarrowString name = + if (xml_schema_file = h_ops->value ()) { - if (tu.native_file_string () != name) + if (tu.native_file_string () != xml_schema_file) gen_xml_schema = false; } } } + } + + // If we are generating polymorphic aggregates then we need + // to add all the schemas to the semantic graph in case they + // define derived polymorphic types, except for the fake XML + // Schema file. + // + Boolean multi (poly_aggr && !gen_xml_schema); + + if (multi) + { + Size ai (1); + paths.push_back (tu); + + try + { + for (; ai < args.size (); ++ai) + { + if (ai != i && args[ai] != xml_schema_file) + paths.push_back ( + SemanticGraph::Path (args[ai], boost::filesystem::native)); + } + } + catch (SemanticGraph::InvalidPath const&) + { + e << "error: '" << args[ai] << "' is not a valid " + << "filesystem path" << endl; + return 1; + } - if (gen_xml_schema) - schema = parser.xml_schema (tu); + // Also include additional schemas that may be specified with + // the --polymorphic-schema option. + // + NarrowStrings const& extra_files ( + h_ops->value ()); + + NarrowStrings::ConstIterator i (extra_files.begin ()); + + try + { + for (; i != extra_files.end (); ++i) + { + paths.push_back ( + SemanticGraph::Path (*i, boost::filesystem::native)); + } + } + catch (SemanticGraph::InvalidPath const&) + { + e << "error: '" << i->c_str () << "' is not a valid " + << "filesystem path" << endl; + return 1; + } + + + if (args.size () <= 1) + multi = false; + } + + if (gen_xml_schema) + schema = parser.xml_schema (tu); + else + { + if (multi) + schema = parser.parse (paths); else schema = parser.parse (tu); } - else - schema = parser.parse (tu); // Morph anonymous types. // @@ -686,7 +751,11 @@ main (Int argc, Char* argv[]) try { Transformations::Anonymous trans (anon_translator); - trans.transform (*schema, tu, true); + + if (multi) + trans.transform (*schema, "", true); + else + trans.transform (*schema, tu, true); } catch (Transformations::Anonymous::Failed const&) { @@ -698,7 +767,11 @@ main (Int argc, Char* argv[]) // { Transformations::Simplifier trans; - trans.transform (*schema, tu); + + if (multi) + trans.transform (*schema, ""); + else + trans.transform (*schema, tu); } // Calculate type sizes. @@ -707,7 +780,12 @@ main (Int argc, Char* argv[]) { try { - CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, tu); + if (multi) + CXX::Hybrid::Generator::calculate_size ( + *h_ops, *schema, "", disabled_w); + else + CXX::Hybrid::Generator::calculate_size ( + *h_ops, *schema, tu, disabled_w); } catch (CXX::Hybrid::Generator::Failed const&) { @@ -721,7 +799,11 @@ main (Int argc, Char* argv[]) try { Processing::Inheritance::Processor proc; - proc.process (*schema, tu, gen_hybrid ? "fixed" : 0); + + if (multi) + proc.process (*schema, "", gen_hybrid ? "fixed" : 0); + else + proc.process (*schema, tu, gen_hybrid ? "fixed" : 0); } catch (Processing::Inheritance::Processor::Failed const&) { @@ -735,7 +817,11 @@ main (Int argc, Char* argv[]) try { Transformations::Restriction trans; - trans.transform (*schema, tu); + + if (multi) + trans.transform (*schema, ""); + else + trans.transform (*schema, tu); } catch (Transformations::Restriction::Failed const&) { @@ -743,6 +829,47 @@ main (Int argc, Char* argv[]) } } + // Get the first schema and assign names in additional + // schemas. + // + SemanticGraph::Schema* root; + + if (multi) + { + using SemanticGraph::Schema; + + Schema::UsesIterator b (schema->uses_begin ()); + ++b; // Implied XML Schema namespace. + + // The first schema. Will be handled later. + // + root = &b->schema (); + ++b; + + for (Schema::UsesIterator e (schema->uses_end ()); b != e; ++b) + { + SemanticGraph::Schema& s (b->schema ()); + SemanticGraph::Path f (b->path ()); + + if (gen_hybrid) + CXX::Hybrid::Generator::process_tree_names (*h_ops, s, f); + + if (gen_parser) + CXX::Parser::Generator::process_names (*p_ops, s, f); + + if (gen_serializer) + CXX::Serializer::Generator::process_names (*s_ops, s, f); + + if (gen_hybrid && gen_parser) + CXX::Hybrid::Generator::process_parser_names (*h_ops, s, f); + + if (gen_hybrid && gen_serializer) + CXX::Hybrid::Generator::process_serializer_names (*h_ops, s, f); + } + } + else + root = schema.get (); + // Generate mapping. // TypeMap::Namespaces parser_type_map, serializer_type_map; @@ -753,7 +880,7 @@ main (Int argc, Char* argv[]) { sloc += CXX::Hybrid::Generator::generate_tree ( *h_ops, - *schema, + *root, tu, disabled_w, parser_type_map, @@ -775,7 +902,7 @@ main (Int argc, Char* argv[]) { sloc += CXX::Parser::Generator::generate ( *p_ops, - *schema, + *root, tu, parser_type_map, true, @@ -797,7 +924,7 @@ main (Int argc, Char* argv[]) { sloc += CXX::Serializer::Generator::generate ( *s_ops, - *schema, + *root, tu, serializer_type_map, true, @@ -821,7 +948,7 @@ main (Int argc, Char* argv[]) { sloc += CXX::Hybrid::Generator::generate_parser ( *h_ops, - *schema, + *root, tu, disabled_w, file_list, @@ -841,7 +968,7 @@ main (Int argc, Char* argv[]) { sloc += CXX::Hybrid::Generator::generate_serializer ( *h_ops, - *schema, + *root, tu, disabled_w, file_list, @@ -925,7 +1052,8 @@ main (Int argc, Char* argv[]) { try { - CXX::Hybrid::Generator::calculate_size (*h_ops, *schema, ""); + CXX::Hybrid::Generator::calculate_size ( + *h_ops, *schema, "", disabled_w); } catch (CXX::Hybrid::Generator::Failed const&) { -- cgit v1.1