diff options
author | randomdan <randomdan@localhost> | 2014-06-26 13:20:58 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2014-06-26 13:20:58 +0000 |
commit | 9b0fb1a52dd7b8db1dab98cebf7b928e4d921111 (patch) | |
tree | 346f7c2dfe4530f86b44d304a5b620ce3a4dce06 | |
parent | Move the name into the hook (diff) | |
download | slicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.tar.bz2 slicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.tar.xz slicer-9b0fb1a52dd7b8db1dab98cebf7b928e4d921111.zip |
Adds support for classes with inheritance
Adds more unit tests and verifies written XML is the same as the initial
-rw-r--r-- | slicer/slicer/modelParts.cpp | 31 | ||||
-rw-r--r-- | slicer/slicer/modelParts.h | 34 | ||||
-rw-r--r-- | slicer/slicer/parser.cpp | 137 | ||||
-rw-r--r-- | slicer/slicer/parser.h | 5 | ||||
-rw-r--r-- | slicer/test/Jamfile.jam | 1 | ||||
-rw-r--r-- | slicer/test/initial/builtins.xml | 8 | ||||
-rw-r--r-- | slicer/test/initial/optionals-areset.xml | 42 | ||||
-rw-r--r-- | slicer/test/initial/optionals-notset.xml | 5 | ||||
-rw-r--r-- | slicer/test/run-slicer.cpp | 6 | ||||
-rw-r--r-- | slicer/test/types.ice | 19 | ||||
-rw-r--r-- | slicer/xml/serializer.cpp | 9 |
11 files changed, 202 insertions, 95 deletions
diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp index 9d33d51..4c05513 100644 --- a/slicer/slicer/modelParts.cpp +++ b/slicer/slicer/modelParts.cpp @@ -1,14 +1,45 @@ #include "modelParts.h" namespace Slicer { + IncorrectElementName::IncorrectElementName(const std::string & n) : + std::invalid_argument(n) + { + } + + UnknownType::UnknownType(const std::string & n) : + std::invalid_argument(n) + { + } + + ClassRefMap * & + classRefMap() + { + static ClassRefMap * refs = new ClassRefMap(); + return refs; + } + void ModelPart::Create() { } + void ModelPart::Complete() { } + + ModelPartPtr + ModelPart::GetSubclassModelPart(const std::string &) + { + return this; + } + + TypeId + ModelPart::GetTypeId() const + { + return TypeId(); + } + void ModelPart::SetValue(ValueSourcePtr) { diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index 9c2bf45..28ab86d 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -15,8 +15,12 @@ namespace Slicer { class IncorrectElementName : public std::invalid_argument { public: - IncorrectElementName() : - std::invalid_argument("") { } + IncorrectElementName(const std::string & n); + }; + + class UnknownType : public std::invalid_argument { + public: + UnknownType(const std::string & n); }; class ValueTarget : public IceUtil::Shared { @@ -49,15 +53,22 @@ namespace Slicer { typedef IceUtil::Handle<ModelPart> ModelPartPtr; typedef std::map<std::string, ModelPartPtr> ModelParts; + typedef IceUtil::Optional<std::string> TypeId; typedef boost::function<void(const std::string &, ModelPartPtr)> ChildHandler; + typedef boost::function<ModelPartPtr(void *)> ClassRef; + typedef std::map<std::string, ClassRef> ClassRefMap; + ClassRefMap * & classRefMap(); + class ModelPart : public IceUtil::Shared { public: virtual ~ModelPart() = default; virtual void OnEachChild(const ChildHandler &) = 0; - virtual ModelPartPtr GetChild(const std::string &) = 0; + virtual ModelPartPtr GetChild(const std::string & memberName) = 0; + virtual ModelPartPtr GetSubclassModelPart(const std::string &); + virtual TypeId GetTypeId() const; virtual void Create(); virtual void Complete(); virtual void SetValue(ValueSourcePtr); @@ -165,7 +176,7 @@ namespace Slicer { }; typedef IceUtil::Handle<HookBase> HookPtr; - template <typename MT, MT T::*M, typename MP> + template <typename MT, typename CT, MT CT::*M, typename MP> class Hook : public HookBase { public: Hook(const std::string & n) : @@ -239,8 +250,19 @@ namespace Slicer { return ModelObject.get(); } + virtual ModelPartPtr GetSubclassModelPart(const std::string & name) override + { + auto ref = classRefMap()->find(name); + if (ref == classRefMap()->end()) { + throw UnknownType(name); + } + return ref->second(&this->ModelObject); + } + virtual bool HasValue() const override { return ModelObject; } + virtual TypeId GetTypeId() const override; + private: T & ModelObject; }; @@ -288,7 +310,7 @@ namespace Slicer { virtual ModelPartPtr GetChild(const std::string & name) override { if (!name.empty() && name != rootName) { - throw IncorrectElementName(); + throw IncorrectElementName(rootName); } ModelPartForClass<T>::Create(); return new ModelPartForClass<T>(ModelObject); @@ -406,7 +428,7 @@ namespace Slicer { ModelPartPtr GetChild(const std::string & name) override { if (!name.empty() && name != pairName) { - throw IncorrectElementName(); + throw IncorrectElementName(pairName); } return new ModelPartForDictionaryElementInserter<T>(dictionary); } diff --git a/slicer/slicer/parser.cpp b/slicer/slicer/parser.cpp index c874f57..8e2bfa9 100644 --- a/slicer/slicer/parser.cpp +++ b/slicer/slicer/parser.cpp @@ -11,7 +11,8 @@ namespace fs = boost::filesystem; namespace Slicer { Slicer::Slicer(FILE * c) : - cpp(c) + cpp(c), + classNo(0) { } @@ -47,47 +48,43 @@ namespace Slicer { { if (c->hasMetaData("slicer:ignore")) { return false; } + auto decl = c->declaration(); fprintf(cpp, "// Class %s\n", c->name().c_str()); fprintf(cpp, "template<>\n"); fprintf(cpp, "ModelPartForComplex< %s::%s >::Hooks ", modulePath().c_str(), c->name().c_str()); fprintf(cpp, "ModelPartForComplex< %s::%s >::hooks {\n", modulePath().c_str(), c->name().c_str()); - BOOST_FOREACH (const auto & dm, c->allDataMembers()) { - auto name = metaDataValue("slicer:name:", dm->getMetaData()); - fprintf(cpp, "\t\t{ "); - auto type = dm->type(); - fprintf(cpp, "new ModelPartForClass< %s::%sPtr >::Hook< ", - modulePath().c_str(), c->name().c_str()); - if (dm->optional()) { - fprintf(cpp, "::IceUtil::Optional< %s >", - Slice::typeToString(type).c_str()); - } - else { - fprintf(cpp, "%s", - Slice::typeToString(type).c_str()); - } - fprintf(cpp, ", &%s::%s::%s, ", - modulePath().c_str(), c->name().c_str(), dm->name().c_str()); - if (dm->optional()) { - fprintf(cpp, "ModelPartForOptional< "); - } - createNewModelPartPtrFor(type); - fprintf(cpp, "< %s", - Slice::typeToString(type).c_str()); - if (dm->optional()) { - fprintf(cpp, " > "); - } - fprintf(cpp, " > >(\"%s\") },\n", - name ? name->c_str() : dm->name().c_str()); - } - fprintf(cpp, "\t};\n"); + visitComplexDataMembers(decl, c->allDataMembers()); + fprintf(cpp, "\t};\n\n"); fprintf(cpp, "template<>\n"); auto name = metaDataValue("slicer:root:", c->getMetaData()); - fprintf(cpp, "std::string ModelPartForClassRoot< %s::%sPtr >::rootName(\"%s\");\n\n", - modulePath().c_str(), c->name().c_str(), + fprintf(cpp, "std::string ModelPartForClassRoot< %s >::rootName(\"%s\");\n\n", + typeToString(decl).c_str(), name ? name->c_str() : c->name().c_str()); + + fprintf(cpp, "static void registerClass_%u() __attribute__ ((constructor(210)));\n", classNo); + fprintf(cpp, "static void registerClass_%u()\n{\n", classNo); + fprintf(cpp, "\tSlicer::classRefMap()->insert({ \"%s::%s\", [](void * p){ return new ModelPartForClass< %s >(*static_cast< %s *>(p)); } });\n", + modulePath().c_str(), c->name().c_str(), + typeToString(decl).c_str(), + typeToString(decl).c_str()); + fprintf(cpp, "}\n\n"); + fprintf(cpp, "static void unregisterClass_%u() __attribute__ ((destructor(210)));\n", classNo); + fprintf(cpp, "static void unregisterClass_%u()\n{\n", classNo); + fprintf(cpp, "\tSlicer::classRefMap()->erase(\"%s::%s\");\n", + modulePath().c_str(), c->name().c_str()); + fprintf(cpp, "}\n\n"); + + fprintf(cpp, "template<>\nTypeId\nModelPartForClass< %s >::GetTypeId() const\n{\n", + typeToString(decl).c_str()); + fprintf(cpp, "\tauto id = ModelObject->ice_id();\n"); + fprintf(cpp, "\treturn (id == \"%s::%s\") ? TypeId() : id;\n}\n\n", + modulePath().c_str(), c->name().c_str()); + + classNo += 1; + return true; } @@ -102,22 +99,43 @@ namespace Slicer { modulePath().c_str(), c->name().c_str()); fprintf(cpp, "ModelPartForComplex< %s::%s >::hooks {\n", modulePath().c_str(), c->name().c_str()); - BOOST_FOREACH (const auto & dm, c->dataMembers()) { + visitComplexDataMembers(c, c->dataMembers()); + fprintf(cpp, "\t};\n\n"); + + return true; + } + + void + Slicer::visitComplexDataMembers(Slice::TypePtr it, const Slice::DataMemberList & dataMembers) const + { + BOOST_FOREACH (const auto & dm, dataMembers) { + auto c = Slice::ContainedPtr::dynamicCast(dm->container()); + auto t = Slice::TypePtr::dynamicCast(dm->container()); + if (!t) { + t = Slice::ClassDefPtr::dynamicCast(dm->container())->declaration(); + } auto name = metaDataValue("slicer:name:", dm->getMetaData()); - fprintf(cpp, "\t\t{ "); + fprintf(cpp, "\t\tnew "); auto type = dm->type(); - fprintf(cpp, "new ModelPartForStruct< %s::%s >::Hook< %s, &%s::%s::%s, ", - modulePath().c_str(), c->name().c_str(), - Slice::typeToString(type).c_str(), - modulePath().c_str(), c->name().c_str(), dm->name().c_str()); + createNewModelPartPtrFor(t); + fprintf(cpp, "< %s >::Hook< %s", + typeToString(it).c_str(), + Slice::typeToString(type, dm->optional()).c_str()); + fprintf(cpp, ", %s::%s, &%s::%s::%s, ", + modulePath().c_str(), c->name().c_str(), + modulePath().c_str(), c->name().c_str(), dm->name().c_str()); + if (dm->optional()) { + fprintf(cpp, "ModelPartForOptional< "); + } createNewModelPartPtrFor(type); - fprintf(cpp, "< %s > >(\"%s\") },\n", - Slice::typeToString(type).c_str(), + fprintf(cpp, "< %s", + Slice::typeToString(type).c_str()); + if (dm->optional()) { + fprintf(cpp, " > "); + } + fprintf(cpp, " > >(\"%s\"),\n", name ? name->c_str() : dm->name().c_str()); } - fprintf(cpp, "\t};\n\n"); - - return true; } void @@ -137,13 +155,11 @@ namespace Slicer { else { fprintf(cpp, "\t(void)name;\n"); } - fprintf(cpp, "\tsequence.push_back(%s());\n", - Slice::typeToString(s->type()).c_str()); + fprintf(cpp, "\tsequence.push_back(typename element_type::value_type());\n"); fprintf(cpp, "\treturn new "); auto etype = s->type(); createNewModelPartPtrFor(etype); - fprintf(cpp, "< %s >(sequence.back());\n}\n\n", - Slice::typeToString(etype).c_str()); + fprintf(cpp, "<typename element_type::value_type>(sequence.back());\n}\n\n"); fprintf(cpp, "template<>\n"); fprintf(cpp, "ModelPartPtr\n"); fprintf(cpp, "ModelPartForSequence< %s::%s >::elementModelPart(typename %s::%s::value_type & e) const {\n", @@ -151,8 +167,7 @@ namespace Slicer { modulePath().c_str(), s->name().c_str()); fprintf(cpp, "\treturn new "); createNewModelPartPtrFor(etype); - fprintf(cpp, "< %s >(e);\n}\n\n", - Slice::typeToString(etype).c_str()); + fprintf(cpp, "<typename element_type::value_type>(e);\n}\n\n"); fprintf(cpp, "template<>\n"); auto ename = metaDataValue("slicer:element:", s->getMetaData()); fprintf(cpp, "std::string ModelPartForSequence< %s::%s >::elementName(\"%s\");\n\n", @@ -179,23 +194,25 @@ namespace Slicer { modulePath().c_str(), d->name().c_str()); auto kname = metaDataValue("slicer:key:", d->getMetaData()); auto vname = metaDataValue("slicer:value:", d->getMetaData()); - fprintf(cpp, "\t\t{ "); + fprintf(cpp, "\t\t"); auto ktype = d->keyType(); - fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::key, ", + fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, ModelPartForDictionaryElement< %s::%s >, &ModelPartForDictionaryElement< %s::%s >::key, ", modulePath().c_str(), d->name().c_str(), Slice::typeToString(ktype).c_str(), + modulePath().c_str(), d->name().c_str(), modulePath().c_str(), d->name().c_str()); createNewModelPartPtrFor(ktype); - fprintf(cpp, "< %s > >(\"%s\") },\n\t\t{ ", + fprintf(cpp, "< %s > >(\"%s\"),\n\t\t", Slice::typeToString(ktype).c_str(), kname ? kname->c_str() : "key"); auto vtype = d->valueType(); - fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::value, ", + fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, ModelPartForDictionaryElement< %s::%s >, &ModelPartForDictionaryElement< %s::%s >::value, ", modulePath().c_str(), d->name().c_str(), Slice::typeToString(vtype).c_str(), + modulePath().c_str(), d->name().c_str(), modulePath().c_str(), d->name().c_str()); createNewModelPartPtrFor(vtype); - fprintf(cpp, "< %s > >(\"%s\") },\n", + fprintf(cpp, "< %s > >(\"%s\"),\n", Slice::typeToString(vtype).c_str(), vname ? vname->c_str() : "value"); fprintf(cpp, "\t};\n"); @@ -213,24 +230,24 @@ namespace Slicer { Slicer::createNewModelPartPtrFor(const Slice::TypePtr & type) const { if (auto builtin = Slice::BuiltinPtr::dynamicCast(type)) { - fprintf(cpp, "ModelPartForSimple "); + fprintf(cpp, "ModelPartForSimple"); } else if (auto complexClass = Slice::ClassDeclPtr::dynamicCast(type)) { - fprintf(cpp, "ModelPartForClass "); + fprintf(cpp, "ModelPartForClass"); } else if (auto complexStruct = Slice::StructPtr::dynamicCast(type)) { - fprintf(cpp, "ModelPartForStruct "); + fprintf(cpp, "ModelPartForStruct"); } else if (auto sequence = Slice::SequencePtr::dynamicCast(type)) { - fprintf(cpp, "ModelPartForSequence "); + fprintf(cpp, "ModelPartForSequence"); } else if (auto dictionary = Slice::DictionaryPtr::dynamicCast(type)) { - fprintf(cpp, "ModelPartForDictionary "); + fprintf(cpp, "ModelPartForDictionary"); } } std::string - Slicer::modulePath() + Slicer::modulePath() const { std::string path; BOOST_FOREACH (const auto & m, modules) { diff --git a/slicer/slicer/parser.h b/slicer/slicer/parser.h index 90aa05a..816738d 100644 --- a/slicer/slicer/parser.h +++ b/slicer/slicer/parser.h @@ -34,12 +34,15 @@ namespace Slicer { private: void createNewModelPartPtrFor(const Slice::TypePtr & type) const; - std::string modulePath(); + void visitComplexDataMembers(Slice::TypePtr t, const Slice::DataMemberList &) const; + + std::string modulePath() const; static boost::optional<std::string> metaDataValue(const std::string & prefix, const std::list<std::string> & metadata); FILE * cpp; std::vector<Slice::ModulePtr> modules; + unsigned int classNo; }; } diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index 88c981f..ebc6c25 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -26,6 +26,7 @@ lib common : : : <library>boost_filesystem <library>boost_system + <include>../../libmisc ; unit-test do-slicer : diff --git a/slicer/test/initial/builtins.xml b/slicer/test/initial/builtins.xml index 650d187..d77126e 100644 --- a/slicer/test/initial/builtins.xml +++ b/slicer/test/initial/builtins.xml @@ -1,11 +1,11 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <BuiltIns> <mbool>true</mbool> <mbyte>4</mbyte> - <mdouble>3.14159265359</mdouble> - <mfloat>3.14</mfloat> + <mshort>40</mshort> <mint>80</mint> <mlong>800</mlong> - <mshort>40</mshort> + <mfloat>3.125</mfloat> + <mdouble>3.0625</mdouble> <mstring>Sample text</mstring> </BuiltIns> diff --git a/slicer/test/initial/optionals-areset.xml b/slicer/test/initial/optionals-areset.xml index e4cdf42..aa2a97a 100644 --- a/slicer/test/initial/optionals-areset.xml +++ b/slicer/test/initial/optionals-areset.xml @@ -1,14 +1,14 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <Optionals> <optSimple>4</optSimple> - <optClass> - <a>1</a> - <b>2</b> - </optClass> <optStruct> <a>1</a> <b>2</b> </optStruct> + <optClass> + <a>1</a> + <b>2</b> + </optClass> <optSeq> <element> <a>3</a> @@ -19,20 +19,20 @@ <b>6</b> </element> </optSeq> - <optDict> - <element> - <key>10</key> - <value> - <a>11</a> - <b>12</b> - </value> - </element> - <element> - <key>13</key> - <value> - <a>14</a> - <b>15</b> - </value> - </element> - </optDict> + <optDict> + <element> + <key>10</key> + <value> + <a>11</a> + <b>12</b> + </value> + </element> + <element> + <key>13</key> + <value> + <a>14</a> + <b>15</b> + </value> + </element> + </optDict> </Optionals> diff --git a/slicer/test/initial/optionals-notset.xml b/slicer/test/initial/optionals-notset.xml index 8fbb701..8c679d1 100644 --- a/slicer/test/initial/optionals-notset.xml +++ b/slicer/test/initial/optionals-notset.xml @@ -1,3 +1,2 @@ -<?xml version="1.0"?> -<Optionals> -</Optionals> +<?xml version="1.0" encoding="UTF-8"?> +<Optionals/> diff --git a/slicer/test/run-slicer.cpp b/slicer/test/run-slicer.cpp index 897d9ee..35db875 100644 --- a/slicer/test/run-slicer.cpp +++ b/slicer/test/run-slicer.cpp @@ -7,6 +7,8 @@ #include <boost/function.hpp> #include <boost/assert.hpp> #include <types.h> +#include <misc.h> +#include "helpers.h" namespace fs = boost::filesystem; @@ -26,6 +28,8 @@ verify(const fs::path & root, const fs::path & tmp, const fs::path & infile, con fprintf(stderr, "%s : Check2\n", input.string().c_str()); if (check) check(*p); fprintf(stderr, "%s : OK\n", input.string().c_str()); + + system(stringbf("diff -w %s %s", input, output)); } void @@ -85,6 +89,8 @@ main(int, char ** argv) verify<TestModule::BuiltIns, Slicer::Xml>(root, tmp, "builtins.xml"); verify<TestModule::Optionals, Slicer::Xml>(root, tmp, "optionals-notset.xml", checkOptionals_notset); verify<TestModule::Optionals, Slicer::Xml>(root, tmp, "optionals-areset.xml", checkOptionals_areset); + verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-a.xml"); + verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-b.xml"); return 0; } diff --git a/slicer/test/types.ice b/slicer/test/types.ice index 46f834f..bdcd4be 100644 --- a/slicer/test/types.ice +++ b/slicer/test/types.ice @@ -38,4 +38,23 @@ module TestModule { StructType str; int simp; }; + class Base { + int a; + }; + class D1 extends Base { + int b; + }; + class D2 extends Base { + int c; + }; + class D3 extends D2 { + int d; + }; + sequence<Base> BaseSeq; + dictionary<int, Base> BaseMap; + class InheritanceCont { + Base b; + BaseSeq bs; + BaseMap bm; + }; }; diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp index 1ff6058..b08e274 100644 --- a/slicer/xml/serializer.cpp +++ b/slicer/xml/serializer.cpp @@ -167,6 +167,10 @@ namespace Slicer { if (auto element = dynamic_cast<const xmlpp::Element *>(node)) { auto smp = mp->GetChild(element->get_name()); if (smp) { + auto typeAttr = element->get_attribute("slicer-typeid"); + if (typeAttr) { + smp = smp->GetSubclassModelPart(typeAttr->get_value()); + } smp->Create(); auto attrs(element->get_attributes()); if (!attrs.empty()) { @@ -208,6 +212,11 @@ namespace Slicer { } else if (mp) { auto element = n->add_child(name); + auto typeId = mp->GetTypeId(); + if (typeId) { + element->set_attribute("slicer-typeid", *typeId); + mp = mp->GetSubclassModelPart(*typeId); + } mp->GetValue(new XmlContentValueTarget(element)); mp->OnEachChild(boost::bind(&Xml::ModelTreeIterate, element, _1, _2)); } |