diff options
128 files changed, 4985 insertions, 363 deletions
@@ -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 @@ <tr><th>3.4</th><td><a href="#3.4">XML Schema Validation</a></td></tr> <tr><th>3.5</th><td><a href="#3.5">64-bit Integer Type</a></td></tr> <tr><th>3.6</th><td><a href="#3.6">Parser and Serializer Reuse</a></td></tr> + <tr><th>3.7</th><td><a href="#3.7">Support for Polymorphism</a></td></tr> </table> </td> </tr> @@ -271,6 +272,7 @@ <tr><th>4.6</th><td><a href="#4.6">Modifying the Object Model</a></td></tr> <tr><th>4.7</th><td><a href="#4.7">Creating the Object Model from Scratch</a></td></tr> <tr><th>4.8</th><td><a href="#4.8">Customizing the Object Model</a></td></tr> + <tr><th>4.9</th><td><a href="#4.9">Polymorphic Object Models</a></td></tr> </table> </td> </tr> @@ -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"</a> in the Embedded C++/Serializer Mapping Getting Started Guide for details.</p> + <h2><a name="3.7">3.7 Support for Polymorphism</a></h2> + + <p>By default the XSD/e compiler generates non-polymorphic code. If your + vocabulary uses XML Schema polymorphism in the form of <code>xsi:type</code> + and/or substitution groups, then you will need to configure the XSD/e + runtime with support for polymorphism, compile your schemas with the + <code>--generate-polymorphic</code> option to produce polymorphism-aware + code, as well as pass <code>true</code> as the last argument to the + <code>xml_schema::document_pimpl</code> and + <code>xml_schema::document_simpl</code> constructors (see + <a href="#6">Chapter 6, "Parsing and Serialization"</a> for details). + If some of your schemas do not require support for polymorphism then + you can compile them with the <code>--runtime-polymorphic</code> option + and still use the XSD/e runtime configured with polymorphism support. + </p> + + <p>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 <code>--polymorphic-type</code> 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:</p> + + <pre class="xml"> +<!-- 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> + </pre> + + <pre class="xml"> +<!-- 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> + </pre> + + <p>In this example we need to specify "<code>--polymorphic-type base</code>" + when compiling both schemas because the substitution group is declared + in a schema other than the one defining type <code>base</code>.</p> + + <p>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 <code>base.xsd</code> from the + above example:</p> + + <pre class="xml"> +<!-- 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> + </pre> + + <p>Suppose we compile this schema as follows:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd + </pre> + + <p>The resulting parser and serializer aggregates for the <code>root</code> + element will not include the parser and serializer for the + <code>derived</code> type that can be used instead of the + <code>base</code> type. This is because the XSD/e compiler + has no knowledge of the <code>derived</code>'s existence when + compiling <code>base.xsd</code>.</p> + + <p>There are two ways to overcome this problem. The easier but + potentially slower approach is to compile all your schemas + at once, for example:</p> + + <pre class="terminal"> +$ xsde cxx-hybrid --generate-parser --generate-serializer \ +--generate-polymorphic --polymorphic-type base \ +--generate-aggregate --root-element root base.xsd derived.xsd + </pre> + + <p>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 <code>--polymorphic-schema</code> + option, additional schemas that may contain derivations of the + polymorphic types. Using this approach we would compile + <code>base.xsd</code> and <code>derived.xsd</code> like this:</p> + + <pre class="terminal"> +$ 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 + </pre> + + <p>For information on how to use object models with polymorphic types, + refer to <a href="#4.9">Section 4.9, "Polymorphic Object Models"</a>.</p> + <!-- Chapater 4 --> @@ -1672,6 +1822,9 @@ private: <li>it is recursive (that is, one of its elements contains a reference, directly or indirectly, to the type itself)</li> + + <li>it is polymorphic (see <a href="#4.9">Section 4.9, "Polymorphic + Object Models"</a> for details)</li> </ol> <p>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) </pre> + <h2><a name="4.9">4.9 Polymorphic Object Models</a></h2> + + <p>When generating polymorphism-aware code (see <a href="#3.7">Section + 3.7, "Support for Polymorphism"</a>), some objects + 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:</p> + + <pre class="xml"> +<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> + </pre> + + <p>Conforming XML documents can use the <code>superman</code> + and <code>batman</code> types in place of the <code>person</code> + type either by specifying the type with the <code>xsi:type</code> + attributes or by using the elements from the substitution + group, for instance:</p> + + + <pre class="xml"> +<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> + </pre> + + <p>When compiling the schema above with the + <code>--generate-polymorphic</code> option, the XSD/e compiler + automatically detects that the type hierarchy starting with + the <code>person</code> 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:</p> + + <pre class="c++"> +// 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 (); + </pre> + + <p>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 <code>--generate-typeinfo</code> XSD/e compiler + option. When this option is specified, each polymorphic + type provides the following two public functions:</p> + + <pre class="c++"> +virtual const std::string& +_dynamic_type () const; + +static const std::string& +_static_type (); + </pre> + + <p>Or, if STL is disabled (<a href="#3.1">Section 3.1, "Standard Template + Library"</a>), the following two functions:</p> + + <pre class="c++"> +virtual const char* +_dynamic_type () const; + +static const char* +_static_type (); + </pre> + + <p>The <code>_dynamic_type()</code> function returns the object's + dynamic type id. The <code>_static_type()</code> 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:</p> + + <pre class="c++"> +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; + } +} + </pre> + + <p>Most of the code presented in this section is taken from the + <code>polymorphism</code> example which can be found in the + <code>examples/cxx/hybrid/</code> directory of the XSD/e distribution. + Handling of <code>xsi:type</code> and substitution groups when used + on root elements requires a number of special actions as shown in + the <code>polyroot</code> example.</p> + + <!-- Built-in XML Schema Type Parsers --> 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 <code>--generate-polymorphic</code> option to produce polymorphism-aware code, as well as pass <code>true</code> as the last argument to the - <code>xml_schema::document</code>'s constructors. If some of your + <code>xml_schema::document_pimpl</code>'s constructors. If some of your schemas do not require support for polymorphism then you can compile them with the <code>--runtime-polymorphic</code> 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.</dd> + <dt><code><b>--generate-polymorphic</b></code></dt> + <dd>Generate polymorphism-aware code. Specify this option if you use + substitution groups or <code><b>xsi:type</b></code>. Use the + <code><b>--polymorphic-type</b></code> option to specify which + type hierarchies are polymorphic.</dd> + + <dt><code><b>--runtime-polymorphic</b></code></dt> + <dd>Generate non-polymorphic code that uses the runtime library + configured with polymorphism support.</dd> + + <dt><code><b>--polymorphic-type</b></code> <i>type</i></dt> + <dd>Indicate that <code><i>type</i></code> 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 <code><i>type</i></code>.</dd> + + <dt><code><b>--generate-typeinfo</b></code></dt> + <dd>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.</dd> + + <dt><code><b>--polymorphic-schema</b></code> <i>file</i></dt> + <dd>Indicate that <code><i>file</i></code> 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.</dd> + <dt><code><b>--reuse-style-mixin</b></code></dt> <dd>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.</dd> - <dt><code><b>--custom-data</b></code> <i>type</i></dt> <dd>Add the ability to store custom data to the C++ class generated for XML Schema type <code><i>type</i></code>. 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 <iostream> #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 <iostream> #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 <iostream> #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 <iostream> #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 <stdio.h> #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 <supermen.xml diff --git a/examples/cxx/hybrid/polymorphism/driver.cxx b/examples/cxx/hybrid/polymorphism/driver.cxx new file mode 100644 index 0000000..926bb91 --- /dev/null +++ b/examples/cxx/hybrid/polymorphism/driver.cxx @@ -0,0 +1,202 @@ +// file : examples/cxx/hybrid/polymorphism/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#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<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; + + // 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<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); +#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 <boris@codesynthesis.com> +# 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 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polymorphism/supermen.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<supermen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd"> + + <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> 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 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polymorphism/supermen.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + + <!-- substitution group root --> + <xsd:element name="person" type="person"/> + + + <xsd:complexType name="superman"> + <xsd:complexContent> + <xsd:extension base="person"> + <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="superman" type="superman" substitutionGroup="person"/> + + <xsd:complexType name="batman"> + <xsd:complexContent> + <xsd:extension base="superman"> + <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="supermen"> + <xsd:sequence> + <xsd:element ref="person" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="supermen" type="supermen"/> + +</xsd:schema> 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 <person.xml +$ ./driver <superman.xml +$ ./driver <batman.xml diff --git a/examples/cxx/hybrid/polyroot/batman.xml b/examples/cxx/hybrid/polyroot/batman.xml new file mode 100644 index 0000000..96248ff --- /dev/null +++ b/examples/cxx/hybrid/polyroot/batman.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polyroot/batman.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd" + xsi:type="batman" can-fly="true" wing-span="10"> + + <name>Bruce Wayne</name> + +</person> 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 <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#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<person_pskel*> (p); +#else + parser_used_ = static_cast<person_pskel*> (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<person> 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<person> 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<batman&> (*p); + cerr << b.name () << ", batman, wing span " << b.wing_span () << endl; + } + else if (superman* s = dynamic_cast<superman*> (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<person_sskel*> (s); +#else + ps = static_cast<person_sskel*> (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 <boris@codesynthesis.com> +# 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 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polyroot/person.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd"> + + <name>John Doe</name> + +</person> 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 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polyroot/superman.xml +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<superman xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="supermen.xsd" + can-fly="false"> + + <name>James "007" Bond</name> + +</superman> 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 @@ +<?xml version="1.0"?> + +<!-- + +file : examples/cxx/hybrid/polyroot/supermen.xsd +author : Boris Kolpackov <boris@codesynthesis.com> +copyright : not copyrighted - public domain + +--> + +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="person"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + + <!-- substitution group root --> + <xsd:element name="person" type="person"/> + + <xsd:complexType name="superman"> + <xsd:complexContent> + <xsd:extension base="person"> + <xsd:attribute name="can-fly" type="xsd:boolean" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:element name="superman" type="superman" substitutionGroup="person"/> + + <xsd:complexType name="batman"> + <xsd:complexContent> + <xsd:extension base="superman"> + <xsd:attribute name="wing-span" type="xsd:unsignedInt" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + +</xsd:schema> 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 <iostream> #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 <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <xsde/cxx/hybrid/any-type.hxx> + +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 <xsde/cxx/config.hxx> + +/* +#ifdef XSDE_STL +# include <string> +#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 <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <string.h> // strcmp + +#include <xsde/cxx/hybrid/parser-map.hxx> + +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<bool&> (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 <boris@codesynthesis.com> +// 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 <stddef.h> // size_t + +#include <xsde/cxx/parser/map.hxx> + +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 <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <string.h> // strcmp + +#include <xsde/cxx/hybrid/serializer-map.hxx> + +namespace xsde +{ + namespace cxx + { + namespace hybrid + { + serializer::serializer_base* serializer_map_impl:: + find (const void* v) const + { + const char* tid = static_cast<const char*> (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<bool&> (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 <boris@codesynthesis.com> +// 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 <stddef.h> // size_t + +#include <xsde/cxx/serializer/map.hxx> + +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<bool&> (resetting_); + r = true; + for (hashmap::const_iterator i (map_.begin ()), e (map_.end ()); i != e; ++i) { parser_base* p = *static_cast<parser_base* const*> (*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<bool&> (resetting_); + r = true; + for (hashmap::const_iterator i (map_.begin ()), e (map_.end ()); i != e; ++i) { serializer_base* s = *static_cast<serializer_base* const*> (*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 <boris@codesynthesis.com> +// 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 <iostream> + +#include "test.hxx" +#include "test-pimpl.hxx" +#include "test-simpl.hxx" + +using namespace std; +using namespace test; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " test.xml" << endl; + return 1; + } + + // Parse. + // + root_paggr root_p; + + xml_schema::document_pimpl doc_p ( + root_p.root_parser (), + root_p.root_namespace (), + root_p.root_name (), + true); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + // 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 <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := test.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +test := $(out_base)/.test +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \ + $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \ + $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \ + $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \ + $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx) + +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen): xsde_options += --generate-parser --generate-serializer \ +--generate-aggregate --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 @@ +<t:root xmlns:t="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <t:any><x>abc</x>junk<y>123</y></t:any> + <t:base ><a>123</a><b>abc</b></t:base> + <t:any xsi:type="t:derived"><a>123</a><b>abc</b><c>9</c><c>8</c><c>7</c></t:any> + +</t:root> 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 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <element name="any" type="anyType"/> + + <complexType name="base"> + <complexContent> + <restriction base="anyType"> + <sequence> + <element name="a" type="int"/> + <element name="b" type="string"/> + </sequence> + </restriction> + </complexContent> + </complexType> + + <element name="base" type="t:base" substitutionGroup="t:any"/> + + <complexType name="derived"> + <complexContent> + <extension base="t:base"> + <sequence> + <element name="c" type="int" maxOccurs="unbounded"/> + </sequence> + </extension> + </complexContent> + </complexType> + + <complexType name="type"> + <sequence> + <element ref="t:any" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="root" type="t:type"/> + +</schema> diff --git a/tests/cxx/hybrid/polymorphism/makefile b/tests/cxx/hybrid/polymorphism/makefile 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 <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +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 <boris@codesynthesis.com> +// 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 <iostream> + +#include "test.hxx" +#include "test-pimpl.hxx" +#include "test-simpl.hxx" + +using namespace std; +using namespace test; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " test.xml" << endl; + return 1; + } + + // Parse. + // + root_paggr root_p; + + xml_schema::document_pimpl doc_p ( + root_p.root_parser (), + root_p.root_namespace (), + root_p.root_name (), + true); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + // 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 <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2009 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../../build/bootstrap.make + +xsd := test.xsd 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 @@ +<t:root xmlns:t="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><x xsi:type="t:foo"><a>abc</a><b>123</b></x><x xsi:type="t:bar"><a>abc</a><b>true</b></x><x xsi:type="t:baz"><a>abc</a><b>123</b><c>true</c></x></t:root>
\ 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 @@ +<t:root xmlns:t="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <x xsi:type="t:foo"><a>abc</a><b>123</b></x> + <x xsi:type="t:bar"><a>abc</a><b>true</b></x> + <x xsi:type="t:baz"><a>abc</a><b>123</b><c>true</c></x> + +</t:root> 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 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <complexType name="base"> + <sequence> + <element name="a" type="string"/> + </sequence> + </complexType> + + <complexType name="foo"> + <complexContent> + <extension base="t:base"> + <sequence> + <element name="b" type="int"/> + </sequence> + </extension> + </complexContent> + </complexType> + + <complexType name="type"> + <sequence> + <element name="x" type="t:base" maxOccurs="unbounded"/> + </sequence> + </complexType> + + <element name="root" type="t:type"/> + +</schema> 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 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <include schemaLocation="test.xsd"/> + + <complexType name="bar"> + <complexContent> + <extension base="t:base"> + <sequence> + <element name="b" type="boolean"/> + </sequence> + </extension> + </complexContent> + </complexType> + + <complexType name="baz"> + <complexContent> + <extension base="t:foo"> + <sequence> + <element name="c" type="boolean"/> + </sequence> + </extension> + </complexContent> + </complexType> + +</schema> 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 <boris@codesynthesis.com> +// 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 <cult/containers/map.hxx> + +#include <cxx/hybrid/elements.hxx> + +namespace CXX +{ + namespace Hybrid + { + typedef + Cult::Containers::Map<SemanticGraph::Type*, String> + TypeInstanceMap; + + struct InstanceInfo + { + SemanticGraph::Type* type; + String name; + }; + + typedef Cult::Containers::Map<String, InstanceInfo> 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 <boris@codesynthesis.com> +// 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 <cult/containers/set.hxx> + +#include <xsd-frontend/semantic-graph.hxx> +#include <xsd-frontend/traversal.hxx> + +#include <cxx/hybrid/elements.hxx> + +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<Schema&> (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<SemanticGraph::Type*> types_; + Cult::Containers::Set<SemanticGraph::Schema*> 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<NarrowString>, + generate_typeinfo, Boolean, + polymorphic_schema, Cult::Containers::Vector<NarrowString>, reuse_style_mixin, Boolean, custom_data, Cult::Containers::Vector<NarrowString>, custom_type, Cult::Containers::Vector<NarrowString>, 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<CLI::no_exceptions> ()), stl (!ops.value<CLI::no_stl> ()), - poly_code (false), - poly_runtime (false), + poly_code (ops.value<CLI::generate_polymorphic> ()), reset (!ops.value<CLI::suppress_reset> ()), detach (ops.value<CLI::generate_detach> ()), mixin (ops.value<CLI::reuse_style_mixin> ()), @@ -55,6 +54,10 @@ namespace CXX ixdrstream (ixdrstream_), oxdrstream (oxdrstream_) { + typeinfo = poly_code && + (ops.value<CLI::generate_typeinfo> () || + ops.value<CLI::generate_serializer> ()); + 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 <type>" << endl + << " Indicate that <type> 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 <file>" << endl + << " Indicate that <file> 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<P::generate_xml_schema> () = h.value<H::generate_xml_schema> (); r->value<P::extern_xml_schema> () = h.value<H::extern_xml_schema> (); r->value<P::suppress_reset> () = h.value<H::suppress_reset> (); + r->value<P::generate_polymorphic> () = h.value<H::generate_polymorphic> (); + r->value<P::runtime_polymorphic> () = h.value<H::runtime_polymorphic> (); r->value<P::output_dir> () = h.value<H::output_dir> (); r->value<P::skel_file_suffix> () = h.value<H::pskel_file_suffix> (); r->value<P::skel_type_suffix> () = h.value<H::pskel_type_suffix> (); @@ -862,6 +895,8 @@ namespace CXX r->value<S::generate_xml_schema> () = h.value<H::generate_xml_schema> (); r->value<S::extern_xml_schema> () = h.value<H::extern_xml_schema> (); r->value<S::suppress_reset> () = h.value<H::suppress_reset> (); + r->value<S::generate_polymorphic> () = h.value<H::generate_polymorphic> (); + r->value<S::runtime_polymorphic> () = h.value<H::runtime_polymorphic> (); r->value<S::output_dir> () = h.value<H::output_dir> (); r->value<S::skel_file_suffix> () = h.value<H::sskel_file_suffix> (); r->value<S::skel_type_suffix> () = h.value<H::sskel_type_suffix> (); @@ -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 <typename S> @@ -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<CLI::generate_aggregate> ()); + // HXX // { @@ -2012,6 +2077,14 @@ namespace CXX hxx << "#include <xsde/cxx/pre.hxx>" << 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<Indentation::CXX, WideChar> hxx_clip (hxx); @@ -2021,9 +2094,24 @@ namespace CXX generate_parser_header (ctx); - if (ops.value<CLI::generate_aggregate> ()) + // 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 <xsde/cxx/post.hxx>" << endl << endl; } @@ -2090,7 +2178,7 @@ namespace CXX generate_parser_source (ctx); - if (ops.value<CLI::generate_aggregate> ()) + 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<CLI::generate_aggregate> ()); // HXX // @@ -2379,6 +2468,14 @@ namespace CXX hxx << "#include <xsde/cxx/pre.hxx>" << 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<Indentation::CXX, WideChar> hxx_clip (hxx); @@ -2388,9 +2485,24 @@ namespace CXX generate_serializer_header (ctx); - if (ops.value<CLI::generate_aggregate> ()) + // 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 <xsde/cxx/post.hxx>" << endl << endl; } @@ -2457,7 +2569,7 @@ namespace CXX generate_serializer_source (ctx); - if (ops.value<CLI::generate_aggregate> ()) + 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 <cxx/hybrid/parser-aggregate-header.hxx> +#include <cxx/hybrid/aggregate-elements.hxx> +#include <cxx/hybrid/aggregate-include.hxx> #include <xsd-frontend/semantic-graph.hxx> #include <xsd-frontend/traversal.hxx> -#include <cult/containers/map.hxx> #include <cult/containers/set.hxx> namespace CXX @@ -17,10 +18,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map<SemanticGraph::Type*, String> - TypeInstanceMap; - typedef Cult::Containers::Set<String> 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<String> ("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<TypeInstanceMap> ("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<String> ("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<TypeInstanceMap> ("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 <xsde/cxx/hybrid/parser-map.hxx>" << 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 <cxx/hybrid/parser-aggregate-source.hxx> +#include <cxx/hybrid/aggregate-elements.hxx> #include <xsd-frontend/semantic-graph.hxx> #include <xsd-frontend/traversal.hxx> @@ -16,10 +17,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map<SemanticGraph::Type*, String> - 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<String> ("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<TypeIdInstanceMap> ("paggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << tc.get<String> ("paggr-parser-map") << " (" << + tc.get<String> ("paggr-parser-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + // Populate the polymorphic parser map. + // + if (tid_map) + { + String const& entry (tc.get<String> ("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<String> ("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<TypeIdInstanceMap> ("paggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << ec.get<String> ("paggr-parser-map") << " (" << + ec.get<String> ("paggr-parser-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + + // Populate the polymorphic parser map. + // + if (tid_map) + { + String const& entry (ec.get<String> ("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<String> ("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 <cxx/hybrid/serializer-aggregate-header.hxx> +#include <cxx/hybrid/aggregate-elements.hxx> +#include <cxx/hybrid/aggregate-include.hxx> #include <xsd-frontend/semantic-graph.hxx> #include <xsd-frontend/traversal.hxx> @@ -17,10 +19,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map<SemanticGraph::Type*, String> - TypeInstanceMap; - typedef Cult::Containers::Set<String> 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<String> ("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<TypeInstanceMap> ("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<String> ("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<TypeInstanceMap> ("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 <xsde/cxx/hybrid/serializer-map.hxx>" << 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 <cxx/hybrid/serializer-aggregate-source.hxx> +#include <cxx/hybrid/aggregate-elements.hxx> #include <xsd-frontend/semantic-graph.hxx> #include <xsd-frontend/traversal.hxx> @@ -16,10 +17,6 @@ namespace CXX { namespace { - typedef - Cult::Containers::Map<SemanticGraph::Type*, String> - 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<String> ("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<TypeIdInstanceMap> ("saggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << tc.get<String> ("saggr-serializer-map") << " (" << + tc.get<String> ("saggr-serializer-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + // Populate the polymorphic serializer map. + // + if (tid_map) + { + String const& entry ( + tc.get<String> ("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<String> ("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<TypeIdInstanceMap> ("saggr-tid-map"); + // c-tor () // os << name << "::" << endl - << name << " ()" - << "{"; + << name << " ()"; + + if (tid_map) + { + os << endl + << ": " << ec.get<String> ("saggr-serializer-map") << " (" << + ec.get<String> ("saggr-serializer-map-entries") << ", " << + tid_map->size () << "UL)"; + } + + os << "{"; + + // Populate the polymorphic serializer map. + // + if (tid_map) + { + String const& entry ( + ec.get<String> ("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<String> ("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<String> ("p:name")); + String const& skel (lc.get<String> ("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 <string.h>" << 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<String> ("value")); String const& member (uc.get<String> ("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<Complex*> (&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<SemanticGraph::Complex*> 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<SemanticGraph::Fundamental::Type> () || + rt.is_a<SemanticGraph::AnySimpleType> ()) + */ + if (rt.is_a<SemanticGraph::Fundamental::Type> () || + rt.is_a<SemanticGraph::AnySimpleType> () || + rt.is_a<SemanticGraph::AnyType> ()) + { + 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<Schema&> (e.scope ().scope ())); + Schema& rts (dynamic_cast<Schema&> (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<Sources> ()) + { + 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<CLI::no_stl> ()); + Boolean poly (ops.value<CLI::generate_polymorphic> ()); + + // Prepare a set of polymorphic types. + // + + TypeSet poly_types; + if (poly) + { + poly_types.insert ( + ops.value<CLI::polymorphic_type> ().begin (), + ops.value<CLI::polymorphic_type> ().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 <cxx/hybrid/cli.hxx> +#include <xsde.hxx> + 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<String> ("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<CLI::suppress_validation> ()); 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<CXX::Hybrid::CLI::generate_serializer> ())); + Boolean poly_aggr ( + gen_hybrid && + h_ops->value<CXX::Hybrid::CLI::generate_polymorphic> () && + h_ops->value<CXX::Hybrid::CLI::generate_aggregate> ()); + 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<CLI::disable_full_check> (), + loc_translator, + disabled_w); + + Evptr<SemanticGraph::Schema> 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<CLI::disable_full_check> (), - loc_translator, - disabled_w); - - Evptr<SemanticGraph::Schema> 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<CXX::Parser::CLI::extern_xml_schema> ()) { - 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<CXX::Serializer::CLI::extern_xml_schema> ()) { - 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<CXX::Hybrid::CLI::extern_xml_schema> ()) { - 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<CXX::Hybrid::CLI::polymorphic_schema> ()); + + 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&) { |