From a15335691527bec1cdf55121ad4e28480cac1343 Mon Sep 17 00:00:00 2001 From: randomdan Date: Thu, 29 May 2014 13:01:20 +0000 Subject: First hash of slicer, works well for the golden path, beyond that is uncharted territory --- slicer/Jamfile.jam | 9 ++ slicer/slicer/Jamfile.jam | 17 +++ slicer/slicer/modelParts.cpp | 21 ++++ slicer/slicer/modelParts.h | 292 +++++++++++++++++++++++++++++++++++++++++++ slicer/slicer/parser.cpp | 268 +++++++++++++++++++++++++++++++++++++++ slicer/slicer/parser.h | 47 +++++++ slicer/slicer/serializer.h | 19 +++ slicer/slicer/slicer.h | 31 +++++ slicer/test/Jamfile.jam | 3 + slicer/test/do-slicer.cpp | 13 ++ slicer/test/types.ice | 38 ++++++ slicer/tool/Jamfile.jam | 5 + slicer/tool/slicer.cpp | 17 +++ slicer/xml/Jamfile.jam | 16 +++ slicer/xml/serializer.cpp | 239 +++++++++++++++++++++++++++++++++++ slicer/xml/serializer.h | 29 +++++ 16 files changed, 1064 insertions(+) create mode 100644 slicer/Jamfile.jam create mode 100644 slicer/slicer/Jamfile.jam create mode 100644 slicer/slicer/modelParts.cpp create mode 100644 slicer/slicer/modelParts.h create mode 100644 slicer/slicer/parser.cpp create mode 100644 slicer/slicer/parser.h create mode 100644 slicer/slicer/serializer.h create mode 100644 slicer/slicer/slicer.h create mode 100644 slicer/test/Jamfile.jam create mode 100644 slicer/test/do-slicer.cpp create mode 100644 slicer/test/types.ice create mode 100644 slicer/tool/Jamfile.jam create mode 100644 slicer/tool/slicer.cpp create mode 100644 slicer/xml/Jamfile.jam create mode 100644 slicer/xml/serializer.cpp create mode 100644 slicer/xml/serializer.h diff --git a/slicer/Jamfile.jam b/slicer/Jamfile.jam new file mode 100644 index 0000000..b6de7a4 --- /dev/null +++ b/slicer/Jamfile.jam @@ -0,0 +1,9 @@ +import package ; + +build-project tool ; +build-project slicer ; +build-project xml ; +build-project test ; + +package.install install : . : tool//slicer : slicer//slicer : [ glob slicer/*.h ] ; +package.install install-xml : . : : xml//slicer-xml : [ glob xml/*.h ] ; diff --git a/slicer/slicer/Jamfile.jam b/slicer/slicer/Jamfile.jam new file mode 100644 index 0000000..96bd9a9 --- /dev/null +++ b/slicer/slicer/Jamfile.jam @@ -0,0 +1,17 @@ +lib Slice ; +lib IceUtil ; +lib boost_system ; +lib boost_filesystem ; + +lib slicer : + [ glob *.cpp ] + : + Slice + IceUtil + boost_system + boost_filesystem + : : + .. + boost_system + boost_filesystem + ; diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp new file mode 100644 index 0000000..9d33d51 --- /dev/null +++ b/slicer/slicer/modelParts.cpp @@ -0,0 +1,21 @@ +#include "modelParts.h" + +namespace Slicer { + void + ModelPart::Create() + { + } + void + ModelPart::Complete() + { + } + void + ModelPart::SetValue(ValueSourcePtr) + { + } + void + ModelPart::GetValue(ValueTargetPtr) + { + } +} + diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h new file mode 100644 index 0000000..6dc450e --- /dev/null +++ b/slicer/slicer/modelParts.h @@ -0,0 +1,292 @@ +#ifndef SLICER_MODELPARTS_H +#define SLICER_MODELPARTS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Slicer { + class IncorrectElementName : public std::invalid_argument { + public: + IncorrectElementName() : + std::invalid_argument("") { } + }; + + class ValueTarget : public IceUtil::Shared { + public: + virtual void get(const bool &) const = 0; + virtual void get(const Ice::Byte &) const = 0; + virtual void set(const Ice::Short &) const = 0; + virtual void get(const Ice::Int &) const = 0; + virtual void get(const Ice::Long &) const = 0; + virtual void get(const Ice::Float &) const = 0; + virtual void get(const Ice::Double &) const = 0; + virtual void get(const std::string &) const = 0; + }; + typedef IceUtil::Handle ValueTargetPtr; + + class ValueSource : public IceUtil::Shared { + public: + virtual void set(bool &) const = 0; + virtual void set(Ice::Byte &) const = 0; + virtual void set(Ice::Short &) const = 0; + virtual void set(Ice::Int &) const = 0; + virtual void set(Ice::Long &) const = 0; + virtual void set(Ice::Float &) const = 0; + virtual void set(Ice::Double &) const = 0; + virtual void set(std::string &) const = 0; + }; + typedef IceUtil::Handle ValueSourcePtr; + + class ModelPart; + + typedef IceUtil::Handle ModelPartPtr; + typedef std::map ModelParts; + + typedef boost::function ChildHandler; + + class ModelPart : public IceUtil::Shared { + public: + virtual ~ModelPart() = default; + + virtual void OnEachChild(const ChildHandler &) = 0; + virtual ModelPartPtr GetChild(const std::string &) = 0; + virtual void Create(); + virtual void Complete(); + virtual void SetValue(ValueSourcePtr); + virtual void GetValue(ValueTargetPtr); + }; + + template + class ModelPartForSimple : public ModelPart { + public: + ModelPartForSimple(T & h) : + Member(h) + { + } + ModelPartForSimple(T * h) : + Member(*h) + { + } + virtual void OnEachChild(const ChildHandler &) { } + virtual ModelPartPtr GetChild(const std::string &) override { return NULL; } + virtual void SetValue(ValueSourcePtr s) override { s->set(Member); } + virtual void GetValue(ValueTargetPtr s) override { s->get(Member); } + + private: + T & Member; + }; + + template + class ModelPartForComplex : public ModelPart { + public: + class HookBase : public IceUtil::Shared { + public: + virtual ModelPartPtr Get(T & t) const = 0; + }; + typedef IceUtil::Handle HookPtr; + + template + class Hook : public HookBase { + public: + ModelPartPtr Get(T & t) const override + { + return new MP(t.*M); + } + }; + + virtual void OnEachChild(const ChildHandler & ch) + { + for (auto h = hooks.begin(); h != hooks.end(); h++) { + ch(h->first, h->second->Get(GetModel())); + } + } + + ModelPartPtr GetChild(const std::string & name) override + { + auto childitr = hooks.find(name); + if (childitr != hooks.end()) { + return childitr->second->Get(GetModel()); + } + return NULL; + } + + virtual T & GetModel() = 0; + + typedef std::map Hooks; + + private: + static Hooks hooks; + }; + + template + class ModelPartForClass : public ModelPartForComplex { + public: + ModelPartForClass(IceInternal::Handle & h) : + ModelObject(h) + { + } + + virtual void Create() override + { + ModelObject = new T(); + } + + T & GetModel() override + { + return *ModelObject; + } + + private: + IceInternal::Handle & ModelObject; + }; + + template + class ModelPartForStruct : public ModelPartForComplex { + public: + ModelPartForStruct(T & o) : + ModelObject(o) + { + } + + T & GetModel() override + { + return ModelObject; + } + + private: + T & ModelObject; + }; + + template + class ModelPartForClassRoot : public ModelPartForClass { + public: + ModelPartForClassRoot() : + ModelPartForClass(ModelObject) + { + } + + ModelPartForClassRoot(IceInternal::Handle o) : + ModelPartForClass(ModelObject) + { + ModelObject = o; + } + + virtual ModelPartPtr GetChild(const std::string & name) override + { + if (!name.empty() && name != rootName) { + throw IncorrectElementName(); + } + ModelPartForClass::Create(); + return new ModelPartForClass(ModelObject); + } + + virtual void OnEachChild(const ChildHandler & ch) override + { + ch(rootName, new ModelPartForClass(ModelObject)); + } + + T & GetModel() override + { + return *ModelObject; + } + + private: + IceInternal::Handle ModelObject; + static std::string rootName; + }; + + template + class ModelPartForSequence : public ModelPart { + public: + ModelPartForSequence(T & s) : + sequence(s) + { + } + virtual void OnEachChild(const ChildHandler & ch) override + { + BOOST_FOREACH(auto & element, sequence) { + ch(elementName, elementModelPart(element)); + } + } + + ModelPartPtr GetChild(const std::string &) override; + + private: + ModelPartPtr elementModelPart(typename T::value_type &) const; + + T & sequence; + static std::string elementName; + }; + + template + class ModelPartForDictionaryElement : public ModelPartForComplex > { + public: + ModelPartForDictionaryElement(typename T::key_type * k, typename T::mapped_type * v) : + key(k), + value(v) + { + } + + ModelPartForDictionaryElement & GetModel() override + { + return *this; + } + + typename T::key_type * key; + typename T::mapped_type * value; + }; + + template + class ModelPartForDictionaryElementInserter : public ModelPartForDictionaryElement { + public: + ModelPartForDictionaryElementInserter(T & d) : + ModelPartForDictionaryElement(&key, &value), + dictionary(d) + { + } + + virtual void Complete() override { dictionary.insert(typename T::value_type(key, value)); } + + mutable typename T::key_type key; + mutable typename T::mapped_type value; + + private: + T & dictionary; + }; + + template + class ModelPartForDictionary : public ModelPart { + public: + ModelPartForDictionary(T & d) : + dictionary(d) + { + } + virtual void OnEachChild(const ChildHandler & ch) override + { + BOOST_FOREACH(auto & pair, dictionary) { + ch(pairName, new ModelPartForDictionaryElement(const_cast(&pair.first), &pair.second)); + } + } + ModelPartPtr GetChild(const std::string & name) override + { + if (!name.empty() && name != pairName) { + throw IncorrectElementName(); + } + return new ModelPartForDictionaryElementInserter(dictionary); + } + + + private: + T & dictionary; + static std::string pairName; + }; +} + +#endif + diff --git a/slicer/slicer/parser.cpp b/slicer/slicer/parser.cpp new file mode 100644 index 0000000..a67f483 --- /dev/null +++ b/slicer/slicer/parser.cpp @@ -0,0 +1,268 @@ +#include "parser.h" +#include +#include +#include +#include +#include +#include + +namespace Slicer { + Slicer::Slicer(FILE * c) : + cpp(c) + { + } + + void + Slicer::leadIn() + { + fprintf(cpp, "// Begin Slicer code\n\n"); + fprintf(cpp, "#include \n\n"); + fprintf(cpp, "namespace Slicer {\n"); + } + + void + Slicer::leadOut() + { + fprintf(cpp, "}\n\n"); + fprintf(cpp, "// End Slicer code\n\n"); + } + + bool + Slicer::visitModuleStart(const Slice::ModulePtr & m) + { + fprintf(cpp, "// Begin module %s\n\n", m->name().c_str()); + modules.push_back(m); + return true; + } + + bool + Slicer::visitClassDefStart(const Slice::ClassDefPtr & c) + { + if (c->hasMetaData("slicer:ignore")) { return false; } + + 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{ \"%s\", ", + name ? name->c_str() : dm->name().c_str()); + auto type = dm->type(); + fprintf(cpp, "new ModelPartForClass< %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(type); + fprintf(cpp, " >() },\n"); + } + fprintf(cpp, "\t};\n"); + + fprintf(cpp, "template<>\n"); + auto name = metaDataValue("slicer:root:", c->getMetaData()); + fprintf(cpp, "std::string ModelPartForClassRoot< %s::%s >::rootName(\"%s\");\n\n", + modulePath().c_str(), c->name().c_str(), + name ? name->c_str() : c->name().c_str()); + return true; + } + + bool + Slicer::visitStructStart(const Slice::StructPtr & c) + { + if (c->hasMetaData("slicer:ignore")) { return false; } + + fprintf(cpp, "// Struct %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->dataMembers()) { + auto name = metaDataValue("slicer:name:", dm->getMetaData()); + fprintf(cpp, "\t\t{ \"%s\", ", + name ? name->c_str() : dm->name().c_str()); + 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(type); + fprintf(cpp, " >() },\n"); + } + fprintf(cpp, "\t};\n\n"); + + return true; + } + + void + Slicer::visitSequence(const Slice::SequencePtr & s) + { + if (s->hasMetaData("slicer:ignore")) { return; } + + fprintf(cpp, "// Sequence %s\n", s->name().c_str()); + fprintf(cpp, "template<>\n"); + fprintf(cpp, "ModelPartPtr ModelPartForSequence< %s::%s >::GetChild(const std::string & name)\n{\n", + modulePath().c_str(), s->name().c_str()); + auto iname = metaDataValue("slicer:item:", s->getMetaData()); + if (iname) { + fprintf(cpp, "\tif (!name.empty() && name != \"%s\") { throw IncorrectElementName(); }\n", + iname->c_str()); + } + else { + fprintf(cpp, "\t(void)name;\n"); + } + fprintf(cpp, "\tsequence.push_back(%s());\n", + Slice::typeToString(s->type()).c_str()); + fprintf(cpp, "\treturn new "); + createNewModelPartPtrFor(s->type()); + fprintf(cpp, "(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", + modulePath().c_str(), s->name().c_str(), + modulePath().c_str(), s->name().c_str()); + auto etype = s->type(); + fprintf(cpp, "\treturn new "); + createNewModelPartPtrFor(etype); + fprintf(cpp, "(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", + modulePath().c_str(), s->name().c_str(), + ename ? ename->c_str() : "element"); + } + + void + Slicer::visitDictionary(const Slice::DictionaryPtr & d) + { + if (d->hasMetaData("slicer:ignore")) { return; } + + fprintf(cpp, "// Dictionary %s\n", d->name().c_str()); + auto iname = metaDataValue("slicer:item:", d->getMetaData()); + fprintf(cpp, "template<>\n"); + fprintf(cpp, "std::string ModelPartForDictionary< %s::%s >::pairName(\"%s\");\n\n", + modulePath().c_str(), d->name().c_str(), + iname ? iname->c_str() : "element"); + + fprintf(cpp, "template<>\n"); + fprintf(cpp, "ModelPartForComplex< ModelPartForDictionaryElement< %s::%s > >::Hooks ", + modulePath().c_str(), d->name().c_str()); + fprintf(cpp, "ModelPartForComplex< ModelPartForDictionaryElement< %s::%s > >::hooks {\n", + 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{ \"%s\", ", + kname ? kname->c_str() : "key"); + auto ktype = d->keyType(); + fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::key, ", + modulePath().c_str(), d->name().c_str(), + Slice::typeToString(ktype).c_str(), + modulePath().c_str(), d->name().c_str()); + createNewModelPartPtrFor(ktype); + fprintf(cpp, " >() },\n\t\t{ \"%s\", ", + vname ? vname->c_str() : "value"); + auto vtype = d->valueType(); + fprintf(cpp, "new ModelPartForDictionaryElement< %s::%s >::Hook< %s*, &ModelPartForDictionaryElement< %s::%s >::value, ", + modulePath().c_str(), d->name().c_str(), + Slice::typeToString(vtype).c_str(), + modulePath().c_str(), d->name().c_str()); + createNewModelPartPtrFor(vtype); + fprintf(cpp, " >() },\n"); + fprintf(cpp, "\t};\n"); + fprintf(cpp, "\n"); + } + + void + Slicer::visitModuleEnd(const Slice::ModulePtr & m) + { + fprintf(cpp, "// End module %s\n\n", m->name().c_str()); + modules.pop_back(); + } + + void + Slicer::createNewModelPartPtrFor(const Slice::TypePtr & type) const + { + if (auto builtin = Slice::BuiltinPtr::dynamicCast(type)) { + fprintf(cpp, "ModelPartForSimple< %s >", + Slice::typeToString(type).c_str()); + } + else if (auto complexClass = Slice::ClassDeclPtr::dynamicCast(type)) { + fprintf(cpp, "ModelPartForClass< %s::element_type >", + Slice::typeToString(type).c_str()); + } + else if (auto complexStruct = Slice::StructPtr::dynamicCast(type)) { + fprintf(cpp, "ModelPartForStruct< %s >", + Slice::typeToString(type).c_str()); + } + else if (auto sequence = Slice::SequencePtr::dynamicCast(type)) { + fprintf(cpp, "ModelPartForSequence< %s >", + Slice::typeToString(type).c_str()); + } + else if (auto dictionary = Slice::DictionaryPtr::dynamicCast(type)) { + fprintf(cpp, "ModelPartForDictionary< %s >", + Slice::typeToString(type).c_str()); + } + } + + std::string + Slicer::modulePath() + { + std::string path; + BOOST_FOREACH (const auto & m, modules) { + path += "::"; + path += m->name(); + } + return path; + } + + boost::optional + Slicer::metaDataValue(const std::string & prefix, const std::list & metadata) + { + BOOST_FOREACH (const auto & md, metadata) { + if (boost::algorithm::starts_with(md, prefix)) { + return md.substr(prefix.length()); + } + } + return boost::optional(); + } + + void + Slicer::Apply(const boost::filesystem::path & ice, const boost::filesystem::path & cpp) + { + std::vector cppArgs; + Slice::PreprocessorPtr icecpp = Slice::Preprocessor::create("slicer", ice.string(), cppArgs); + FILE * cppHandle = icecpp->preprocess(false); + + if (cppHandle == NULL) { + throw std::runtime_error("preprocess failed"); + } + + Slice::UnitPtr u = Slice::Unit::createUnit(false, false, false, false); + + int parseStatus = u->parse(ice.string(), cppHandle, false); + + if (!icecpp->close()) { + throw std::runtime_error("preprocess close failed"); + } + + if (parseStatus == EXIT_FAILURE) { + throw std::runtime_error("unit parse failed"); + } + + FilePtr cppfile(fopen(cpp.string().c_str(), "a"), fclose); + if (!cppfile) { + throw std::runtime_error("failed to open code file"); + } + + Slicer s(cppfile.get()); + s.leadIn(); + u->visit(&s, false); + s.leadOut(); + + u->destroy(); + } +}; + diff --git a/slicer/slicer/parser.h b/slicer/slicer/parser.h new file mode 100644 index 0000000..c660cc6 --- /dev/null +++ b/slicer/slicer/parser.h @@ -0,0 +1,47 @@ +#ifndef SLICER_PARSER_H +#define SLICER_PARSER_H + +#include +#include +#include + +namespace Slicer { + typedef boost::shared_ptr FilePtr; + + class Slicer : public Slice::ParserVisitor { + public: + Slicer(FILE * c); + + static void Apply(const boost::filesystem::path & ice, const boost::filesystem::path & cpp); + + void leadIn(); + + void leadOut(); + + virtual bool visitModuleStart(const Slice::ModulePtr & m) override; + + virtual bool visitClassDefStart(const Slice::ClassDefPtr & c) override; + + virtual bool visitStructStart(const Slice::StructPtr&) override; + + void visitSequence(const Slice::SequencePtr & s) override; + + void visitDictionary(const Slice::DictionaryPtr & d) override; + + virtual void visitModuleEnd(const Slice::ModulePtr & m) override; + + + private: + void createNewModelPartPtrFor(const Slice::TypePtr & type) const; + + std::string modulePath(); + + static boost::optional metaDataValue(const std::string & prefix, const std::list & metadata); + + FILE * cpp; + std::vector modules; + }; +} + +#endif + diff --git a/slicer/slicer/serializer.h b/slicer/slicer/serializer.h new file mode 100644 index 0000000..dffa0f6 --- /dev/null +++ b/slicer/slicer/serializer.h @@ -0,0 +1,19 @@ +#ifndef SLICER_SERIALIZER_H +#define SLICER_SERIALIZER_H + +#include +#include +#include +#include + +namespace Slicer { + class Serializer : public IceUtil::Shared { + public: + virtual void Deserialize(const boost::filesystem::path &, ModelPartPtr) = 0; + virtual void Serialize(const boost::filesystem::path &, ModelPartPtr) = 0; + }; + typedef IceUtil::Handle SerializerPtr; +} + +#endif + diff --git a/slicer/slicer/slicer.h b/slicer/slicer/slicer.h new file mode 100644 index 0000000..8421774 --- /dev/null +++ b/slicer/slicer/slicer.h @@ -0,0 +1,31 @@ +#ifndef SLICER_H +#define SLICER_H + +#include +#include +#include +#include + +namespace Slicer { + template + IceInternal::Handle + Deserialize(const boost::filesystem::path & path) + { + IceUtil::Handle> root = new ModelPartForClassRoot(); + SerializerPtr serializer = new Serializer(); + serializer->Deserialize(path, root); + return &root->GetModel(); + } + + template + void + Serialize(IceInternal::Handle object, const boost::filesystem::path & path) + { + IceUtil::Handle> root = new ModelPartForClassRoot(object); + SerializerPtr serializer = new Serializer(); + serializer->Serialize(path, root); + } +} + +#endif + diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam new file mode 100644 index 0000000..b4e05b3 --- /dev/null +++ b/slicer/test/Jamfile.jam @@ -0,0 +1,3 @@ +import testing ; + +run do-slicer.cpp ../slicer//slicer : : types.ice ; diff --git a/slicer/test/do-slicer.cpp b/slicer/test/do-slicer.cpp new file mode 100644 index 0000000..8b03a7d --- /dev/null +++ b/slicer/test/do-slicer.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int +main(int, char ** argv) +{ + const boost::filesystem::path slice = argv[1]; + Slicer::Slicer::Apply(slice, "/dev/null"); + + return 0; +} + diff --git a/slicer/test/types.ice b/slicer/test/types.ice new file mode 100644 index 0000000..fdacb2d --- /dev/null +++ b/slicer/test/types.ice @@ -0,0 +1,38 @@ +module TestModule { + class BuiltIns { + bool mbool; + byte mbyte; + short mshort; + int mint; + long mlong; + float mfloat; + double mdouble; + string mstring; + }; + class ClassType { + int a; + int b; + }; + struct StructType { + int a; + int b; + }; + class Optionals { + optional(1) int simple; + optional(2) StructType str; + }; + sequence Classes; + sequence Structs; + dictionary ClassMap; + dictionary StructMap; + class ClassClass { + ClassType cls; + StructType str; + int simp; + }; + struct StructStruct { + ClassType cls; + StructType str; + int simp; + }; +}; diff --git a/slicer/tool/Jamfile.jam b/slicer/tool/Jamfile.jam new file mode 100644 index 0000000..de50043 --- /dev/null +++ b/slicer/tool/Jamfile.jam @@ -0,0 +1,5 @@ +exe slicer : + [ glob *.cpp ] + : + ../slicer//slicer + ; diff --git a/slicer/tool/slicer.cpp b/slicer/tool/slicer.cpp new file mode 100644 index 0000000..ce58c57 --- /dev/null +++ b/slicer/tool/slicer.cpp @@ -0,0 +1,17 @@ +#include + +int +main(int argc, char ** argv) +{ + if (argc < 3) { + fprintf(stderr, "slicer \n"); + return 1; + } + + const boost::filesystem::path slice = argv[1]; + const boost::filesystem::path cpp = argv[2]; + + Slicer::Slicer::Apply(slice, cpp); + + return 0; +} diff --git a/slicer/xml/Jamfile.jam b/slicer/xml/Jamfile.jam new file mode 100644 index 0000000..97f013c --- /dev/null +++ b/slicer/xml/Jamfile.jam @@ -0,0 +1,16 @@ +alias libxmlpp : : : : + "`pkg-config --cflags libxml++-2.6`" + "`pkg-config --libs libxml++-2.6`" ; +lib boost_system ; +lib boost_filesystem ; +lib IceUtil ; + +lib slicer-xml : + [ glob *.cpp ] + : + .. + boost_system + boost_filesystem + IceUtil + libxmlpp + ; diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp new file mode 100644 index 0000000..0a065d8 --- /dev/null +++ b/slicer/xml/serializer.cpp @@ -0,0 +1,239 @@ +#include "serializer.h" +#include +#include +#include +#include +#include +#include + +namespace Slicer { + class BadBooleanValue : public std::invalid_argument { + public: + BadBooleanValue(const Glib::ustring &) : + std::invalid_argument("Bad boolean value") + { + } + }; + + static const Glib::ustring TrueText("true"); + static const Glib::ustring FalseText("false"); + + class XmlValueSource : public ValueSource { + public: + XmlValueSource(const Glib::ustring & s) : + value(s) + { + } + + void set(bool & v) const override + { + if (value == TrueText) { v = true; return; } + if (value == FalseText) { v = false; return; } + throw BadBooleanValue(value); + } + + void set(Ice::Byte & v) const override + { + v = boost::lexical_cast(value); + } + + void set(Ice::Short & v) const override + { + v = boost::lexical_cast(value); + } + + void set(Ice::Int & v) const override + { + v = boost::lexical_cast(value); + } + + void set(Ice::Long & v) const override + { + v = boost::lexical_cast(value); + } + + void set(Ice::Float & v) const override + { + v = boost::lexical_cast(value); + } + + void set(Ice::Double & v) const override + { + v = boost::lexical_cast(value); + } + + void set(std::string & v) const override + { + v = value.raw(); + } + + protected: + const Glib::ustring value; + }; + + class XmlContentValueSource : public XmlValueSource { + public: + XmlContentValueSource(const xmlpp::ContentNode * c) : + XmlValueSource(c->get_content()) + { + } + }; + + class XmlAttributeValueSource : public XmlValueSource { + public: + XmlAttributeValueSource(const xmlpp::Attribute * a) : + XmlValueSource(a->get_value()) + { + } + }; + + class XmlValueTarget : public ValueTarget { + public: + XmlValueTarget(boost::function a) : + apply(a) + { + } + + virtual void get(const bool & value) const + { + if (value) { + apply(TrueText); + } + else { + apply(FalseText); + } + } + + virtual void get(const Ice::Byte & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void set(const Ice::Short & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void get(const Ice::Int & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void get(const Ice::Long & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void get(const Ice::Float & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void get(const Ice::Double & value) const + { + apply(boost::lexical_cast(value)); + } + + virtual void get(const std::string & value) const + { + apply(value); + } + + private: + const boost::function apply; + }; + + + class XmlAttributeValueTarget : public XmlValueTarget { + public: + XmlAttributeValueTarget(xmlpp::Element * p, const std::string & n) : + XmlValueTarget(boost::bind(&xmlpp::Element::set_attribute, p, Glib::ustring(n), _1, Glib::ustring())) + { + } + }; + + class XmlContentValueTarget : public XmlValueTarget { + public: + XmlContentValueTarget(xmlpp::Element * p) : + XmlValueTarget(boost::bind(&xmlpp::Element::set_child_text, p, _1)) + { + } + }; + + void + Xml::DocumentTreeIterate(const xmlpp::Node * node, ModelPartPtr mp) + { + while (node) { + if (auto element = dynamic_cast(node)) { + auto smp = mp->GetChild(element->get_name()); + if (smp) { + smp->Create(); + auto attrs(element->get_attributes()); + if (!attrs.empty()) { + DocumentTreeIterate(attrs.front(), smp); + } + DocumentTreeIterate(element->get_first_child(), smp); + smp->Complete(); + } + } + else if (auto attribute = dynamic_cast(node)) { + auto smp = mp->GetChild("@" + attribute->get_name()); + if (smp) { + smp->Create(); + smp->SetValue(new XmlAttributeValueSource(attribute)); + smp->Complete(); + } + } + else if (auto content = dynamic_cast(node)) { + mp->SetValue(new XmlContentValueSource(content)); + } + node = node->get_next_sibling(); + } + } + + void + Xml::DocumentTreeIterate(const xmlpp::Document * doc, ModelPartPtr mp) + { + DocumentTreeIterate(doc->get_root_node(), mp); + } + + void + Xml::ModelTreeIterate(xmlpp::Element * n, const std::string & name, ModelPartPtr mp) + { + if (name.empty()) { + return; + } + if (name[0] == '@') { + mp->GetValue(new XmlAttributeValueTarget(n, name.substr(1))); + } + else { + auto element = n->add_child(name); + mp->GetValue(new XmlContentValueTarget(element)); + mp->OnEachChild(boost::bind(&Xml::ModelTreeIterate, element, _1, _2)); + } + } + + void + Xml::ModelTreeIterateRoot(xmlpp::Document * doc, const std::string & name, ModelPartPtr mp) + { + auto root = doc->create_root_node(name); + mp->OnEachChild(boost::bind(&Xml::ModelTreeIterate, root, _1, _2)); + } + + void + Xml::Deserialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) + { + xmlpp::DomParser dom(path.string()); + auto doc = dom.get_document(); + DocumentTreeIterate(doc, modelRoot); + } + + void + Xml::Serialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) + { + xmlpp::Document doc; + modelRoot->OnEachChild(boost::bind(&Xml::ModelTreeIterateRoot, &doc, _1, _2)); + doc.write_to_file_formatted(path.string()); + } +} + diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h new file mode 100644 index 0000000..8e8a023 --- /dev/null +++ b/slicer/xml/serializer.h @@ -0,0 +1,29 @@ +#ifndef SLICER_XML_H +#define SLICER_XML_H + +#include + +namespace xmlpp { + class Document; + class Node; + class Element; + class Attribute; + class ContentNode; +} + +namespace Slicer { + class Xml : public Serializer { + public: + virtual void Deserialize(const boost::filesystem::path &, ModelPartPtr) override; + virtual void Serialize(const boost::filesystem::path &, ModelPartPtr) override; + + protected: + static void DocumentTreeIterate(const xmlpp::Node * node, ModelPartPtr mp); + static void DocumentTreeIterate(const xmlpp::Document * doc, ModelPartPtr mp); + static void ModelTreeIterate(xmlpp::Element *, const std::string &, ModelPartPtr mp); + static void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, ModelPartPtr mp); + }; +} + +#endif + -- cgit v1.2.3