diff --git a/source/RobotAPI/applications/AronCodeGenerator/main.cpp b/source/RobotAPI/applications/AronCodeGenerator/main.cpp index 8544c238abca345b587f78737198d6e5e51e7de6..f7e39ceefaefdc1bc131d075bd419fcd3fd20ba1 100644 --- a/source/RobotAPI/applications/AronCodeGenerator/main.cpp +++ b/source/RobotAPI/applications/AronCodeGenerator/main.cpp @@ -177,33 +177,60 @@ int main(int argc, char* argv[]) } } + auto w = CppWriterPtr(new CppWriter()); + + // Generate enums at top of generated header file + std::vector<MetaEnumPtr> enums = writer.getTypeEnums(); + if (verbose) + { + std::cout << "Now exporting enums..." << std::endl; + } + + MetaEnum::Write(enums, w); + + std::string enum_file_generation_content = w->getString(); + + if (verbose) + { + std::cout << "Now exporting enums... done!" << std::endl; + } + + if (enums.size() > 0 && enum_file_generation_content == "") + { + std::cerr << "\033[31m" << "Error code 11 - Found error in code generation. Aborting!" << "\033[0m" << std::endl; + exit(1); + } + + // Generate all classes std::vector<MetaClassPtr> classes = writer.getTypeClasses(); if (verbose) { std::cout << "Now exporting classes..." << std::endl; } - auto w = CppWriterPtr(new CppWriter()); CppClass::Write(classes, w); - std::string new_file_content = w->getString(); + std::string class_file_generation_content = simox::alg::remove_prefix(w->getString(), enum_file_generation_content); if (verbose) { std::cout << "Now exporting classes... done!" << std::endl; } - if (new_file_content == "") + if (classes.size() > 0 && class_file_generation_content == "") { - std::cerr << "Found error in code generation. Aborting!" << std::endl; + std::cerr << "\033[31m" << "Error code 21 - Found error in code generation. Aborting!" << "\033[0m" << std::endl; exit(1); } + std::time_t current_time = std::time(0); + std::tm* now = std::localtime(¤t_time); + std::string current_year = std::to_string(now->tm_year + 1900); std::string new_file_header = "\ /* \n\ * This file is part of ArmarX. \n\ * \n\ - * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), \n\ + * Copyright (C) 2012-" + current_year + ", High Performance Humanoid Technologies (H2T), \n\ * Karlsruhe Institute of Technology (KIT), all rights reserved. \n\ * \n\ * ArmarX is free software; you can redistribute it and/or modify \n\ @@ -228,7 +255,7 @@ int main(int argc, char* argv[]) ************************************************************************* \n\ */\n\n\n"; - std::string new_file_full_content = new_file_header + new_file_content; + std::string new_file_full_content = new_file_header + w->getString(); std::string new_name_with_extension = input_file.filename().replace_extension("").string(); new_name_with_extension += ".aron.generated.h"; @@ -247,7 +274,7 @@ int main(int argc, char* argv[]) { if (verbose) { - std::cout << "File content not changed for <" + output_file.string() + ">" << std::endl; + std::cout << "\033[31m" << "Error code 31 - File content not changed for <" + output_file.string() + ">" << "\033[0m" << std::endl; } exit(0); } @@ -261,12 +288,12 @@ int main(int argc, char* argv[]) if (verbose) { - std::cout << "Finished generating <" + output_file.string() + ">. The new file ist called <" << output_file.string() << ">" << std::endl; + std::cout << "\033[32m" << "Finished generating <" + output_file.string() + ">. The new file ist called <" << output_file.string() << ">" << "\033[0m" << std::endl; } } catch (const cxxopts::OptionException& e) { - std::cerr << "Error in parsing cxxopts options: " << e.what() << std::endl; + std::cerr << "\033[31m" << "Error code 01 - Error in parsing cxxopts options: " << e.what() << "\033[0m" << std::endl; exit(1); } exit(0); diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/CodeWriter.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/CodeWriter.h index 942d036f3e6ed88f012ccd2577c703bd85ac2c26..8649037d81255c299cb37d5e10c420b7df54fd6e 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/CodeWriter.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/CodeWriter.h @@ -31,7 +31,8 @@ #include <typeindex> // ArmarX -#include <ArmarXCore/libraries/cppgen/MetaClass.h> +#include <ArmarXCore/libraries/cppgen/CppEnum.h> +#include <ArmarXCore/libraries/cppgen/CppClass.h> #include <RobotAPI/libraries/aron/core/type/variant/All.h> @@ -61,12 +62,18 @@ namespace armarx::aron::codegenerator return typeClasses; } + std::vector<MetaEnumPtr> getTypeEnums() const // TODO: Create Meta Enum class to abstract away cpp details + { + return typeEnums; + } + protected: virtual void addSpecificReaderMethods() = 0; virtual void addSpecificWriterMethods() = 0; protected: std::vector<MetaClassPtr> typeClasses; + std::vector<MetaEnumPtr> typeEnums; std::string producerName; std::vector<codegenerator::WriterInfo> dataWriters; diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp index 41d39e44a9548099bc85ef8a22347796ba740717..a62bb8b681dfa73e4b641d10ca6e0b7d3d17af49 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.cpp @@ -247,17 +247,19 @@ namespace armarx::aron::codegenerator::cpp ARMARX_CHECK_NOT_NULL(nav); generator::IntEnumClass generator(*nav); + + // Create enum class and add to enums + CppEnumPtr enumrepresentation = setupEnumPtr(publicGenerateIntEnumType, generator); + typeEnums.push_back(enumrepresentation); + + // Generate aron wrapper class and add to classes CppClassPtr c = setupBasicCppClass(publicGenerateIntEnumType, generator); setupMemberFields(c, publicGenerateIntEnumType.doc_values, generator); c->addInherit("public armarx::aron::cpp::AronGeneratedClass"); // ctor - c->addCtor(generator.toInnerEnumCtor(c->getName())); - - // Specific methods - CppEnumPtr enumrepresentation = generator.toInnerEnumDefinition(); - c->addInnerEnum(enumrepresentation); + c->addCtor(generator.toEnumCtor(c->getName())); CppMethodPtr toString = generator.toToStringMethod(); c->addMethod(toString); @@ -346,6 +348,33 @@ namespace armarx::aron::codegenerator::cpp } } + CppEnumPtr Writer::setupEnumPtr(const typereader::GenerateInfo& info, const generator::IntEnumClass& gen) const + { + const auto& type = gen.getType(); + if (type.getMaybe() != type::Maybe::NONE) + { + // Should not happen since we check the maybe flag on creation of the generator. However, better to double check + throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Somehow the maybe flag of a top level object declaration is set. This is not valid!", std::to_string((int) type.getMaybe()) + " aka " + type::defaultconversion::string::Maybe2String.at(type.getMaybe()), type.getPath()); + } + + const std::string classCppTypename = gen.getClassCppTypename(); + + std::vector<std::string> namespaces = info.getNamespaces(); + std::string rawObjectName = info.getNameWithoutNamespace(); + namespaces.push_back(simox::alg::to_lower(rawObjectName) + "_details"); + + std::string enumdoc = "The enum definition of the enum of the auogenerated class '" + gen.getFullClassCppTypename() + "'."; + CppEnumPtr e = std::make_shared<CppEnum>(namespaces, "Enum"); + auto enumFields = gen.toEnumFields(); + + for (const auto& field : enumFields) + { + e->addField(field); + } + + return e; + } + CppClassPtr Writer::setupBasicCppClass(const typereader::GenerateInfo& info, const Generator& gen) const { const auto& type = gen.getType(); @@ -393,7 +422,7 @@ namespace armarx::aron::codegenerator::cpp } } - // add aron includes + // always add aron includes c->addInclude("<RobotAPI/libraries/aron/core/aron_conversions.h>"); c->addInclude("<RobotAPI/libraries/aron/core/rw.h>"); c->addInclude("<RobotAPI/libraries/aron/core/codegeneration/cpp/AronGeneratedClass.h>"); @@ -434,7 +463,7 @@ namespace armarx::aron::codegenerator::cpp void Writer::setupMemberFields(CppClassPtr& c, const std::map<std::string, std::string>& doc_members, const generator::ObjectClass& o) const { - auto publicFields = o.getPublicVariableDeclarations(""); + auto publicFields = o.getPublicVariableDeclarations(c->getName()); for (const auto& f : publicFields) { if (auto it = doc_members.find(f->getName()); it != doc_members.end()) @@ -447,7 +476,7 @@ namespace armarx::aron::codegenerator::cpp void Writer::setupMemberFields(CppClassPtr& c, const std::map<std::string, std::string>& doc_members, const generator::IntEnumClass& o) const { - auto publicFields = o.getPublicVariableDeclarations(""); + auto publicFields = o.getPublicVariableDeclarations(c->getName()); for (const auto& f : publicFields) { if (auto it = doc_members.find(f->getName()); it != doc_members.end()) diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.h index 9405f63952de447de96a97e68fb3614bfec47807..3aa93f1775c7fe460935552c9eb078f8ae45ad0c 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/Writer.h @@ -59,6 +59,8 @@ namespace armarx::aron::codegenerator::cpp virtual void addSpecificReaderMethods() override; CppClassPtr setupBasicCppClass(const typereader::GenerateInfo& info, const Generator& gen) const; + CppEnumPtr setupEnumPtr(const typereader::GenerateInfo& info, const generator::IntEnumClass& gen) const; + void setupMemberFields(CppClassPtr&, const std::map<std::string, std::string>& doc_members, const generator::ObjectClass&) const; void setupMemberFields(CppClassPtr&, const std::map<std::string, std::string>& doc_members, const generator::IntEnumClass&) const; diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp index f5463258db1423ba317c428b2d604907b913755a..ce2bbb8dd8df9bfc0fe5c8482e4a7921b42fdfa7 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.cpp @@ -44,7 +44,7 @@ namespace armarx::aron::codegenerator::cpp::generator } } - std::vector<CppFieldPtr> IntEnumClass::getPublicVariableDeclarations(const std::string&) const + std::vector<CppFieldPtr> IntEnumClass::getPublicVariableDeclarations(const std::string& className) const { std::vector<CppFieldPtr> fields; std::stringstream enum_to_name; @@ -52,6 +52,9 @@ namespace armarx::aron::codegenerator::cpp::generator std::stringstream enum_to_value; std::stringstream value_to_enum; + // add legacy typedef + fields.push_back(std::make_shared<CppField>("using", std::string(IMPL_ENUM), simox::alg::to_lower(className) + "_details::Enum", "Legacy typedef of enum")); + enum_to_name << "{" << std::endl; name_to_enum << "{" << std::endl; enum_to_value << "{" << std::endl; @@ -164,7 +167,7 @@ namespace armarx::aron::codegenerator::cpp::generator return {{{"value", ARON_OTHER_ACCESSOR + ".value"}}, false}; } - CppCtorPtr IntEnumClass::toInnerEnumCtor(const std::string& name) const + CppCtorPtr IntEnumClass::toEnumCtor(const std::string& name) const { CppCtorPtr c = std::make_shared<CppCtor>(name + "(const " + std::string(IMPL_ENUM) + " e)"); std::vector<std::pair<std::string, std::string>> initList = {{"value", "e"}}; @@ -173,12 +176,12 @@ namespace armarx::aron::codegenerator::cpp::generator return c; } - CppEnumPtr IntEnumClass::toInnerEnumDefinition() const + std::vector<CppEnumFieldPtr> IntEnumClass::toEnumFields() const { - CppEnumPtr e = std::make_shared<CppEnum>(std::string(IMPL_ENUM), "The internal enum definition of the enum of this autogenerated class."); + std::vector<CppEnumFieldPtr> e; for (const auto& [key, value] : type.getAcceptedValueMap()) { - e->addField(std::make_shared<CppEnumField>(key)); + e.push_back(std::make_shared<CppEnumField>(key)); } return e; } diff --git a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h index 10d6ca0c14d8100e71d78944f24fd3f46870b8e1..53e9dd4a31143ad193e29fa59aec0aed351860a5 100644 --- a/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h +++ b/source/RobotAPI/libraries/aron/codegeneration/codegenerator/codewriter/cpp/generator/toplevel/IntEnumClass.h @@ -54,8 +54,8 @@ namespace armarx::aron::codegenerator::cpp::generator // TODO: Move some of those methods to upper class for enums (if we want to support multiple enums) //CppCtorPtr toCopyCtor(const std::string&) const; - CppCtorPtr toInnerEnumCtor(const std::string&) const; - CppEnumPtr toInnerEnumDefinition() const; + std::vector<CppEnumFieldPtr> toEnumFields() const; + CppCtorPtr toEnumCtor(const std::string&) const; CppMethodPtr toIntMethod() const; CppMethodPtr toCopyAssignmentMethod() const; CppMethodPtr toEnumAssignmentMethod() const;