From a768408493618bfa69881eb0f4faedd5f0b9e458 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 28 Oct 2017 16:31:07 +0200 Subject: [PATCH] Refactor JsonSerializationCodeGenerator * JSONSerializationCodeGenerator -> JsonSerializationCodeGenerator * Move to separate file --- generator/CMakeLists.txt | 2 + generator/codegenerator.cpp | 113 ----------------- generator/codegenerator.h | 36 ------ generator/jsonserializationcodegenerator.cpp | 121 +++++++++++++++++++ generator/jsonserializationcodegenerator.h | 45 +++++++ generator/main.cpp | 5 +- generator/tests/jsongenerator.cpp | 3 +- 7 files changed, 173 insertions(+), 152 deletions(-) create mode 100644 generator/jsonserializationcodegenerator.cpp create mode 100644 generator/jsonserializationcodegenerator.h diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 6d0161e..29ee26a 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -8,6 +8,7 @@ set(LINK_TESTS_AGAINST_APP_TARGET ON) # add project files set(HEADER_FILES codegenerator.h + jsonserializationcodegenerator.h codefactory.h frontendaction.h consumer.h @@ -16,6 +17,7 @@ set(HEADER_FILES ) set(SRC_FILES codegenerator.cpp + jsonserializationcodegenerator.cpp codefactory.cpp frontendaction.cpp consumer.cpp diff --git a/generator/codegenerator.cpp b/generator/codegenerator.cpp index 54665b0..808d470 100644 --- a/generator/codegenerator.cpp +++ b/generator/codegenerator.cpp @@ -1,27 +1,13 @@ #include "./codegenerator.h" -#include "../lib/json/serializable.h" - #include #include -#include -#include - using namespace std; namespace ReflectiveRapidJSON { -/*! - * \brief Prints an LLVM string reference without instantiating a std::string first. - */ -ostream &operator<<(ostream &os, llvm::StringRef str) -{ - os.write(str.data(), static_cast(str.size())); - return os; -} - CodeGenerator::~CodeGenerator() { } @@ -49,103 +35,4 @@ bool CodeGenerator::inheritsFromInstantiationOf(clang::CXXRecordDecl *const reco return false; } -void JSONSerializationCodeGenerator::addDeclaration(clang::Decl *decl) -{ - switch (decl->getKind()) { - case clang::Decl::Kind::CXXRecord: { - auto *const record = static_cast(decl); - // skip forward declarations - if (!record->hasDefinition()) { - return; - } - // add classes derived from any instantiation of "ReflectiveRapidJSON::JsonSerializable" - if (inheritsFromInstantiationOf(record, JsonSerializable::qualifiedName)) { - m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record); - } - break; - } - case clang::Decl::Kind::Enum: - // TODO: add enums - break; - default:; - } -} - -void JSONSerializationCodeGenerator::generate(ostream &os) const -{ - if (m_relevantClasses.empty()) { - return; - } - - // put everything into namespace ReflectiveRapidJSON::Reflector - os << "namespace ReflectiveRapidJSON {\n" - "namespace Reflector {\n\n"; - - // add push and pull functions for each class, for an example of the resulting - // output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...") - for (const RelevantClass &relevantClass : m_relevantClasses) { - // write comment - os << "// define code for (de)serializing " << relevantClass.qualifiedName << " objects\n"; - - // find relevant base classes - const vector relevantBases = findRelevantBaseClasses(relevantClass); - - // print push method - os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const ::" << relevantClass.qualifiedName - << " &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)\n{\n" - " // push base classes\n"; - for (const RelevantClass *baseClass : relevantBases) { - os << " push(static_castqualifiedName << " &>(reflectable), value, allocator);\n"; - } - os << " // push members\n"; - for (const clang::FieldDecl *field : relevantClass.record->fields()) { - os << " push(reflectable." << field->getName() << ", \"" << field->getName() << "\", value, allocator);\n"; - } - os << "}\n"; - - // print pull method - os << "template <> inline void pull<::" << relevantClass.qualifiedName << ">(::" << relevantClass.qualifiedName - << " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, " - "JsonDeserializationErrors " - "*errors)\n{\n" - " // pull base classes\n"; - for (const RelevantClass *baseClass : relevantBases) { - os << " pull(static_cast<::" << baseClass->qualifiedName << " &>(reflectable), value, errors);\n"; - } - os << " // set error context for current record\n" - " const char *previousRecord;\n" - " if (errors) {\n" - " previousRecord = errors->currentRecord;\n" - " errors->currentRecord = \"" - << relevantClass.qualifiedName - << "\";\n" - " }\n" - " // pull members\n"; - for (const clang::FieldDecl *field : relevantClass.record->fields()) { - os << " pull(reflectable." << field->getName() << ", \"" << field->getName() << "\", value, errors);\n"; - } - os << " // restore error context for previous record\n" - " if (errors) {\n" - " errors->currentRecord = previousRecord;\n" - " }\n"; - os << "}\n\n"; - } - - // close namespace ReflectiveRapidJSON::Reflector - os << "} // namespace Reflector\n" - "} // namespace ReflectiveRapidJSON\n"; -} - -std::vector JSONSerializationCodeGenerator::findRelevantBaseClasses( - const RelevantClass &relevantClass) const -{ - vector relevantBaseClasses; - for (const RelevantClass &otherClass : m_relevantClasses) { - if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) { - relevantBaseClasses.push_back(&otherClass); - } - } - return relevantBaseClasses; -} - } // namespace ReflectiveRapidJSON diff --git a/generator/codegenerator.h b/generator/codegenerator.h index ad06131..28686aa 100644 --- a/generator/codegenerator.h +++ b/generator/codegenerator.h @@ -7,7 +7,6 @@ namespace clang { class Decl; -class NamedDecl; class CXXRecordDecl; } // namespace clang @@ -46,41 +45,6 @@ inline CodeFactory &CodeGenerator::factory() const return m_factory; } -/*! - * \brief The JSONSerializationCodeGenerator class generates code for JSON (de)serialization - * of objects inheriting from an instantiation of JsonSerializable. - */ -class JSONSerializationCodeGenerator : public CodeGenerator { -public: - JSONSerializationCodeGenerator(CodeFactory &factory); - - void addDeclaration(clang::Decl *decl) override; - void generate(std::ostream &os) const override; - -private: - struct RelevantClass { - explicit RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record); - - std::string qualifiedName; - clang::CXXRecordDecl *record; - }; - - std::vector findRelevantBaseClasses(const RelevantClass &relevantClass) const; - - std::vector m_relevantClasses; -}; - -inline JSONSerializationCodeGenerator::JSONSerializationCodeGenerator(CodeFactory &factory) - : CodeGenerator(factory) -{ -} - -inline JSONSerializationCodeGenerator::RelevantClass::RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record) - : qualifiedName(qualifiedName) - , record(record) -{ -} - } // namespace ReflectiveRapidJSON #endif // REFLECTIVE_RAPIDJSON_CODE_GENERATOR_H diff --git a/generator/jsonserializationcodegenerator.cpp b/generator/jsonserializationcodegenerator.cpp new file mode 100644 index 0000000..4604902 --- /dev/null +++ b/generator/jsonserializationcodegenerator.cpp @@ -0,0 +1,121 @@ +#include "./jsonserializationcodegenerator.h" + +#include "../lib/json/serializable.h" + +#include + +#include + +using namespace std; + +namespace ReflectiveRapidJSON { + +/*! + * \brief Prints an LLVM string reference without instantiating a std::string first. + */ +ostream &operator<<(ostream &os, llvm::StringRef str) +{ + os.write(str.data(), static_cast(str.size())); + return os; +} + +void JsonSerializationCodeGenerator::addDeclaration(clang::Decl *decl) +{ + switch (decl->getKind()) { + case clang::Decl::Kind::CXXRecord: { + auto *const record = static_cast(decl); + // skip forward declarations + if (!record->hasDefinition()) { + return; + } + // add classes derived from any instantiation of "ReflectiveRapidJSON::JsonSerializable" + if (inheritsFromInstantiationOf(record, JsonSerializable::qualifiedName)) { + m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record); + } + break; + } + case clang::Decl::Kind::Enum: + // TODO: add enums + break; + default:; + } +} + +void JsonSerializationCodeGenerator::generate(ostream &os) const +{ + if (m_relevantClasses.empty()) { + return; + } + + // put everything into namespace ReflectiveRapidJSON::Reflector + os << "namespace ReflectiveRapidJSON {\n" + "namespace Reflector {\n\n"; + + // add push and pull functions for each class, for an example of the resulting + // output, see ../lib/tests/jsonserializable.cpp (code under comment "pretend serialization code...") + for (const RelevantClass &relevantClass : m_relevantClasses) { + // write comment + os << "// define code for (de)serializing " << relevantClass.qualifiedName << " objects\n"; + + // find relevant base classes + const vector relevantBases = findRelevantBaseClasses(relevantClass); + + // print push method + os << "template <> inline void push<::" << relevantClass.qualifiedName << ">(const ::" << relevantClass.qualifiedName + << " &reflectable, ::RAPIDJSON_NAMESPACE::Value::Object &value, ::RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)\n{\n" + " // push base classes\n"; + for (const RelevantClass *baseClass : relevantBases) { + os << " push(static_castqualifiedName << " &>(reflectable), value, allocator);\n"; + } + os << " // push members\n"; + for (const clang::FieldDecl *field : relevantClass.record->fields()) { + os << " push(reflectable." << field->getName() << ", \"" << field->getName() << "\", value, allocator);\n"; + } + os << "}\n"; + + // print pull method + os << "template <> inline void pull<::" << relevantClass.qualifiedName << ">(::" << relevantClass.qualifiedName + << " &reflectable, const ::RAPIDJSON_NAMESPACE::GenericValue<::RAPIDJSON_NAMESPACE::UTF8>::ConstObject &value, " + "JsonDeserializationErrors " + "*errors)\n{\n" + " // pull base classes\n"; + for (const RelevantClass *baseClass : relevantBases) { + os << " pull(static_cast<::" << baseClass->qualifiedName << " &>(reflectable), value, errors);\n"; + } + os << " // set error context for current record\n" + " const char *previousRecord;\n" + " if (errors) {\n" + " previousRecord = errors->currentRecord;\n" + " errors->currentRecord = \"" + << relevantClass.qualifiedName + << "\";\n" + " }\n" + " // pull members\n"; + for (const clang::FieldDecl *field : relevantClass.record->fields()) { + os << " pull(reflectable." << field->getName() << ", \"" << field->getName() << "\", value, errors);\n"; + } + os << " // restore error context for previous record\n" + " if (errors) {\n" + " errors->currentRecord = previousRecord;\n" + " }\n"; + os << "}\n\n"; + } + + // close namespace ReflectiveRapidJSON::Reflector + os << "} // namespace Reflector\n" + "} // namespace ReflectiveRapidJSON\n"; +} + +std::vector JsonSerializationCodeGenerator::findRelevantBaseClasses( + const RelevantClass &relevantClass) const +{ + vector relevantBaseClasses; + for (const RelevantClass &otherClass : m_relevantClasses) { + if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) { + relevantBaseClasses.push_back(&otherClass); + } + } + return relevantBaseClasses; +} + +} // namespace ReflectiveRapidJSON diff --git a/generator/jsonserializationcodegenerator.h b/generator/jsonserializationcodegenerator.h new file mode 100644 index 0000000..9a55560 --- /dev/null +++ b/generator/jsonserializationcodegenerator.h @@ -0,0 +1,45 @@ +#ifndef REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H +#define REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H + +#include "./codegenerator.h" + +namespace ReflectiveRapidJSON { + +/*! + * \brief The JSONSerializationCodeGenerator class generates code for JSON (de)serialization + * of objects inheriting from an instantiation of JsonSerializable. + */ +class JsonSerializationCodeGenerator : public CodeGenerator { +public: + JsonSerializationCodeGenerator(CodeFactory &factory); + + void addDeclaration(clang::Decl *decl) override; + void generate(std::ostream &os) const override; + +private: + struct RelevantClass { + explicit RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record); + + std::string qualifiedName; + clang::CXXRecordDecl *record; + }; + + std::vector findRelevantBaseClasses(const RelevantClass &relevantClass) const; + + std::vector m_relevantClasses; +}; + +inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory) + : CodeGenerator(factory) +{ +} + +inline JsonSerializationCodeGenerator::RelevantClass::RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record) + : qualifiedName(qualifiedName) + , record(record) +{ +} + +} // namespace ReflectiveRapidJSON + +#endif // REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H diff --git a/generator/main.cpp b/generator/main.cpp index c6ebcf2..4a5f743 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -1,4 +1,5 @@ #include "./codefactory.h" +#include "./jsonserializationcodegenerator.h" #include "resources/config.h" @@ -66,7 +67,7 @@ int main(int argc, char *argv[]) // find and construct generators by name for (const char *generatorName : generatorsArg.values(0)) { if (!strcmp(generatorName, "json")) { - factory.addGenerator(); + factory.addGenerator(); } else { cerr << Phrases::Error << "The specified generator \"" << generatorName << "\" does not exist." << Phrases::EndFlush; return -5; @@ -74,7 +75,7 @@ int main(int argc, char *argv[]) } } else { // add default generators - factory.addGenerator(); + factory.addGenerator(); } // read AST elements from input files and run the code generator diff --git a/generator/tests/jsongenerator.cpp b/generator/tests/jsongenerator.cpp index c12c75e..cae1a43 100644 --- a/generator/tests/jsongenerator.cpp +++ b/generator/tests/jsongenerator.cpp @@ -2,6 +2,7 @@ #include "./structs.h" #include "../codefactory.h" +#include "../jsonserializationcodegenerator.h" #include "resources/config.h" @@ -70,7 +71,7 @@ void OverallTests::testGeneratorItself() stringstream buffer; CodeFactory factory(TestApplication::appPath(), inputFiles, clangOptions, buffer); - factory.addGenerator(); + factory.addGenerator(); CPPUNIT_ASSERT(factory.run()); assertEqualityLinewise(m_expectedCode, toArrayOfLines(buffer.str())); }