ddl/ddlgenerators/generator_library/headerrepresentation/header_printer.cpp
2019-12-12 14:41:47 +01:00

382 lines
12 KiB
C++

/**
* @file
*
* @copyright
* @verbatim
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
This Source Code Form is subject to the terms of the Mozilla
Public License, v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
@endverbatim
*/
#include <ddl.h>
#include "header_printer.h"
#include "header_header.h"
#include "header_basic_type.h"
namespace ddl_generator
{
namespace oo
{
//define all needed error types and values locally
_MAKE_RESULT(0, ERR_NOERROR)
_MAKE_RESULT(-4, ERR_POINTER)
_MAKE_RESULT(-5, ERR_INVALID_ARG)
_MAKE_RESULT(-11, ERR_INVALID_FILE)
_MAKE_RESULT(-20, ERR_NOT_FOUND)
_MAKE_RESULT(-24, ERR_PATH_NOT_FOUND)
_MAKE_RESULT(-27, ERR_OPEN_FAILED)
_MAKE_RESULT(-38, ERR_FAILED)
}
}
using namespace ddl_generator::oo;
using namespace ddl;
namespace ddl
{
HeaderPrinter::HeaderPrinter() : _header(NULL)
{ }
HeaderPrinter::~HeaderPrinter()
{ }
a_util::result::Result HeaderPrinter::writeToFile(const a_util::filesystem::Path &filename)
{
std::string guarded_header_output = addHeaderGuards(filename, _header_output);
if (a_util::filesystem::writeTextFile(filename, guarded_header_output) != a_util::filesystem::OK)
{
return (ERR_OPEN_FAILED);
}
return ERR_NOERROR;
}
const std::string& HeaderPrinter::getHeader()
{
return _header_output;
}
a_util::result::Result HeaderPrinter::visit(const Header* header)
{
_header = header;
_header_output = "";
_header_output.append("// This is a generated file, changes to it may be overwritten in the future.\n\n");
if (_name_space.length() > 0)
{
_header_output.append(a_util::strings::format("namespace %s\n{\n", _name_space.c_str()));
}
HeaderTypedefs typedefs = header->getTypedefs();
for (HeaderTypedefs::iterator iter = typedefs.begin(); iter != typedefs.end(); iter++)
{
if (isFailed((appendType(*iter))))
{
return ERR_FAILED;
}
}
HeaderEnums enums = header->getEnums();
for (auto iter = enums.begin(); iter != enums.end(); iter++)
{
if (isFailed(((*iter)->accept(this))))
{
return ERR_FAILED;
}
}
HeaderStructs structs = header->getStructs();
for (HeaderStructs::iterator iter = structs.begin(); iter != structs.end(); iter++)
{
if (isFailed((appendType(*iter))))
{
return ERR_FAILED;
}
}
HeaderConstants constants = header->getConstants();
for (HeaderConstants::iterator iter = constants.begin(); iter != constants.end(); iter++)
{
if (isFailed(((*iter)->accept(this))))
{
return ERR_FAILED;
}
}
if (isFailed((printUnknownTypes())))
{
return ERR_FAILED;
}
if (_name_space.length() > 0)
{
_header_output.append(a_util::strings::format("} // namespace %s\n", _name_space.c_str()));
}
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderBasicType* basic_type)
{
CollectType(basic_type, true);
_header_output.append("// The following type is assumed to be known:\n");
_header_output.append("// ");
_header_output.append(basic_type->getName());
_header_output.append("\n\n");
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderTypedef* type_def)
{
printDescription(type_def);
// Set known first, so no infinite loop will occur when looking for base type
CollectType(type_def, true);
appendType(type_def->getOriginalType());
_header_output.append(a_util::strings::format("typedef %s %s;\n\n",
type_def->getOriginalType()->getName().c_str(), type_def->getName().c_str()));
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderConstant* constant)
{
appendType(constant->getType());
_header_output.append("const ");
_header_output.append(constant->getType()->getName());
_header_output.append(" ");
_header_output.append(constant->getName());
_header_output.append(" = ");
_header_output.append(constant->asString());
_header_output.append(";\n\n");
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderStruct* header_struct)
{
printDescription(header_struct);
// Set known first, so no infinite loop will occur when looking for base type
CollectType(header_struct, true);
// Make sure all types are already defined
HeaderStructElementVec elements = header_struct->getElements();
for (HeaderStructElementVec::iterator iter = elements.begin(); iter != elements.end(); iter++)
{
appendType((*iter)->getType());
}
_header_output.append(a_util::strings::format("#pragma pack(push,%d)\n", header_struct->getPacking()));
_header_output.append("typedef struct\n{\n");
for (HeaderStructElementVec::iterator iter = elements.begin(); iter != elements.end(); iter++)
{
if (isFailed(((*iter)->accept(this))))
{
return ERR_FAILED;
}
}
_header_output.append(a_util::strings::format("} %s;\n", header_struct->getName().c_str()));
_header_output.append("#pragma pack(pop)\n\n");
CollectType(header_struct, true);
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderStructElement* header_struct)
{
if (!header_struct || !header_struct->getType())
{
return ERR_INVALID_ARG;
}
printDescription(header_struct->getDescription(), header_struct->getComment(), true);
appendType(header_struct->getType());
_header_output.append(" ");
if (header_struct->isStatic())
{
_header_output.append("static ");
}
if (header_struct->isConst())
{
_header_output.append("const ");
}
_header_output.append(header_struct->getType()->getName());
if (header_struct->isPointer())
{
_header_output.append("* ");
}
_header_output.append(" ");
_header_output.append(header_struct->getName());
if (header_struct->getArraySize() > 1)
{
_header_output.append(a_util::strings::format("[%d]", header_struct->getArraySize()));
}
_header_output.append(";\n");
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::visit(const HeaderEnum* header_enum)
{
CollectType(header_enum, true);
printDescription(header_enum);
_header_output.append("typedef enum {\n");
for (auto iter = header_enum->getValues().begin(); iter != header_enum->getValues().end(); iter++)
{
_header_output.append(a_util::strings::format(" %s=%i,\n", iter->second.c_str(), iter->first));
}
if (header_enum->getValues().size() > 0)
{
// remove last ',' since some versions of C/C++ don't allow trailing commas in enums
_header_output.resize(_header_output.length() - 2);
}
_header_output.append(a_util::strings::format("\n} %s;\n\n", header_enum->getName().c_str()));
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::appendType(const HeaderType* type)
{
// See if we already know this type and therefore have printed it already
for (HeaderConstTypes::iterator iter = _known_types.begin(); iter != _known_types.end(); iter++)
{
if (*iter == type)
{
return ERR_NOERROR;
}
}
// Search the header for the type.
if (_header != NULL)
{
for (HeaderTypedefs::const_iterator iter = _header->getTypedefs().begin(); iter != _header->getTypedefs().end(); iter++)
{
if (*iter == type)
{
// Found it, append it
return ((*iter)->accept(this));
}
}
for (HeaderStructs::const_iterator iter = _header->getStructs().begin(); iter != _header->getStructs().end(); iter++)
{
if (*iter == type)
{
// Found it, append it
return ((*iter)->accept(this));
}
}
}
// Nothing found so far, so type is unknown
CollectType(type, false);
return (ERR_NOT_FOUND);
}
a_util::result::Result HeaderPrinter::CollectType(const ddl::HeaderType* type, bool is_known)
{
if (is_known)
{
if (std::find(_known_types.begin(), _known_types.end(), type) ==
_known_types.end())
{
_known_types.push_back(type);
}
}
else
{
if (std::find(_unknown_types.begin(), _unknown_types.end(), type) ==
_unknown_types.end())
{
_unknown_types.push_back(type);
}
}
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::printUnknownTypes()
{
// visit all types that are in the unknown types set but not in the knowN types set
HeaderConstTypes vec = _unknown_types;
for (HeaderConstTypes::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
if (std::find(_known_types.begin(), _known_types.end(), *iter) == _known_types.end())
{
(*iter)->accept(this);
}
}
if (vec.size() != _unknown_types.size())
{
printUnknownTypes();
}
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::printDescription(const std::string& description, const std::string& comment, bool indent)
{
if (description.length() == 0 && comment.length() == 0)
{
return ERR_NOERROR;
}
std::string indent_string;
if (indent)
{
indent_string = " ";
}
_header_output.append(indent_string);
_header_output.append("/**\n");
if (description.length() > 0)
{
_header_output.append(a_util::strings::format("%s * %s\n", indent_string.c_str(), description.c_str()));
}
if (comment.length() > 0)
{
_header_output.append(a_util::strings::format("%s * %s\n", indent_string.c_str(), comment.c_str()));
}
_header_output.append(indent_string);
_header_output.append("*/\n");
return ERR_NOERROR;
}
a_util::result::Result HeaderPrinter::printDescription(const HeaderType* type)
{
return printDescription(type->getDescription(), type->getComment());
}
bool invalidHeaderChar(char c)
{
bool is_num = (c >= '0' && c <= '9');
bool is_uppercase_alpha = (c >= 'A' && c <= 'Z');
bool is_lowercase_alpha = (c >= 'a' && c <= 'z');
bool is_allowed_punctuation = (c == '.' || c == '_' || c == '-');
return !(is_num || is_uppercase_alpha || is_lowercase_alpha || is_allowed_punctuation);
}
std::string HeaderPrinter::addHeaderGuards(const a_util::filesystem::Path &filename, const std::string &unguarded_header_content)
{
std::string guard_name = filename.getLastElement().toString();
guard_name.erase(std::remove_if(guard_name.begin(), guard_name.end(), invalidHeaderChar), guard_name.end());
std::replace(guard_name.begin(), guard_name.end(), '.', '_');
std::transform(guard_name.begin(), guard_name.end(), guard_name.begin(), ::toupper);
std::string output;
output.append("#ifndef ");
output.append(guard_name + "\n");
output.append("#define ");
output.append(guard_name + "\n\n");
output.append(unguarded_header_content);
output.append("\n#endif //");
output.append(guard_name + "\n");
return output;
}
void HeaderPrinter::SetNamespace(std::string name_space)
{
_name_space = name_space;
}
} // namespace ddl