Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
#include "context.h"
#include "cmake_generator.h"
#include "../exception.h"
#include <cassert>
#include <cctype>
#include <fstream>
#include <algorithm>
#include <set>
#include <mutex>
CIdlCompilerCMakeGenerator::CIdlCompilerCMakeGenerator(sdv::IInterfaceAccess* pParser) : CGenContext(pParser), m_mtx("SDV_IDL_COMPILER_GENERATE_CMAKE")
{}
CIdlCompilerCMakeGenerator::~CIdlCompilerCMakeGenerator()
{}
bool CIdlCompilerCMakeGenerator::Generate(const std::string& ssTargetLibName)
{
// Synchronize CMake code generation among processes.
std::unique_lock<ipc::named_mutex> lock(m_mtx);
if (ssTargetLibName.empty())
throw CCompileException("No target library name defined for proxy/stub CMake file.");
// Create "proxy" directory
std::filesystem::path pathPSTarget = GetOutputDir() / "ps";
if (!std::filesystem::exists(pathPSTarget) && !std::filesystem::create_directory(pathPSTarget))
throw CCompileException("Cannot create proxy/stub directory: ", pathPSTarget.generic_u8string());
// The source string
std::string ssSource;
// File with "CMakeLists.txt" function; read completely if existing
std::filesystem::path pathFile = pathPSTarget / "CMakeLists.txt";
if (g_log_control.GetVerbosityMode() == EVerbosityMode::report_all)
std::cout << "Target file: " << pathFile.generic_u8string() << std::endl;
// Create or update CMakeLists.txt
if (std::filesystem::exists(pathFile))
{
std::ifstream stream;
stream.open(pathFile);
if (!stream.is_open()) throw CCompileException("Failed to open the CMakeLists.txt file for reading.");
// Read the complete source
std::stringstream sstream;
sstream << stream.rdbuf();
ssSource = std::move(sstream.str());
}
else // Create the file in memory
{
CKeywordMap mapKeywords;
mapKeywords.insert(std::make_pair("target_lib_name", ssTargetLibName));
ssSource = ReplaceKeywords(R"code(# Enforce CMake version 3.20 or newer needed for path function
cmake_minimum_required (VERSION 3.20)
# Use new policy for project version settings and default warning level
cmake_policy(SET CMP0048 NEW) # requires CMake 3.14
cmake_policy(SET CMP0092 NEW) # requires CMake 3.15
# Define project
project(%target_lib_name% VERSION 1.0 LANGUAGES CXX)
# Use C++17 support
set(CMAKE_CXX_STANDARD 17)
# Library symbols are hidden by default
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
# Set target name.
set(TARGET_NAME %target_lib_name%)
# Set the SDV_FRAMEWORK_DEV_INCLUDE if not defined yet
if (NOT DEFINED SDV_FRAMEWORK_DEV_INCLUDE)
if (NOT DEFINED ENV{SDV_FRAMEWORK_DEV_INCLUDE})
message( FATAL_ERROR "The environment variable SDV_FRAMEWORK_DEV_INCLUDE needs to be pointing to the SDV V-API development include files location!")
endif()
set (SDV_FRAMEWORK_DEV_INCLUDE "$ENV{SDV_FRAMEWORK_DEV_INCLUDE}")
endif()
# Include link to export directory of SDV V-API development include files location
include_directories(${SDV_FRAMEWORK_DEV_INCLUDE})
# Set platform specific compile flags
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(/W4 /WX /wd4996 /wd4100 /permissive- /Zc:rvalueCast)
else()
add_compile_options(-Werror -Wall -Wextra -Wshadow -Wpedantic -Wunreachable-code -fno-common)
endif()
# Add the dynamic library
add_library(${TARGET_NAME} SHARED)
# Set extension to .sdv
set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "")
set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".sdv")
# TODO: set target name.
#add_dependencies(${TARGET_NAME} <add_cmake_target_this_depends_on>)
)code", mapKeywords);
}
// Search function for caseless finding in the string.
auto fnNCFind = [&](const std::string& rssText, size_t nPos = 0) -> size_t
{
auto it = std::search(ssSource.begin() + nPos, ssSource.end(), rssText.begin(), rssText.end(),
[](unsigned char ch1, unsigned char ch2) { return std::tolower(ch1) == std::tolower(ch2); }
);
if (it == ssSource.end()) return std::string::npos;
return std::distance(ssSource.begin(), it);
};
// Find the add_library function
size_t nPos = fnNCFind("add_library");
if (nPos == std::string::npos) throw CCompileException("Missing 'add_library' keyword.");
// Search for shared keyword
nPos = fnNCFind("shared", nPos);
if (nPos == std::string::npos) throw CCompileException("Missing 'shared' keyword.");
nPos += 6;
// Build set with files
size_t nStop = fnNCFind(")", nPos);
if (nStop == std::string::npos) throw CCompileException("Missing ')' closing the 'add_library' statement.");
std::set<std::string> setFiles;
while (nPos < nStop)
{
// Skip whitespace
while (std::isspace(ssSource[nPos])) nPos++;
// Read file name
size_t nFileBegin = nPos;
while (nPos < nStop && !std::isspace(ssSource[nPos])) nPos++;
// Store the file
setFiles.insert(ssSource.substr(nFileBegin, nPos - nFileBegin));
}
// Insert additional files if needed
size_t nSourceSize = ssSource.size();
std::filesystem::path pathPSFileBase = GetSource().filename();
pathPSFileBase.replace_extension("");
std::string ssFileBase = pathPSFileBase.generic_u8string();
if (setFiles.find(ssFileBase + "_stub.cpp") == setFiles.end())
ssSource.insert(nStop, std::string("\n ") + ssFileBase + "_stub.cpp");
if (setFiles.find(ssFileBase + "_stub.h") == setFiles.end())
ssSource.insert(nStop, std::string("\n ") + ssFileBase + "_stub.h");
if (setFiles.find(ssFileBase + "_proxy.cpp") == setFiles.end())
ssSource.insert(nStop, std::string("\n ") + ssFileBase + "_proxy.cpp");
if (setFiles.find(ssFileBase + "_proxy.h") == setFiles.end())
ssSource.insert(nStop, std::string("\n ") + ssFileBase + "_proxy.h");
// Write the file again if needed
if (nSourceSize != ssSource.size())
{
std::ofstream stream;
stream.open(pathFile, std::ofstream::trunc);
if (!stream.is_open()) throw CCompileException("Failed to open the CMakeLists.txt file for writing.");
// Write the complete source
stream << ssSource;
}
// Done!
return true;
}

View File

@@ -0,0 +1,34 @@
#ifndef CMAKE_GENERATOR_H
#define CMAKE_GENERATOR_H
#include "../../../global/ipc_named_mutex.h"
/**
* @brief CMake generator class.
*/
class CIdlCompilerCMakeGenerator : public CGenContext
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CIdlCompilerCMakeGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CIdlCompilerCMakeGenerator() override;
/**
* @brief Generate the definition.
* @param[in] ssTargetLibName Library target name to add in the cmake file.
* @return Returns whether the generation was successful.
*/
bool Generate(const std::string& ssTargetLibName);
private:
ipc::named_mutex m_mtx; ///< Guarantee exclusive access while writing the CMake file.
};
#endif // !defined CMAKE_GENERATOR_H

View File

@@ -0,0 +1,499 @@
#include "context.h"
#include "../exception.h"
#include <cassert>
#include <cctype>
#include <fstream>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <functional>
#include <vector>
CGenContext::CGenContext(sdv::IInterfaceAccess* pParser) : m_pParser(pParser)
{
if (!m_pParser) throw CCompileException("Internal error: no valid parser pointer supplied to generator.");
m_pCompilerInfo = m_pParser->GetInterface<sdv::idl::ICompilerInfo>();
if (!m_pCompilerInfo) throw CCompileException("Internal error: compiler info is not available.");
m_pOption = m_pParser->GetInterface<sdv::idl::ICompilerOption>();
if (!m_pOption) throw CCompileException("Internal error: cannot access options interface.");
}
CGenContext::~CGenContext()
{}
std::filesystem::path CGenContext::GetSource() const
{
if (!m_pCompilerInfo) return std::filesystem::path();
std::filesystem::path pathSource = static_cast<std::string>(m_pCompilerInfo->GetFilePath());
if (pathSource.empty()) throw CCompileException("Internal error: file path is not available.");
return pathSource;
}
std::filesystem::path CGenContext::GetOutputDir() const
{
if (!m_pCompilerInfo) return std::filesystem::path();
std::filesystem::path pathOutputDir = static_cast<std::string>(m_pCompilerInfo->GetOutputDir());
if (pathOutputDir.empty())
pathOutputDir = GetSource().parent_path();
return pathOutputDir;
}
std::string CGenContext::Header(const std::filesystem::path& rpathFile,
const std::string& rssDescription /*= std::string()*/) const
{
std::stringstream sstream;
// Add file header
sstream << "/**" << std::endl;
sstream << " * @file " << rpathFile.filename().generic_u8string() << std::endl;
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
sstream << " * @date " << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << std::endl;
sstream << " * This file was generated by the SDV IDL compiler from '" << GetSource().filename().generic_u8string() << "'" <<
std::endl;
if (!rssDescription.empty())
{
// Insert the JavaDoc marks before each line
size_t nPos = 0;
while (nPos < rssDescription.size())
{
size_t nEnd = rssDescription.find_first_of("\r\n", nPos);
sstream << " * " << rssDescription.substr(nPos, nEnd == std::string::npos ? nEnd : nEnd - nPos) << std::endl;
nPos = nEnd;
if (nPos < rssDescription.size() && rssDescription[nPos] == '\r')
nPos++;
if (nPos < rssDescription.size() && rssDescription[nPos] == '\n')
nPos++;
}
}
sstream << " */" << std::endl;
sstream << std::endl;
return sstream.str();
}
std::string CGenContext::Safeguard(const std::filesystem::path& rpathFile, bool bInitial)
{
// Safeguards start with "__IDL_GENERATED__", add the file name, add the date and time and end with "__"
std::stringstream sstreamSafeguard;
sstreamSafeguard << "__IDL_GENERATED__";
std::string ssFile = rpathFile.filename().generic_u8string();
for (char c : ssFile)
{
if ((c < '0' || c > '9') &&
(c < 'a' || c > 'z') &&
(c < 'A' || c > 'Z'))
sstreamSafeguard << '_';
else
sstreamSafeguard << static_cast<char>(std::toupper(c));
}
sstreamSafeguard << "__";
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
sstreamSafeguard << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << "_";
sstreamSafeguard << std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() % 1000;
sstreamSafeguard << "__";
// Return the safeguard code
std::stringstream sstream;
if (bInitial)
sstream << "#ifndef " << sstreamSafeguard.str() << std::endl << "#define " << sstreamSafeguard.str() << std::endl << std::endl;
else
sstream << std::endl << "#endif // !defined(" << sstreamSafeguard.str() << ")" << std::endl;
return sstream.str();
}
std::string CGenContext::SmartIndent(const std::string& rssStr, const std::string& rssIndent)
{
// Determine the amount of whitespace at the beginning of the string and replace this whitespace by the current indent. Do
// this for every line.
// Use four spaces for every tab (to allow mixed tab and space usage).
size_t nDetectedIndentation = 0;
size_t nPos = 0;
enum class EState {init, skip_indent, code} eState = EState::init;
while (eState == EState::init && nPos < rssStr.size())
{
switch (rssStr[nPos])
{
case ' ':
nDetectedIndentation++;
nPos++;
break;
case '\t':
nDetectedIndentation += 4;
nPos++;
break;
default:
eState = EState::code;
break;
}
}
std::stringstream sstream;
while (nPos < rssStr.size())
{
// Skip indentation
size_t nSkip = 0;
while (eState == EState::skip_indent && nSkip < nDetectedIndentation)
{
switch (rssStr[nPos])
{
case ' ':
nSkip++;
nPos++;
break;
case '\t':
nSkip +=4;
nPos++;
break;
default:
eState = EState::code;
break;
}
}
eState = EState::code;
// Find the next newline
size_t nEnd = rssStr.find_first_of("\r\n", nPos);
std::string ssSubstr = rssStr.substr(nPos, nEnd == std::string::npos ? nEnd : nEnd - nPos);
// If the string didn't start with a number character, remove the line concatinating character if it's there.
if (rssStr[0] != '#' && !ssSubstr.empty() && *ssSubstr.rbegin() == '\\')
ssSubstr.resize(ssSubstr.size() - 1);
// Remove whitespace at the end of the string
while (!ssSubstr.empty() && std::isspace(*ssSubstr.rbegin()))
ssSubstr.resize(ssSubstr.size() - 1);
// Stream the sub-string with indentation if the string didn't start with a number character.
sstream << (rssStr[0] != '#' ? rssIndent : "") << ssSubstr;
// Stream and skip newline
nPos = nEnd;
if (nPos < rssStr.size())
{
if (rssStr[nPos] == '\r')
nPos++;
if (rssStr[nPos] == '\n')
nPos++;
eState = EState::skip_indent;
}
sstream << std::endl;
}
return sstream.str();
}
std::string CGenContext::QualifyName(const std::string& rssName)
{
std::stringstream sstream;
size_t nPos = 0;
while (nPos < rssName.size())
{
size_t nSeparator = rssName.find_first_of(":.[]", nPos);
sstream << rssName.substr(nPos, nSeparator == std::string::npos ? nSeparator : nSeparator - nPos);
nPos = nSeparator;
if (nPos != std::string::npos)
{
if (rssName[nPos] != ']')
sstream << "_";
nPos++;
}
}
return sstream.str();
}
std::string CGenContext::ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker /*= '%'*/)
{
std::stringstream sstream;
size_t nPos = 0;
while (nPos < rssStr.size())
{
// Find the initial separator
size_t nSeparator = rssStr.find(cMarker, nPos);
sstream << rssStr.substr(nPos, nSeparator == std::string::npos ? nSeparator : nSeparator - nPos);
nPos = nSeparator;
if (nSeparator == std::string::npos) continue;
nPos++;
// Find the next separator.
nSeparator = rssStr.find(cMarker, nPos);
if (nSeparator == std::string::npos)
throw CCompileException("Internal error: missing second separator during code generation.");
// Find the keyword in the keyword map (between the separator and the position).
CKeywordMap::const_iterator itKeyword = rmapKeywords.find(rssStr.substr(nPos, nSeparator - nPos));
if (itKeyword == rmapKeywords.end())
{
std::stringstream sstreamError;
sstreamError << "Internal error: invalid keyword \"" << rssStr.substr(nPos, nSeparator - nPos) <<
"\" during code generation.";
throw CCompileException(sstreamError.str().c_str());
} else
sstream << itKeyword->second;
nPos = nSeparator + 1;
}
return sstream.str();
}
std::string CGenContext::GetIndentChars()
{
// Default indentation is 4 spaces
return " ";
}
CGenContext::SCDeclInfo CGenContext::GetCDeclTypeStr(sdv::IInterfaceAccess* pDeclTypeObj, const std::string& rssScope /*= std::string()*/, bool bScopedName /*= false*/) const
{
std::function<void(sdv::IInterfaceAccess*, CGenContext::SCDeclInfo&)> fnInterpretType =
[&, this](sdv::IInterfaceAccess* pTypeObj, CGenContext::SCDeclInfo& rsCDeclInfo)
{
if (!pTypeObj) throw CCompileException("Internal error: expecting a declaration type.");
const sdv::idl::IDeclarationType* pDeclType = pTypeObj->GetInterface<sdv::idl::IDeclarationType>();
if (!pDeclType) throw CCompileException("Internal error: expecting a declaration type.");
rsCDeclInfo.eBaseType = pDeclType->GetBaseType();
// Separate between system type and defined type.
if (pDeclType->GetTypeDefinition())
{
// Deal with anonymous definitions
const sdv::idl::IEntityInfo* pTypeInfo = GetInterface<sdv::idl::IEntityInfo>(pDeclType->GetTypeDefinition());
if (!pTypeInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
rsCDeclInfo.ssDeclType = bScopedName ?
GetRelativeScopedName(pTypeInfo->GetScopedName(), rssScope) :
static_cast<std::string>(pTypeInfo->GetName());
if (rsCDeclInfo.ssDeclType.empty()) throw CCompileException("Internal error: the intity doesn't have a name.");
}
else
rsCDeclInfo.ssDeclType = MapDeclType2CType(rsCDeclInfo.eBaseType);
// If the type is an interface, add a pointer to the type
// TODO: Check for derived type...
switch (rsCDeclInfo.eBaseType)
{
case sdv::idl::EDeclType::decltype_interface:
rsCDeclInfo.ssDeclType += "*";
rsCDeclInfo.bIsInterface = true;
rsCDeclInfo.bIsPointer = true;
break;
case sdv::idl::EDeclType::decltype_string:
case sdv::idl::EDeclType::decltype_u8string:
case sdv::idl::EDeclType::decltype_u16string:
case sdv::idl::EDeclType::decltype_u32string:
case sdv::idl::EDeclType::decltype_wstring:
rsCDeclInfo.bIsString = true;
rsCDeclInfo.bIsComplex = true;
if (pDeclType->GetFixedLength())
{
// Insert fixed after sdv:: and before the string name
rsCDeclInfo.ssDeclType.insert(5, "fixed_");
rsCDeclInfo.ssDeclType += "<" + std::to_string(pDeclType->GetFixedLength()) + ">";
rsCDeclInfo.bTemplated = true;
}
break;
case sdv::idl::EDeclType::decltype_sequence:
rsCDeclInfo.bIsComplex = true;
if (!pDeclType->GetValueType())
throw CCompileException("Internal error: expecting value type for template parameter.");
else
{
CGenContext::SCDeclInfo sCDeclInfoValueType;
fnInterpretType(pDeclType->GetValueType(), sCDeclInfoValueType);
rsCDeclInfo.ssDeclType += "<" + sCDeclInfoValueType.ssDeclType;
if (pDeclType->GetFixedLength())
rsCDeclInfo.ssDeclType += ", " + std::to_string(pDeclType->GetFixedLength());
rsCDeclInfo.ssDeclType += ">";
rsCDeclInfo.bTemplated = true;
}
break;
case sdv::idl::EDeclType::decltype_pointer:
rsCDeclInfo.bIsComplex = true;
if (!pDeclType->GetValueType())
throw CCompileException("Internal error: expecting value type for template parameter.");
else
{
CGenContext::SCDeclInfo sCDeclInfoValueType;
fnInterpretType(pDeclType->GetValueType(), sCDeclInfoValueType);
rsCDeclInfo.ssDeclType += "<" + sCDeclInfoValueType.ssDeclType;
if (pDeclType->GetFixedLength())
rsCDeclInfo.ssDeclType += ", " + std::to_string(pDeclType->GetFixedLength());
rsCDeclInfo.ssDeclType += ">";
rsCDeclInfo.bTemplated = true;
}
break;
case sdv::idl::EDeclType::decltype_struct:
case sdv::idl::EDeclType::decltype_union:
rsCDeclInfo.bIsComplex = true;
break;
default:
break;
}
};
// Fill the C++ type structure
CGenContext::SCDeclInfo sCDeclInfo;
if (!pDeclTypeObj) return sCDeclInfo;
fnInterpretType(pDeclTypeObj, sCDeclInfo);
// Exclude void as valid type
if (sCDeclInfo.ssDeclType != "void")
sCDeclInfo.bValidType = true;
return sCDeclInfo;
}
std::string CGenContext::MapEntityType2CType(sdv::idl::EEntityType eEntityType)
{
switch (eEntityType)
{
case sdv::idl::EEntityType::type_enum: return "enum class";
case sdv::idl::EEntityType::type_struct: return "struct";
case sdv::idl::EEntityType::type_union: return "union";
case sdv::idl::EEntityType::type_module: return "namespace";
case sdv::idl::EEntityType::type_interface: return "interface";
case sdv::idl::EEntityType::type_exception: return "except";
case sdv::idl::EEntityType::type_typedef: return "typedef";
case sdv::idl::EEntityType::type_attribute: return "";
case sdv::idl::EEntityType::type_operation: return "";
case sdv::idl::EEntityType::type_parameter: return "";
case sdv::idl::EEntityType::type_enum_entry: return "";
case sdv::idl::EEntityType::type_case_entry: return "";
default:
return "invalid";
}
}
std::string CGenContext::MapDeclType2CType(sdv::idl::EDeclType eDeclType)
{
switch (eDeclType)
{
case sdv::idl::EDeclType::decltype_short: return "int16_t";
case sdv::idl::EDeclType::decltype_long: return "int32_t";
case sdv::idl::EDeclType::decltype_long_long: return "int64_t";
case sdv::idl::EDeclType::decltype_unsigned_short: return "uint16_t";
case sdv::idl::EDeclType::decltype_unsigned_long: return "uint32_t";
case sdv::idl::EDeclType::decltype_unsigned_long_long: return "uint64_t";
case sdv::idl::EDeclType::decltype_float: return "float";
case sdv::idl::EDeclType::decltype_double: return "double";
case sdv::idl::EDeclType::decltype_long_double: return "long double";
case sdv::idl::EDeclType::decltype_fixed: return "uint32_t"; // TODO: Not implemented!
case sdv::idl::EDeclType::decltype_char: return "char";
case sdv::idl::EDeclType::decltype_char16: return "char16_t";
case sdv::idl::EDeclType::decltype_char32: return "char32_t";
case sdv::idl::EDeclType::decltype_wchar: return "wchar_t";
case sdv::idl::EDeclType::decltype_boolean: return "bool";
case sdv::idl::EDeclType::decltype_native: return "size_t";
case sdv::idl::EDeclType::decltype_octet: return "uint8_t";
case sdv::idl::EDeclType::decltype_string: return "sdv::string";
case sdv::idl::EDeclType::decltype_u8string: return "sdv::u8string";
case sdv::idl::EDeclType::decltype_u16string: return "sdv::u16string";
case sdv::idl::EDeclType::decltype_u32string: return "sdv::u32string";
case sdv::idl::EDeclType::decltype_wstring: return "sdv::wstring";
case sdv::idl::EDeclType::decltype_enum: return "enum class";
case sdv::idl::EDeclType::decltype_struct: return "struct";
case sdv::idl::EDeclType::decltype_union: return "union";
case sdv::idl::EDeclType::decltype_module: return "namespace";
case sdv::idl::EDeclType::decltype_interface: return "interface";
case sdv::idl::EDeclType::decltype_exception: return "struct";
case sdv::idl::EDeclType::decltype_attribute: return "";
case sdv::idl::EDeclType::decltype_operation: return "";
case sdv::idl::EDeclType::decltype_parameter: return "";
case sdv::idl::EDeclType::decltype_enum_entry: return "";
case sdv::idl::EDeclType::decltype_case_entry: return "";
case sdv::idl::EDeclType::decltype_typedef: return "typedef";
case sdv::idl::EDeclType::decltype_sequence: return "sdv::sequence";
case sdv::idl::EDeclType::decltype_pointer: return "sdv::pointer";
case sdv::idl::EDeclType::decltype_map: return "uint32_t"; // TODO: Not implemented!
case sdv::idl::EDeclType::decltype_bitset: return "uint32_t"; // TODO: Not implemented!
case sdv::idl::EDeclType::decltype_bitfield: return "uint32_t"; // TODO: Not implemented!
case sdv::idl::EDeclType::decltype_bitmask: return "uint32_t"; // TODO: Not implemented!
case sdv::idl::EDeclType::decltype_any: return "sdv::any_t";
case sdv::idl::EDeclType::decltype_interface_id: return "sdv::interface_id";
case sdv::idl::EDeclType::decltype_interface_type: return "sdv::interface_t";
case sdv::idl::EDeclType::decltype_exception_id: return "sdv::exception_id";
case sdv::idl::EDeclType::decltype_void: return "void";
case sdv::idl::EDeclType::decltype_unknown:
default:
return "invalid";
}
}
std::string CGenContext::GetRelativeScopedName(const std::string& ssScopedName, const std::string& rssScope)
{
if (rssScope.empty()) return ssScopedName;
// Splitting function
using CScopeVector = std::vector<std::string>;
auto fnSplitScopedName = [](const std::string& rssName) -> CScopeVector
{
CScopeVector vecSplittedName;
size_t nPos = 0;
while (nPos != std::string::npos)
{
size_t nStart = nPos;
nPos = rssName.find("::", nStart);
vecSplittedName.push_back(rssName.substr(nStart, nPos - nStart));
if (nPos != std::string::npos)
nPos += 2;
}
return vecSplittedName;
};
// Split the scoped name
CScopeVector vecScopedName = fnSplitScopedName(ssScopedName);
if (vecScopedName.empty()) return ssScopedName;
// Split the scope
CScopeVector vecScope = fnSplitScopedName(rssScope);
if (vecScope.empty()) return ssScopedName;
// Reverse find the starting point
auto itScope = vecScope.end();
auto itScopedName = vecScopedName.begin();
while (itScope != vecScope.begin())
{
itScope--;
if (*itScope == *itScopedName) break;
}
// As long as both iterators have identical scope names, increase the iterators.
auto itSavedScopedName = itScopedName;
while (itScope != vecScope.end() && itScopedName != vecScopedName.end() && *itScope == *itScopedName)
{
itScope++;
itSavedScopedName = itScopedName;
itScopedName++;
}
// If the next name scope is anywhere in the rest of the scope, use the save scope name instead. For example:
// Name = a::b::c::d
// Scope = a::b::x::c
// The iterator is pointing to:
// Name iterator = c::d
// Scope iterator = x::c
// If returning the relative name (which is "c::d") it will be relative to the scope (which is "a::b::x::c") and will then be
// a scoped name "a::b::x::c::d", which might not even exist. To solve this, insert the last scoped name part to the returned
// name if the name is used in the rest of the scope as well (so insert "b" to the name which leads to a relative name of
// "b::c::d").
while (itScope != vecScope.end())
{
if (*itScope == *itScopedName)
{
itScopedName = itSavedScopedName;
break;
}
itScope++;
}
// Create a new scoped name from the left over scope names in the scoped name vector.
std::string ssScopedNameNew;
while (itScopedName != vecScopedName.end())
{
if (!ssScopedNameNew.empty()) ssScopedNameNew += "::";
ssScopedNameNew += *itScopedName;
itScopedName++;
}
return ssScopedNameNew;
}

View File

@@ -0,0 +1,187 @@
#ifndef CONTEXT_H
#define CONTEXT_H
#include "../includes.h"
#include <filesystem>
#include <map>
/**
* @brief Generator context
*/
class CGenContext
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CGenContext(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CGenContext();
/**
*
* @brief Get the parser interface.
* @tparam TInterface The interface to request the interface from.
* @param[in] pObject Pointer to the object to request the interface from or NULL when the parser should be asked.
* @return Returns a pointer to the interface if available.
*/
template <typename TInterface>
TInterface* GetInterface(sdv::IInterfaceAccess* pObject) const;
/**
* @brief Return the interface to the parser.
* @return The interface to the parser or NULL when the parser is not available.
*/
sdv::IInterfaceAccess* GetParser() const { return m_pParser; }
/**
* @brief Get source path.
* @return Returns the source path.
*/
std::filesystem::path GetSource() const;
/**
* @brief Get the output directory.
* @remarks If there is no output directory defined, takes the parent directory of the source.
* @return Returns the output directory path.
*/
std::filesystem::path GetOutputDir() const;
/**
* @brief File header generation using JavaDoc C-style comments.
* @param[in] rpathFile Reference to the path to the file to generate the header for.
* @param[in] rssDescription Optional description to add to the file header.
* @return Returns the file header string.
*/
std::string Header(const std::filesystem::path& rpathFile, const std::string& rssDescription = std::string()) const;
/**
* @brief Creates safeguard C++ string that can be used to safeguard a C++ header file.
* @param[in] rpathFile Reference to the path to the file to use for safeguarding.
* @param[in] bInitial When set, creates initial lines, otherwise closing lines.
* @return Returns the safeguard string composed front the path.
*/
static std::string Safeguard(const std::filesystem::path& rpathFile, bool bInitial);
/**
* @brief Insert indentation before each text within a (multi-line) string.
* @details If the line doesn't start with a number sign insert an indentation before each line. Also a line-concatinating
* character (back-slash before end of line) will be removed. Independent of the number sign, any whitespace at the end of each
* line will be removed.
* @param[in] rssStr Reference to the string to adapt.
* @param[in] rssIndent Reference to the indentation string to insert.
* @return Returns the string with inserted indentations
*/
static std::string SmartIndent(const std::string& rssStr, const std::string& rssIndent);
/**
* @brief Make a qualified identifier from a fully scoped name with array brackets.
* @details A fully scoped name contains all the namespace and struct definitions that define the context of the supplied name.
* The names of each level is separated by the scope separator (::). Also any member declaration is separated by the member
* separator (.). The name could also contain square brackets to identify an array. This function replaces the scope operator by
* a double underscore (__), the array operator by a single underscore and the array brackets by a single underscore. In the
* end, the name results in a qualified C++ name.
* @param[in] rssName Reference to the name string to qualify.
* @return Returns the qualified name sstring.
*/
static std::string QualifyName(const std::string& rssName);
/**
* @brief Keyword map for keyword replacement in a string.
*/
typedef std::map<std::string, std::string> CKeywordMap;
/**
* @brief Vector containing the exceptions that might be thrown by the function.
*/
typedef std::vector<std::string> CExceptionVector;
/**
* @brief Replace keywords in a string.
* @param[in] rssStr Reference to the string containing the keywords.
* @param[in] rmapKeywords Map with keywords to replace.
* @param[in] cMarker Character to identify the keyword with (placed before and after the keyword; e.g. %keyword%).
* @return Returns the string with replacements.
*/
static std::string ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker = '%');
/**
* @brief Get indentation string (represents one tab).
* @return Reference to the string with the indentation.
*/
static std::string GetIndentChars();
/**
* @brief Declaration information.
*/
struct SCDeclInfo
{
sdv::idl::EDeclType eBaseType = sdv::idl::EDeclType::decltype_unknown; ///< Base type
std::string ssDeclType; ///< Declaration type (incl. pointer addition for every array extend).
bool bIsPointer = false; ///< Type is represented as a pointer to dynamic data or an interface.
bool bIsComplex = false; ///< Complex data type; use by-ref for parameters.
bool bTemplated = false; ///< Type has template parameters
bool bIsInterface = false; ///< Type is an interface pointer.
bool bIsString = false; ///< Set when the type represents a string object.
bool bIsDynamic = false; ///< Type is dynamic
bool bValidType = false; ///< Type is not void
};
/**
* @brief Get the C++ declaration type as string.
* @attention Does not check for anonymous types.
* @param[in] pDeclTypeObj Pointer to the IInterfaceAccess interface of the declaration type object.
* @param[in] rssScope Reference to the string containing the current scope.
* @param[in] bScopedName When set, return the scoped name.
* @return The declaration information (or empty types when not available).
*/
SCDeclInfo GetCDeclTypeStr(sdv::IInterfaceAccess* pDeclTypeObj, const std::string& rssScope /*= std::string()*/, bool bScopedName = false) const;
/**
* @brief Map the IDL type to the C type (if possible).
* @param[in] eEntityType The entity type to map.
* @return Returns a string representing the C type or empty if there is no C type or "invalid" if the type is invalid.
*/
static std::string MapEntityType2CType(sdv::idl::EEntityType eEntityType);
/**
* @brief Map the IDL type to the C type (if possible).
* @param[in] eDeclType The declaration type to map.
* @return Returns a string representing the C type or empty if there is no C type or "invalid" if the type is invalid.
*/
static std::string MapDeclType2CType(sdv::idl::EDeclType eDeclType);
/**
* @brief Get a relative scoped name based on the provided scope entity.
* @param[in] ssScopedName Reference to the fully scoped name of the entity.
* @param[in] rssScope Reference to the current scope.
* @return String with the relatively scoped name.
*/
static std::string GetRelativeScopedName(const std::string& ssScopedName, const std::string& rssScope);
private:
sdv::IInterfaceAccess* m_pParser = nullptr; ///< Parse tree instance.
sdv::idl::ICompilerInfo* m_pCompilerInfo = nullptr; ///< Compiler information interface.
sdv::idl::ICompilerOption* m_pOption = nullptr; ///< Program options interface.
};
template <typename TInterface>
inline TInterface* CGenContext::GetInterface(sdv::IInterfaceAccess* pObject) const
{
if (!pObject) return nullptr;
return pObject->GetInterface(sdv::GetInterfaceId<TInterface>()).template get<TInterface>();
}
#ifndef DOXYGEN_IGNORE
template <>
inline sdv::IInterfaceAccess* CGenContext::GetInterface(sdv::IInterfaceAccess* pObject) const
{
return pObject;
}
#endif
#endif // !defined(CONTEXT_H)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
#ifndef DEFINITION_GENERATOR_H
#define DEFINITION_GENERATOR_H
#include "definition_generator_base.h"
#include <list>
#include <fstream>
#include <set>
#include <sstream>
// TODO: Comment style overwrite: all javadoc, QT, C, Cpp, preceding, succeeding
// TODO: Tabs or spaces
// TODO: Tab size (default 4 characters)
// TODO: Succeeding comments
/**
* @brief Switch code context specifically for definition creation.
*/
struct SDefinitionSwitchCodeContext : SSwitchCodeContext
{
std::stringstream sstreamCode; ///< Code used to the actual switching
std::stringstream sstreamConstructorImpl; ///< Constructor content stream. Not applicable if the definition is a
///< namespace.
std::stringstream sstreamDestructorImpl; ///< Destructor content stream. Not applicable if the definition is a namespace.
std::stringstream sstreamConstructHelperImpl; ///< Constructor helper function for this switch variable.
std::stringstream sstreamCopyConstructHelperImpl; ///< Constructor content stream for copy construction. Not applicable if the
///< definition is a namespace.
std::stringstream sstreamMoveConstructHelperImpl; ///< Constructor content stream for move construction. Not applicable if the
///< definition is a namespace.
std::stringstream sstreamDestructHelperImpl; ///< Constructor helper function for this switch variable.
};
/**
* @brief Definition stream context.
*/
struct CDefinitionContext : CDefEntityContext<CDefinitionContext>
{
/**
* @brief Constructor assigning the generator context.
* @param[in] rGenContext Reference to the context to assign.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
*/
CDefinitionContext(const CGenContext& rGenContext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Copy constructor assigning a new definition entity.
* @param[in] rcontext Original context to copy from.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
*/
CDefinitionContext(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Join a context into this context. Overload of CDefEntityContext::operator<<.
* @param[in] rcontext Reference to the context to join.
* @return Reference to this context containing the joined result.
*/
virtual CDefinitionContext& operator<<(const CDefinitionContext& rcontext) override;
/**
* @brief Set the definition access to public (default).
*/
void SetDefAccessPublic();
/**
* @brief Set the definition access to private..
*/
void SetDefAccessPrivate();
/**
* @brief Get a reference to the preface stream.
* @return Reference to the preface stream object.
*/
std::stringstream& GetPrefaceStream();
/**
* @brief Get a reference to the definition code stream.
* @return Reference to the definition code stream object.
*/
std::stringstream& GetDefCodeStream();
/**
* @brief Get a reference to the preface or definition code stream dependable on the preface switch.
* @return Reference to the preface or definition code stream object.
*/
std::stringstream& GetAutoStream();
/**
* @brief Get definition code (this adds both prefacce and definition code stream content).
* @return Returns a string containing the definition code collected within this context.
*/
std::string GetDefinitionCode() const;
/**
* @brief Returns whether the preface switch is still activated.
* @return The current state of the preface switch for streaming.
*/
bool UsePreface() const;
/**
* @brief Disable the preface switch.
*/
void DisablePreface();
/**
* @brief Is construction needed?
* @return Returns whether construction is needed.
*/
bool NeedsConstruction() const;
/**
* @brief Set the construction needed flag.
*/
void SetConstructionNeeded();
/**
* @brief Newline-after-content-flag set?
* @return Returns whether a newline after the definition content is required.
*/
bool NeedsNewlineAfterContent() const;
/**
* @brief Set the newline-after-content-flag.
*/
void EnableNewlineAfterContent();
/**
* @brief Reset the newline-after-content-flag.
*/
void DisableNewlineAfterContent();
/**
* @brief Dies this entity have any friends?
* @return Returns whether this entity has any friends in the friend set.
*/
bool HasFriends() const;
/**
* @brief Get the set of friends.
* @return Returns the reference to the set of friends.
*/
const std::set<std::string>& GetFriendSet() const;
/**
* @brief Assign a the friend to this entity.
* @param[in] rssScopedName Reference to the scoped name of the friend entity.
*/
void AddFriend(const std::string& rssScopedName);
private:
std::stringstream m_sstreamPreface; ///< Preface stream (before the first code).
std::stringstream m_sstreamDefCode; ///< Definition code stream.
bool m_bPreface = false; ///< When set, streaming is done in the preface stream
///< instead of the definition code stream.
bool m_bConstructionCompulsory = false; ///< Constructor needed even if no content is available
///< (needed wen objects need to be initialized with default
///< initialization). Not applicable if the definition is a
///< namespace (should not occur).
bool m_bCurrentDefAccessPublic = true; ///< When set, the current definition access is public;
///< private when not set.
bool m_bNewlineAfterContent = false; ///< The next content that is streamed, should insert a
///< newline.
sdv::IInterfaceAccess* m_pDefEntity = nullptr; ///< The definition entity that defines this context.
std::set<std::string> m_setFriends; ///< Friend structures needed to allow access to the
///< private member.
};
/**
* @brief Definition generator class.
*/
class CDefinitionGenerator : public CDefinitionGeneratorBase<CDefinitionContext>
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CDefinitionGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CDefinitionGenerator() override;
private:
/**
* @brief Return the information for target file creation. Overload of CDefinitionGeneratorBase::GetTargetFileInfo.
* @param[out] rssTargetSubDir Reference to the string containing the target sub-directory to be added to the output directory.
* Could be empty to target the output directory.
* @param[out] rssTargetFileEnding Reference to string containing the file ending (file name and extension) to be placed at the
* end of the source file name replacing the extension.
*/
virtual void GetTargetFileInfo(std::string& rssTargetSubDir, std::string& rssTargetFileEnding) override;
/**
* @brief Return the file header text for automatic file generation. Overload of CDefinitionGeneratorBase::GetFileHeaderText.
* @return The header text to place into the file.
*/
virtual std::string GetFileHeaderText() const override;
/**
* @brief Stream the code into the file. Called once after processing. Overload of CDefinitionGeneratorBase::StreamIntoFile.
* @param[in, out] rcontext Reference to the stream context.
* @param[in, out] rfstream Reference to the file stream to stream into
*/
virtual void StreamIntoFile(CDefinitionContext& rcontext, std::ofstream& rfstream) override;
/**
* @brief Stream the include section for the file. Overload of CDefinitionGeneratorBase::StreamIncludeSection.
* @param[in, out] rcontext Reference to the stream context to stream into.
*/
virtual void StreamIncludeSection(CDefinitionContext& rcontext) override;
/**
* @brief Stream the meta entity. Overload of CDefinitionGeneratorBase::StreamMetaEntity.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the interface of the meta entity.
*/
virtual void StreamMetaEntity(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity) override;
/**
* @brief Compound comment enumerator
*/
enum class ECommentGroup { none, begin, end };
/**
* @brief Stream preceding comments if there are any.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] eGroup Defines whether the comment groups several statements or comments a single statement.
*/
void StreamComments(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity,
ECommentGroup eGroup = ECommentGroup::none);
/**
* @brief Stream declaration if the entity is a declaration. Overload of CDefinitionGeneratorBase::StreamDeclaration.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @return Returns true when the streaming was successful or false when streaming was not successful and should be canceled.
*/
virtual bool StreamDeclaration(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity) override;
/**
* @brief Stream definition if the entity is a definition. Overload of CDefinitionGeneratorBase::StreamDefinition.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] bInline When set the definition is part of a declaration.
* @param[in] bAnonymousDecl When set, the definition is part of an anonymous declaration (only valid for unions).
*/
virtual void StreamDefinition(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity, bool bInline = false,
bool bAnonymousDecl = false) override;
/**
* @brief Stream typedef declaration if the entity is a typedef.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamTypedef(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream attribute declaration if the entity is an attribute.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @details Attributes are implemented as getter- and setter-functions.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamAttribute(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream operation declaration if the entity is an operation.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamOperation(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream parameter declaration if the entity is a parameter.
* @details Stream parameter declarations. Input parameters are provided by-value unless the parameter is a complex parameter
* (a struct, union, string, pointer, sequence, map or an array); they are provided by-reference (const). Interfaces are
* provided by C/C++ pointer. Output parameters are always provided by reference. Pointers are defined in IDL as boundless
* arrays (var[]) and are implemented using a smart-pointer class (hence a complex parameter). Fixed-bound arrays are provided
* as C-arrays. Dynamic-bound arrays (arrays that have alength defined through a variable) are available only when the length
* is provided as an input parameter and the variable itself is allocated on input (hence either an input parameter or an in-
* and output parameter). In case dynamic bound arrays are required as output parameter, use a sequence instead.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] bInitial When set, this is the first parameter of an operation.
*/
void StreamParameter(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity, bool bInitial);
/**
* @brief Stream enum entry declaration if the entity is an enum entry.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamEnumEntry(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream case entry declaration if the entity is an case entry.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamCaseEntry(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream the declaration type string.
* details The stream is created inline. In case the declaration contains an anonymous definition, the definition is inserted
* as well (hence the use of indentation).
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the declaration entity.
* @param[in] rbDefinitionStreamed When set, a definition was streamed and a newline should be inserted before the next
* declaration.
* @param[in] bAnonymousDecl When set, the definition is part of an anonymous declaration (only valid for unions).
* @param[in] bSkipInitialIndent When set, do not insert an additional indentation before the declaration of the type.
* @return Returns whether the declaration type was streamed or whether the type was unknown and could not be streamed.
*/
bool StreamDeclType(CDefinitionContext& rcontext, sdv::IInterfaceAccess* pEntity, bool& rbDefinitionStreamed,
bool bAnonymousDecl = false, bool bSkipInitialIndent = true);
/**
* @brief For a switch variable, process the joint container of both switch variable and union. Start with the highest parent
* running through all children. Overload of CDefinitionGeneratorBase::ProcessUnionJointContainerForSwitchVar.
* @param[in, out] rcontext Reference to the definition stream context of the switch variable to stream into.
* @param[in] pSwitchVarEntity Interface to the switch var declaration.
* @param[in] pContainerEntity Interface to the container definition.
*/
virtual void ProcessUnionJointContainerForSwitchVar(CDefinitionContext& rcontext,
sdv::IInterfaceAccess* pSwitchVarEntity, sdv::IInterfaceAccess* pContainerEntity) override;
/**
* @brief Process the union member that, together with the switch variable, has a mutual container from the entity in the
* context. Overload of CDefinitionGeneratorBase::ProcessUnionInContainerContext.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] rssMemberScopeUnionDecl Reference to the member scope of the union declaration (could be empty when the union
* switch is not variable based).
* @param[in] rssMemberScopeSwitchVar Reference to the member scope of the switch variable (could be empty when the union
* switch is not variable based).
* @param[in] pUnionDef Pointer to the union definition entity.
* @param[in] rvecArrayIndices Reference to the vector containing the array indices of the declaration to use for the detection.
* If the declaration is not declared as array, the vector should be empty. If the declaration is declared as an array and the
* amount of dimensions is below the amount of dimensions within the provided vector, the detection function is called for each
* array dimension extending the vector with the index to do the detection for.
*/
virtual void ProcessUnionInContainerContext(CDefinitionContext& rcontext, std::string rssMemberScopeUnionDecl,
std::string rssMemberScopeSwitchVar, sdv::IInterfaceAccess* pUnionDef,
const std::vector<SArrayIterationInfo>& rvecArrayIndices = std::vector<SArrayIterationInfo>()) override;
std::set<std::string> m_setHistory; ///< Set with a history of all added entity definitions.
std::set<std::string> m_setForwardDecl; ///< Set with with forward declared structure definitions.
};
#endif // !defined(DEFINITION_GENERATOR_H)

View File

@@ -0,0 +1,505 @@
#ifndef DEFINITION_GENERATOR_BASE_H
#define DEFINITION_GENERATOR_BASE_H
#include "context.h"
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <list>
/**
* @brief Multiple unions can be switched using one switch variable. The switch functions are implemented in the struct or
* exception containing the switch variable. This struct collects the switch information globally to allow the variable to be
* used in a switch case even if the union is several layers deep in the child hierarchy.
*/
struct SSwitchVarContext
{
sdv::IInterfaceAccess* pVarEntity = nullptr; ///< The switch variable entity pointer.
std::string ssType; ///< Switch var type
std::string ssName; ///< Switch var name
std::string ssScopedName; ///< Scoped name of the switch
std::vector<std::string> vecUnionDecl; ///< Vector containing the union names to switch for.
};
/**
* @brief Array iteration information contains the variable that is used for iteration and the array dimension expression to
* determine the upper boundary.
*/
struct SArrayIterationInfo
{
std::string ssArrayIterator; ///< The name of the variable used for the array iteration.
std::string ssCountExpression; ///< The expression used to identify the maximum array elements.
};
/**
* @brief Switch code context to be processed in the joined parent of both the union with variable based switch and the
* switch variable.
*/
struct SSwitchCodeContext
{
std::shared_ptr<SSwitchVarContext> ptrSwitchVar; ///< The switch variable context
std::string ssSwitchVarName; ///< Exact statement of the switch var as scoped member
///< relative to the joint container of both union and switch
///< variable.
std::string ssSwitchValue; ///< The first switch value (if available).
std::vector<SArrayIterationInfo> vecArrayIterationInfo; ///< The iteration information about any array of
///< declarations for the structures holding unions or for
///< unions themselves.
};
/**
* @brief Definition stream context.
* @tparam TDerivedContext The derived context class. Must be deriving from this class.
*/
template <typename TDerivedContext>
class CDefEntityContext
{
public:
// Forward declaration
struct SIterator;
/// Allow the iterator structure to access member variables.
friend SIterator;
/**
* @brief Constructor assigning the generator context.
* @param[in] rContext Reference to the context to assign.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
*/
CDefEntityContext(const CGenContext& rContext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Copy constructor assigning a new definition entity.
* @param[in] rcontext Original context to copy from.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
*/
CDefEntityContext(CDefEntityContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Virtual destructor allowing the destruction of derived class members as well.
*/
virtual ~CDefEntityContext();
/**
* @brief Join a context into this context.
* @param[in] rContext Reference to the context to join.
* @return Reference to this context containing the joined result.
*/
virtual TDerivedContext& operator<<(const TDerivedContext& rContext);
/**
* @brief Return the scope of the members of the definition entity (which is the scoped name of the definition).
* @return The scope if existing or empty if not.
*/
std::string GetScope() const;
/**
* @brief Current scope part of compound structure?
* @return Returns whether the current structure is part of a compound structure.
*/
bool IsCompound() const;
/**
* @brief Is this definition structural (struct, exception, union)?
* @return Returns whether the definition is structural.
*/
bool IsStructural() const;
/**
* @brief Get the stored indentation.
* @param[in] bDefBody When set, the indentation is for the definition body, keeping the deep indentation flag in consideration.
* @param[in] bFuncImpl When set, the indentation is for the function implementation, increasing the indentation.
* @return The current indentation.
*/
std::string GetIndent(bool bDefBody = true, bool bFuncImpl = false) const;
/**
* @brief Enable (if not enabled) and increase the indentation.
*/
void IncrIndent();
/**
* @brief Enable (if not enabled) and decrease the indentation (if possible).
*/
void DecrIndent();
/**
* @brief Disable the indentation if enabled.
*/
void DisableIndent();
/**
* @brief Enable the indentation if disabled.
*/
void EnableIndent();
/**
* @brief Enable deep indentation (one more indentation in definition part).
*/
void EnableDeepIndent();
/**
* @brief Get the interface to the definition entity.
* @return The interface to the definition or NULL when the context is representing the root definition.
*/
sdv::IInterfaceAccess* GetDefEntity() const;
/**
* @brief Templated function for getting an interface to the definition entity.
* @tparam TInterface The interface to get.
* @return Pointer to the interface or NULL when the definition is not available or doesn#t expose the interface.
*/
template <typename TInterface>
TInterface* GetDefEntity() const;
/**
* @brief Iterator structure (used for entity iteration).
*/
struct SIterator
{
/// The context class is allowed to access content directly.
friend CDefEntityContext<TDerivedContext>;
private:
/**
* @brief Constructor
* @param[in] rContextParam Reference to the entity context that holds the iterator list.
*/
SIterator(CDefEntityContext<TDerivedContext>& rContextParam);
public:
/**
* @brief No copy constructor
* @param[in] rsIterator Reference to the itertor to copy from.
*/
SIterator(const SIterator& rsIterator) = delete;
/**
* @brief Move constructor
* @param[in] rsIterator Reference to the itertor to move from.
*/
SIterator(SIterator&& rsIterator);
/**
* @brief Destructor
*/
~SIterator();
/**
* @brief Releases the iterator.
*/
void Release();
/**
* @brief Increase the iteration value by 1.
* @return Returns reference to the iterator object after incrementation.
*/
SIterator& operator++();
/**
* @brief Increase the iteration value by 1.
* @param[in] iVal Value is ignored.
* @return Returns the iteration value before incrementation.
*/
uint32_t operator++(int iVal);
/**
* @brief Get the current iteration value.
* @return The iteration index.
*/
operator uint32_t() const;
private:
CDefEntityContext<TDerivedContext>& rContext; ///< Reference to the entity context holding the iterator list.
bool bValid = false; ///< The iterator is only valid when set.
typename std::list<uint32_t>::iterator itPos{}; ///< Iterator position in the context iteration object list.
};
/**
* @brief Create a new iterator object and make it current.
* @remarks The iterator object is deleted automatically when out of scope or when explicitly triggered to release the iterator.
* @return The iterator object.
*/
SIterator CreateIterator();
/**
* @brief Get the iteration value of the current iterator.
* @return The value of the current iteration or 0 when no iterator was created.
*/
uint32_t GetCurrentIteration();
/**
* @brief Assign a switch variable context to the definition containing the switch variable.
* @param[in] rptrSwitchVarContext Reference to the smart pointer holding the context structure for the switch variable.
*/
void AssignSwitchVarContext(const std::shared_ptr<SSwitchVarContext>& rptrSwitchVarContext);
/**
* @brief Create or get a switch code context for the switch variable supplied.
* @tparam TSwitchCodeContext Type of switch code context structure. Must derive from SSwitchCodeContext.
* @param[in] rssSwitchVarName Reference to the scoped member name of the switch variable including array brackets.
* @param[in] rptrSwitchVar Reference to the smart pointer holding the switch variable context.
* @param[in] rvecArrayIndices Reference to the iterator information of any arrays being part of the switch variable name.
* @return Returns a shared pointer to an existing or a new switch code context.
*/
template <typename TSwitchCodeContext = SSwitchCodeContext>
std::shared_ptr<TSwitchCodeContext> GetOrCreateSwitchCodeContext(const std::string& rssSwitchVarName,
const std::shared_ptr<SSwitchVarContext>& rptrSwitchVar, const std::vector<SArrayIterationInfo>& rvecArrayIndices);
/**
* @brief Are multiple switch code contexts available?
* @return Returns whether more than one switch code contexts are available.
*/
bool HasMultipleSwitchCodeContexts() const;
/**
* @brief Get a vector with all the switch code contexts.
* @tparam TSwitchCodeContext Type of switch code context structure. Must derive from SSwitchCodeContext.
* @param[in] rssScopedSwitchVar Reference to the string containing the scoped variable name that should be used as a filter. If
* not set, all contexts are returned.
* @return Returns a vector with the stored switch code contexts.
*/
template <typename TSwitchCodeContext = SSwitchCodeContext>
std::vector<std::shared_ptr<TSwitchCodeContext>> GetSwitchCodeContexts(
const std::string& rssScopedSwitchVar = std::string()) const;
private:
/**
* @brief Create an iterator object and return the current position to the object.
* @return The iterator position in the iterator list.
*/
std::list<uint32_t>::iterator CreateIteratorObject();
/**
* @brief Remove the iterator object from the iterator list.
* @remarks This function is not protected by providing faulty positions.
* @param[in] itPos Iterator position in the iterator list.
*/
void RemoveIteratorObject(std::list<uint32_t>::iterator itPos);
const CGenContext& m_rGenContext; ///< Reference to te generator context.
sdv::IInterfaceAccess* m_pDefEntity = nullptr; ///< The definition entity that defines this context.
std::string m_ssIndent; ///< Current indentation for definition body (needs to be indented once more
///< for constructor and destructor implementations).
std::string m_ssIndentBackup; ///< Stored indent for disabled indentation support.
bool m_bDeepDefIndent = false; ///< When set, the definitions are one level deeper than the provided
///< indentation. This doesn't count for the functions. The boolean is
///< needed when the definition is implemented using two levels of
///< definitions, as is the case with unions using a type based switch.
uint32_t m_uiItIdx = 0; ///< Current iteration index during iteration.
/// Contained switch var contexts in this definition.
std::vector<std::shared_ptr<SSwitchVarContext>> m_vecSwitchVars;
/// Switch code implemented in this definition entity.
using TSwitchCodeMap = std::map<std::string, std::shared_ptr<SSwitchCodeContext>>;
/// Shareable switch code map.
std::shared_ptr<TSwitchCodeMap> m_ptrSwitchCodeMap;
/// List with iterators. The bottom iterator (latest added) is the current iterator.
std::list<uint32_t> m_lstIterators;
};
/**
* @brief Definition code generator base.
* @tparam TDefEntityContext Type of definition entity context to use. Must derive from CDefEntityContext.
*/
template <typename TDefEntityContext>
class CDefinitionGeneratorBase : public CGenContext
{
static_assert(std::is_base_of_v<CDefEntityContext<TDefEntityContext>, TDefEntityContext>);
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CDefinitionGeneratorBase(sdv::IInterfaceAccess* pParser);
/**
* @brief Generate the definition code.
* @return Returns whether generation was successful.
*/
virtual bool Generate();
protected:
/**
* @brief Return the information for target file creation.
* @param[out] rssTargetSubDir Reference to the string containing the target sub-directory to be added to the output directory.
* Could be empty to target the output directory.
* @param[out] rssTargetFileEnding Reference to string containing the file ending (file name and extension) to be placed at the
* end of the source file name replacing the extension.
*/
virtual void GetTargetFileInfo(std::string& rssTargetSubDir, std::string& rssTargetFileEnding) = 0;
/**
* @brief Return the file header text for automatic file generation.
* @return The header text to place into the file.
*/
virtual std::string GetFileHeaderText() const = 0;
/**
* @brief Stream the code into the file. Called once after processing.
* @param[in, out] rcontext Reference to the stream context.
* @param[in, out] rfstream Reference to the file stream to stream into
*/
virtual void StreamIntoFile(TDefEntityContext& rcontext, std::ofstream& rfstream);
/**
* @brief Stream the include section for the file.
* @param[in, out] rcontext Reference to the stream context to stream into.
*/
virtual void StreamIncludeSection(TDefEntityContext& rcontext);
/**
* @brief Process the entities.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pIterator Pointer to the iterator interface.
* @return Returns true when the streaming of declarations was successful or false when streaming of declarations was not
* successful and should be canceled.
*/
virtual bool ProcessEntities(TDefEntityContext& rcontext, sdv::idl::IEntityIterator* pIterator);
/**
* @brief Stream the meta entity.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the interface of the meta entity.
*/
virtual void StreamMetaEntity(TDefEntityContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream declaration if the entity is a declaration.
* @param[in, out] rcontext Reference to the stream context.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @return Returns true when the streaming was successful or false when streaming was not successful and should be canceled.
*/
virtual bool StreamDeclaration(TDefEntityContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream definition if the entity is a definition.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] bInline When set the definition is part of a declaration.
* @param[in] bAnonymousDecl When set, the definition is part of an anonymous declaration (only valid for unions).
*/
virtual void StreamDefinition(TDefEntityContext& rcontext, sdv::IInterfaceAccess* pEntity, bool bInline = false,
bool bAnonymousDecl = false);
/**
* @brief Check for the existence of the switch variable and add the variable if not existing.
* @param[in] pSwitchVarEntity Interface pointer to the switch variable entity.
* @return Smart pointer to the switch variable.
*/
std::shared_ptr<SSwitchVarContext> GetOrCreateVarBasedSwitch(sdv::IInterfaceAccess* pSwitchVarEntity);
/**
* @brief Detect a declaration of a union using a variable based switch case. If the switch case variable is within the scope
* of the provided context, stream the functions needed to initialize and use the switch case. If the declaration is not a
* fitting union but is of a compound structure (struct, exception or union), go through the declaration members for further
* detection.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] rssMemberScope Reference to the string containing the declarative member scope. Each declaration is separated by
* a dot separator.
* @param[in] pDeclEntity Interface pointer to the declarative entity to check.
* @param[in] rvecArrayIndices Reference to the vector containing the array indices of the declaration to use for the detection.
* If the declaration is not declared as array, the vector should be empty. If the declaration is declared as an array and the
* amount of dimensions is below the amount of dimensions within the provided vector, the detection function is called for each
* array dimension extending the vector with the index to do the detection for.
*/
virtual void DetectUnionContainerForProcessing(TDefEntityContext& rcontext, const std::string& rssMemberScope,
sdv::IInterfaceAccess* pDeclEntity, const std::vector<SArrayIterationInfo>& rvecArrayIndices = {});
/**
* @brief Process the union member that, together with the switch variable, has a mutual container from the entity in the
* context.
* @details Union definitions and declarations are to be treated differently, dependable on the switch type and the way of the
* integration. The following differences are to be distingueshed:
* - Unions can be defined as named or as unnamed unions. Unnamed unions can only occur when followed by a declaration. They
* cannot be declared at global level due to the missing possibility to initialize/uninitialize using a member
* constructor/destructor.
* - Union declarations can be explicit or anonymous (not existing, but due to the unnamed nature of the union implicitly
* present). Anonymous declaration only occur for unnamed unions and are not allowed at root level. For named unions,
* there are no anonymous declarations.
*
* The following table defines the different types:
* +------------------+---------------------------------------------------------------------+---------------------------------------------------------------------+
* | | switch type base | switch var based |
* | +----------------------------------+----------------------------------+----------------------------------+----------------------------------+
* | | named | unnamed | named | unnamed |
* | +----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | | explicit decl. | anonymous decl. | explicit decl. | anonymous decl. | explicit decl. | anonymous decl. | explicit decl. | anonymous decl. |
* +==================+================+=================+================+=================+================+=================+================+=================+
* | definition code | Use struct to | Not existing | Use struct to | Not allowed/ | Define named | Not existing | Must be | Define unnamed |
* | | encapsulate | | encapsulate | not occurring. | union as | | followed by | union as part |
* | | switch var and | | switch var and | | member. | | decl. Cannot | of struct. |
* | | union def. | | union def. | | | | be global. | Will not be |
* | | | | Auto generate | | | | | followed by |
* | | | | struct name. | | | | | decl. |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | declaration code | Normal decl. | N.a. | Following def. | N.a. | Normal | N.a. | Following def. | Absent |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | switch variable | Part of struct | N.a. | Part of struct | N.a. | Part of | N.a. | Part of | Part of |
* | | | | | | container | | container | container |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | constructor | Part of struct | N.a. | Part of struct | N.a. | Part of | N.a. | Part of | Part of |
* | | | | | | container | | container | container |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | destructor | Part of struct | N.a. | Part of struct | N.a. | Part of | N.a. | Part of | Part of |
* | | | | | | container | | container | container |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | switch function | Part of struct | N.a. | Part of struct | N.a. | Part of | N.a. | Part of | Part of |
* | | | | | | container | | container | container |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
* | element access | Internal | N.a. | Internal | N.a. | Over member | N.a. | Over member | Direct access |
* | | | | | | var | | var | to elements |
* +------------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+----------------+-----------------+
*
* In case of a switch case based on a variable, this variable might be defined in a sub-structure of a mutual container of
* a union. The union content depends on the switch variable. Both need to be processed together in the same context of one of
* the containers.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] rssMemberScopeUnionDecl Reference to the member scope of the union declaration (could be empty when the union
* switch is not variable based).
* @param[in] rssMemberScopeSwitchVar Reference to the member scope of the switch variable (could be empty when the union
* switch is not variable based).
* @param[in] pUnionDef Pointer to the union definition entity.
* @param[in] rvecArrayIndices Reference to the vector containing the array indices of the declaration to use for the detection.
* If the declaration is not declared as array, the vector should be empty. If the declaration is declared as an array and the
* amount of dimensions is below the amount of dimensions within the provided vector, the detection function is called for each
* array dimension extending the vector with the index to do the detection for.
*/
virtual void ProcessUnionInContainerContext(TDefEntityContext& rcontext, std::string rssMemberScopeUnionDecl,
std::string rssMemberScopeSwitchVar, sdv::IInterfaceAccess* pUnionDef,
const std::vector<SArrayIterationInfo>& rvecArrayIndices = std::vector<SArrayIterationInfo>());
/**
* @brief For a switch variable, detect the joint container of both switch variable and union. Start with the highest parent
* running through all children.
* @param[in, out] rcontext Reference to the definition stream context of the switch variable to stream into.
* @param[in] pSwitchVarEntity Interface to the switch var declaration.
* @param[in] pEntity Interface to the definition to detect for the container.
*/
void DetectUnionJointContainerForSwitchVar(TDefEntityContext& rcontext, sdv::IInterfaceAccess* pSwitchVarEntity,
sdv::IInterfaceAccess* pEntity);
/**
* @brief For a switch variable, process the joint container of both switch variable and union. Start with the highest parent
* running through all children.
* @param[in, out] rcontext Reference to the definition stream context of the switch variable to stream into.
* @param[in] pSwitchVarEntity Interface to the switch var declaration.
* @param[in] pContainerEntity Interface to the container definition.
*/
virtual void ProcessUnionJointContainerForSwitchVar(TDefEntityContext& rcontext, sdv::IInterfaceAccess* pSwitchVarEntity,
sdv::IInterfaceAccess* pContainerEntity);
private:
/// Map with union switch variables. The switch variable scoped name is the key for the map.
std::map<std::string, std::shared_ptr<SSwitchVarContext>> m_mapSwitchFunc;
};
// Include the code as well
#include "definition_generator_base.inl"
#endif // !defined DEFINITION_GENERATOR_BASE_H

View File

@@ -0,0 +1,655 @@
#ifndef DEFINITION_GENERATOR_BASE_INL
#define DEFINITION_GENERATOR_BASE_INL
#ifndef DEFINITION_GENERATOR_BASE_H
#error Do not include this file directly. Include "definition_generator_base.h" instead.
#endif
#include "../exception.h"
#include <filesystem>
#include <thread>
#include <fstream>
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::CDefEntityContext(const CGenContext& rContext, sdv::IInterfaceAccess* pEntity) :
m_rGenContext(rContext), m_pDefEntity(pEntity), m_ptrSwitchCodeMap(std::make_shared<TSwitchCodeMap>())
{
static_assert(std::is_base_of_v<CDefEntityContext, TDerivedContext>);
}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::CDefEntityContext(CDefEntityContext& rcontext, sdv::IInterfaceAccess* pEntity) :
m_rGenContext(rcontext.m_rGenContext), m_pDefEntity(pEntity), m_ssIndent(rcontext.m_ssIndent),
m_ptrSwitchCodeMap(pEntity == rcontext.m_pDefEntity ? rcontext.m_ptrSwitchCodeMap : std::make_shared<TSwitchCodeMap>())
{}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::~CDefEntityContext()
{}
template <typename TDerivedContext>
TDerivedContext& CDefEntityContext<TDerivedContext>::operator<<(const TDerivedContext& /*rContext*/)
{
return static_cast<TDerivedContext&>(*this);
}
template <typename TDerivedContext>
inline std::string CDefEntityContext<TDerivedContext>::GetScope() const
{
if (!m_pDefEntity) return {};
const sdv::idl::IEntityInfo* pEntityInfo = m_pDefEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pEntityInfo) return {};
return pEntityInfo->GetScopedName();
}
template <typename TDerivedContext>
inline bool CDefEntityContext<TDerivedContext>::IsCompound() const
{
if (!m_pDefEntity) return false;
const sdv::idl::IEntityInfo* pEntityInfo = m_pDefEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pEntityInfo) return false;
return pEntityInfo->GetType() != sdv::idl::EEntityType::type_module;
}
template <typename TDerivedContext>
inline bool CDefEntityContext<TDerivedContext>::IsStructural() const
{
const sdv::idl::IEntityInfo* pEntityInfo = m_rGenContext.GetInterface<sdv::idl::IEntityInfo>(m_pDefEntity);
if (!pEntityInfo) return false;
switch (pEntityInfo->GetType())
{
case sdv::idl::EEntityType::type_struct:
case sdv::idl::EEntityType::type_union:
case sdv::idl::EEntityType::type_exception:
return true;
default:
return false;
}
}
template <typename TDerivedContext>
inline std::string CDefEntityContext<TDerivedContext>::GetIndent(bool bDefBody /*= true*/, bool bFuncImpl /*= false*/) const
{
return m_ssIndent + (((bDefBody && m_bDeepDefIndent) || bFuncImpl) ? m_rGenContext.GetIndentChars() : "");
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::IncrIndent()
{
EnableIndent();
m_ssIndent += m_rGenContext.GetIndentChars();
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::DecrIndent()
{
EnableIndent();
m_ssIndent.resize(m_ssIndent.size() - m_rGenContext.GetIndentChars().size());
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::DisableIndent()
{
if (!m_ssIndent.empty())
{
m_ssIndentBackup = m_ssIndent;
m_ssIndent.clear();
}
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::EnableIndent()
{
if (!m_ssIndentBackup.empty())
{
m_ssIndent = m_ssIndentBackup;
m_ssIndentBackup.clear();
}
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::EnableDeepIndent()
{
m_bDeepDefIndent = true;
}
template <typename TDerivedContext>
inline sdv::IInterfaceAccess* CDefEntityContext<TDerivedContext>::GetDefEntity() const
{
return m_pDefEntity;
}
template <typename TDerivedContext>
template <typename TInterface>
inline TInterface* CDefEntityContext<TDerivedContext>::GetDefEntity() const
{
return m_rGenContext.GetInterface<TInterface>(m_pDefEntity);
}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::SIterator::SIterator(CDefEntityContext<TDerivedContext>& rContextParam) :
rContext(rContextParam), bValid(true), itPos(rContextParam.CreateIteratorObject())
{}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::SIterator::SIterator(SIterator&& rsIterator) :
rContext(rsIterator.rContext), itPos(rsIterator.itPos), bValid(rsIterator.bValid)
{
// The iterator that was moved from is not valid any more.
rsIterator.bValid = false;
}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::SIterator::~SIterator()
{
Release();
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::SIterator::Release()
{
if (!bValid) return;
rContext.RemoveIteratorObject(itPos);
bValid = false;
}
template <typename TDerivedContext>
inline typename CDefEntityContext<TDerivedContext>::SIterator& CDefEntityContext<TDerivedContext>::SIterator::operator++()
{
if (bValid) (*itPos)++;
return *this;
}
template <typename TDerivedContext>
inline uint32_t CDefEntityContext<TDerivedContext>::SIterator::operator++(int /*iVal*/)
{
if (!bValid) return 0;
uint32_t uiTemp = *itPos;
(*itPos)++;
return uiTemp;
}
template <typename TDerivedContext>
inline CDefEntityContext<TDerivedContext>::SIterator::operator uint32_t() const
{
if (!bValid) return 0;
return *itPos;
}
template <typename TDerivedContext>
inline typename CDefEntityContext<TDerivedContext>::SIterator CDefEntityContext<TDerivedContext>::CreateIterator()
{
return SIterator(*this);
}
template <typename TDerivedContext>
inline uint32_t CDefEntityContext<TDerivedContext>::GetCurrentIteration()
{
return m_lstIterators.empty() ? 0u : m_lstIterators.back();
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::AssignSwitchVarContext(const std::shared_ptr<SSwitchVarContext>& rptrSwitchVarContext)
{
m_vecSwitchVars.push_back(rptrSwitchVarContext);
}
template <typename TDerivedContext>
template <typename TSwitchCodeContext>
inline std::shared_ptr<TSwitchCodeContext> CDefEntityContext<TDerivedContext>::GetOrCreateSwitchCodeContext(const std::string& rssSwitchVarName,
const std::shared_ptr<SSwitchVarContext>& rptrSwitchVar, const std::vector<SArrayIterationInfo>& rvecArrayIndices)
{
static_assert(std::is_base_of_v<SSwitchCodeContext, TSwitchCodeContext>);
// Get the switch code map...
if (!m_ptrSwitchCodeMap) return {}; // Should not occur
auto itSwitchCodeContext = m_ptrSwitchCodeMap->find(rssSwitchVarName);
if (itSwitchCodeContext == m_ptrSwitchCodeMap->end())
{
itSwitchCodeContext = m_ptrSwitchCodeMap->emplace(rssSwitchVarName, std::make_shared<TSwitchCodeContext>()).first;
itSwitchCodeContext->second->ptrSwitchVar = rptrSwitchVar;
itSwitchCodeContext->second->ssSwitchVarName = rssSwitchVarName;
itSwitchCodeContext->second->vecArrayIterationInfo = rvecArrayIndices;
}
return std::static_pointer_cast<TSwitchCodeContext>(itSwitchCodeContext->second);
}
template <typename TDerivedContext>
inline bool CDefEntityContext<TDerivedContext>::HasMultipleSwitchCodeContexts() const
{
if (!m_ptrSwitchCodeMap) return false;
return m_ptrSwitchCodeMap->size() > 1u;
}
template <typename TDerivedContext>
template <typename TSwitchCodeContext>
inline std::vector<std::shared_ptr<TSwitchCodeContext>> CDefEntityContext<TDerivedContext>::GetSwitchCodeContexts(
const std::string& rssScopedSwitchVar /*= std::string()*/) const
{
static_assert(std::is_base_of_v<SSwitchCodeContext, TSwitchCodeContext>);
if (!m_ptrSwitchCodeMap) return {};
std::vector<std::shared_ptr<TSwitchCodeContext>> vecSwitchCodeContexts;
for (const auto& rptrSwitchCodeContext : *m_ptrSwitchCodeMap)
{
if (!rssScopedSwitchVar.empty() && rssScopedSwitchVar != rptrSwitchCodeContext.second->ptrSwitchVar->ssScopedName) continue;
vecSwitchCodeContexts.push_back(std::static_pointer_cast<TSwitchCodeContext>(rptrSwitchCodeContext.second));
}
return vecSwitchCodeContexts;
}
template <typename TDerivedContext>
inline std::list<uint32_t>::iterator CDefEntityContext<TDerivedContext>::CreateIteratorObject()
{
return m_lstIterators.insert(m_lstIterators.end(), 0);
}
template <typename TDerivedContext>
inline void CDefEntityContext<TDerivedContext>::RemoveIteratorObject(std::list<uint32_t>::iterator itPos)
{
m_lstIterators.erase(itPos);
}
template <typename TDefEntityContext>
inline CDefinitionGeneratorBase<TDefEntityContext>::CDefinitionGeneratorBase(sdv::IInterfaceAccess* pParser) : CGenContext(pParser)
{}
template <typename TDefEntityContext>
inline bool CDefinitionGeneratorBase<TDefEntityContext>::Generate()
{
// Get target file information for directory and file creation.
std::string ssTargetSubDir;
std::string ssTargetFileEnding;
GetTargetFileInfo(ssTargetSubDir, ssTargetFileEnding);
// Create target directory if it doesn't exist. Since race conditions could exist due to parallel processing, do this
// up to five times before reporting an error.
std::filesystem::path pathTargetDir = GetOutputDir();
if (!ssTargetSubDir.empty()) pathTargetDir /= ssTargetSubDir;
for (size_t nCnt = 0; nCnt < 5; nCnt++)
{
if (!std::filesystem::exists(pathTargetDir))
std::filesystem::create_directories(pathTargetDir);
else
break;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
if (!std::filesystem::exists(GetOutputDir()))
throw CCompileException("Cannot create output directory: ", pathTargetDir.generic_u8string());
// Replace the extension by the new file ending;
std::filesystem::path pathFile = pathTargetDir / GetSource().filename();
pathFile.replace_extension("");
pathFile += ssTargetFileEnding;
if (g_log_control.GetVerbosityMode() != EVerbosityMode::report_all)
std::cout << "Target file: " << pathFile.generic_u8string() << std::endl;
// Open the file for writing
std::ofstream streamDefFile;
streamDefFile.open(pathFile);
if (!streamDefFile.is_open()) throw CCompileException("Failed to open the target file: ", pathFile.generic_u8string());
// Add file header
streamDefFile << Header(pathFile, GetFileHeaderText());
// Add safeguard
streamDefFile << Safeguard(pathFile, true);
// Include headers
TDefEntityContext sStreamContext(*this, GetParser());
StreamIncludeSection(sStreamContext);
// Run through the entities and process the entities...
sdv::idl::IDefinitionEntity* pDefinition = GetInterface<sdv::idl::IDefinitionEntity>(GetParser());
if (!pDefinition) throw CCompileException("Internal error: the parser doesn't have a root definition.");
sdv::idl::IEntityIterator* pIterator = pDefinition->GetChildren();
if (!pIterator) throw CCompileException("Internal error: the parser doesn't support entity iteration.");
ProcessEntities(sStreamContext, pIterator);
// Stream the result into the file
StreamIntoFile(sStreamContext, streamDefFile);
// End of safeguard
streamDefFile << Safeguard(pathFile, false);
// Finalize the stream
streamDefFile.close();
return true;
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::StreamIntoFile(TDefEntityContext& /*rcontext*/,
std::ofstream& /*rfstream*/) {}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::StreamIncludeSection(TDefEntityContext& /*rcontext*/)
{}
template <typename TDefEntityContext>
inline bool CDefinitionGeneratorBase<TDefEntityContext>::ProcessEntities(TDefEntityContext& rcontext,
sdv::idl::IEntityIterator* pIterator)
{
if (!pIterator) throw CCompileException("Internal error: processing entities without iterator.");
bool bStreamDeclSuccess = true;
// Do detection first...
for (auto sIterator = rcontext.CreateIterator(); sIterator < pIterator->GetCount(); ++sIterator)
{
// Get the entity
sdv::IInterfaceAccess* pEntity = pIterator->GetEntityByIndex(sIterator);
if (!pEntity) throw CCompileException("Internal error: processing non-existent entity.");
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
const sdv::idl::IEntityContext* pContext = GetInterface<sdv::idl::IEntityContext>(pEntity);
if (!pContext) throw CCompileException("Internal error: the entity doesn't expose context information.");
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pEntity);
// Only process entities in the source code
if (pContext->GetLocation() != sdv::idl::IEntityContext::ELocation::source)
continue;
// Check whether the entity has a name.
if (pEntityInfo->GetName().empty())
throw CCompileException("Internal error: the entity doesn't have a name.");
if (pDeclaration) // Handle declarations
{
// Create a switch variable if not already available
if (pEntityInfo->GetType() == sdv::idl::EEntityType::type_switch_variable)
{
rcontext.AssignSwitchVarContext(GetOrCreateVarBasedSwitch(pEntity));
// Detect the container for the switch variable and the union using the variable.
sdv::IInterfaceAccess* pOldestContainer = pEntity;
while (true)
{
sdv::idl::IEntityInfo* pHighestContainerEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pOldestContainer);
sdv::IInterfaceAccess* pContainerEntity = pHighestContainerEntityInfo->GetParent();
const sdv::idl::IEntityInfo* pContainerEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pContainerEntity);
if (!pContainerEntityInfo) break;
pOldestContainer = pContainerEntity;
}
DetectUnionJointContainerForSwitchVar(rcontext, pEntity, pOldestContainer);
}
// If a declaration is a compound type and has declarations of unions that use switch case variables that are within the
// scope of the definition stream context provided to this function, add the switch functions to the definition.
DetectUnionContainerForProcessing(rcontext, pDeclaration->IsAnonymous() ? "" : pEntityInfo->GetName(), pEntity);
}
}
// Do the processing...
for (auto sIterator = rcontext.CreateIterator(); sIterator < pIterator->GetCount(); ++sIterator)
{
// Get the entity
sdv::IInterfaceAccess* pEntity = pIterator->GetEntityByIndex(sIterator);
if (!pEntity) throw CCompileException("Internal error: processing non-existent entity.");
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
const sdv::idl::IEntityContext* pContext = GetInterface<sdv::idl::IEntityContext>(pEntity);
if (!pContext) throw CCompileException("Internal error: the entity doesn't expose context information.");
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pEntity);
// Only process entities in the source code
if (pContext->GetLocation() != sdv::idl::IEntityContext::ELocation::source)
continue;
// Check whether the entity has a name.
if (pEntityInfo->GetName().empty())
throw CCompileException("Internal error: the entity doesn't have a name.");
// Process the entity
const sdv::idl::IMetaEntity* pMeta = GetInterface<sdv::idl::IMetaEntity>(pEntity);
if (pMeta) // Handle meta data
{
// Stream the meta entity.
StreamMetaEntity(rcontext, pEntity);
}
else if (pDeclaration) // Handle declarations
{
// Skip streaming of declarations when one declaration was already non-streamable
if (!bStreamDeclSuccess) continue;
// Stream the declaration
bStreamDeclSuccess &= StreamDeclaration(rcontext, pEntity);
}
else // Handle definitions
StreamDefinition(rcontext, pEntity);
}
return bStreamDeclSuccess;
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::StreamMetaEntity(TDefEntityContext& /*rcontext*/,
sdv::IInterfaceAccess* /*pEntity*/)
{}
template <typename TDefEntityContext>
inline bool CDefinitionGeneratorBase<TDefEntityContext>::StreamDeclaration(TDefEntityContext& /*rcontext*/,
sdv::IInterfaceAccess* /*pEntity*/)
{
return false;
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::StreamDefinition(TDefEntityContext& /*rcontext*/,
sdv::IInterfaceAccess* /*pEntity*/, bool /*bInline = false*/, bool /*bAnonymousDecl = false*/)
{
}
template <typename TDefEntityContext>
inline std::shared_ptr<SSwitchVarContext> CDefinitionGeneratorBase<TDefEntityContext>::GetOrCreateVarBasedSwitch(
sdv::IInterfaceAccess* pSwitchVarEntity)
{
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pSwitchVarEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
// Check for the existence of the variable
auto itSwitchVar = m_mapSwitchFunc.find(pEntityInfo->GetScopedName());
if (itSwitchVar != m_mapSwitchFunc.end()) return itSwitchVar->second;
// Get variable information
auto ptrSwitchVar = std::make_shared<SSwitchVarContext>();
ptrSwitchVar->pVarEntity = pSwitchVarEntity;
ptrSwitchVar->ssScopedName = pEntityInfo->GetScopedName();
ptrSwitchVar->ssName = pEntityInfo->GetName();
size_t nPos = pEntityInfo->GetScopedName().find_last_of(".:");
std::string ssScope = pEntityInfo->GetScopedName().substr(nPos == std::string::npos ? 0 : nPos + 1);
// Get the declaration type string
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pSwitchVarEntity);
if (!pDeclaration)
throw CCompileException("Internal error: the entity is a declaration, but doesn't expose declaration information.");
if (pEntityInfo->GetType() != sdv::idl::EEntityType::type_switch_variable)
throw CCompileException("Internal error: the entity to be used as switch variable is not declared as switch variable.");
SCDeclInfo sDeclInfo = GetCDeclTypeStr(pDeclaration->GetDeclarationType(), ssScope, true);
ptrSwitchVar->ssType = sDeclInfo.ssDeclType;
// Add the switch var context to the map
m_mapSwitchFunc[pEntityInfo->GetScopedName()] = ptrSwitchVar;
// Return the result
return ptrSwitchVar;
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::DetectUnionContainerForProcessing(TDefEntityContext& rcontext,
const std::string& rssMemberScope, sdv::IInterfaceAccess* pDeclEntity,
const std::vector<SArrayIterationInfo>& rvecArrayIndices /*= {}*/)
{
// Get the declaration interface from the entity
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pDeclEntity);
if (!pDeclaration) return;
// Get the declaration type
sdv::idl::IDeclarationType* pDeclType = GetInterface<sdv::idl::IDeclarationType>(pDeclaration->GetDeclarationType());
if (!pDeclType) return;
// Get the declaration variable name.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pDeclEntity);
if (!pEntityInfo) return;
// Get the definition that belongs to this entity declaration (only entities with definitions are currently of interest).
sdv::IInterfaceAccess* pDefTypeEntity = pDeclType->GetTypeDefinition();
if (!pDefTypeEntity) return;
sdv::idl::IDefinitionEntity* pDefinition = GetInterface<sdv::idl::IDefinitionEntity>(pDefTypeEntity);
if (!pDefinition) return;
// Create the new member string
std::string ssDeclMemberScope = rssMemberScope;
// If the declaration is declared as an array, get the dimensions
std::vector<SArrayIterationInfo> vecNewInicesInfo = rvecArrayIndices;
if (pDeclaration->HasArray())
{
// Check whether iteration through each element is necessary (for each dimension of a multi-vector array).
sdv::sequence<sdv::idl::SArrayDimension> seqArrayDimensions = pDeclaration->GetArrayDimensions();
size_t nIndex = 0;
for (const sdv::idl::SArrayDimension& rsDimension : seqArrayDimensions)
{
// Create an index variable name
std::string ssIndexVarName = std::string("uiIndex_") + pEntityInfo->GetName();
if (seqArrayDimensions.size() > 1) ssIndexVarName += std::to_string(nIndex++);
vecNewInicesInfo.push_back(SArrayIterationInfo{ ssIndexVarName, rsDimension.ssExpression });
ssDeclMemberScope += std::string("[") + ssIndexVarName + "]";
}
}
// Detection in child declaration entities.
auto fnDetectInChildren = [&](sdv::idl::IDefinitionEntity* pLocalDefinition)
{
// Get the child iterator
sdv::idl::IEntityIterator* pChildIterator = pLocalDefinition->GetChildren();
if (!pChildIterator) return;
// Iterate through each child
for (uint32_t uiIndex = 0; uiIndex < pChildIterator->GetCount(); uiIndex++)
{
sdv::IInterfaceAccess* pChildEntity = pChildIterator->GetEntityByIndex(uiIndex);
const sdv::idl::IEntityInfo* pChildEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pChildEntity);
const sdv::idl::IDeclarationEntity* pChildDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pChildEntity);
if (!pChildEntity || !pChildEntityInfo || !pChildDeclaration) continue;
std::string ssChildMemberScope = ssDeclMemberScope;
if (!pChildDeclaration->IsAnonymous())
ssChildMemberScope += std::string(".") + static_cast<std::string>(pChildEntityInfo->GetName());
DetectUnionContainerForProcessing(rcontext, ssChildMemberScope, pChildEntity, vecNewInicesInfo);
}
};
// First deal with inheritance - iterate through each base type
sdv::idl::IEntityIterator* pInheritanceIterator = pDefinition->GetInheritance();
if (pInheritanceIterator)
{
for (uint32_t uiIndex = 0; uiIndex < pInheritanceIterator->GetCount(); uiIndex++)
{
sdv::idl::IDefinitionEntity* pDefinitionBase =
GetInterface<sdv::idl::IDefinitionEntity>(pInheritanceIterator->GetEntityByIndex(uiIndex));
if (!pDefinitionBase) continue;
fnDetectInChildren(pDefinitionBase);
}
}
// Further action depends on the type
switch (pDeclType->GetBaseType())
{
case sdv::idl::EDeclType::decltype_exception:
case sdv::idl::EDeclType::decltype_struct:
// Detect within the children
fnDetectInChildren(pDefinition);
return;
case sdv::idl::EDeclType::decltype_union:
// Union processing below...
break;
default:
return; // Other types don't contain unions.
}
// Union detected... check for variable based union
const sdv::idl::IUnionEntity* pUnion = GetInterface<sdv::idl::IUnionEntity>(pDefTypeEntity);
if (!pUnion || pUnion->GetSwitchInterpretation() != sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable) return;
sdv::u8string ssVarDeclName;
sdv::IInterfaceAccess* pSwitchVar = nullptr;
sdv::IInterfaceAccess* pContainer = nullptr;
pUnion->GetSwitchVar(ssVarDeclName, pSwitchVar, pContainer);
// Check the scope names for the context entity and the container of the switch. If identical, this is the context to add
// union initialization for.
const sdv::idl::IEntityInfo* pSwitchParentEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pContainer);
const sdv::idl::IEntityInfo* pDefEntityInfo = rcontext.template GetDefEntity<sdv::idl::IEntityInfo>();
if (!pSwitchParentEntityInfo || !pDefEntityInfo ||
pSwitchParentEntityInfo->GetScopedName() != pDefEntityInfo->GetScopedName())
return;
// Stream union initialization functions
ProcessUnionInContainerContext(rcontext, ssDeclMemberScope, ssVarDeclName, pDefTypeEntity, vecNewInicesInfo);
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::ProcessUnionInContainerContext(TDefEntityContext& /*rcontext*/, std::string /*rssMemberScopeUnionDecl*/,
std::string /*rssMemberScopeSwitchVar*/, sdv::IInterfaceAccess* /*pUnionDef*/,
const std::vector<SArrayIterationInfo>& /*rvecArrayIndices = std::vector<SArrayIterationInfo>()*/)
{}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::DetectUnionJointContainerForSwitchVar(TDefEntityContext& rcontext,
sdv::IInterfaceAccess* pSwitchVarEntity, sdv::IInterfaceAccess* pEntity)
{
// Check for valid definitions
sdv::idl::IEntityInfo* pDefEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
sdv::idl::IEntityInfo* pCurrentDefEntityInfo = rcontext.template GetDefEntity<sdv::idl::IEntityInfo>();
sdv::idl::IDefinitionEntity* m_pDefEntity = GetInterface<sdv::idl::IDefinitionEntity>(pEntity);
sdv::idl::IDefinitionEntity* pCurrentDefEntity = rcontext.template GetDefEntity<sdv::idl::IDefinitionEntity>();
if (!pDefEntityInfo || !pCurrentDefEntityInfo || !m_pDefEntity || !pCurrentDefEntity) return;
// Check for the current scope
std::string ssCurrentScopedDefName = pCurrentDefEntityInfo->GetScopedName();
// Run through the inherited entities and do detection.
sdv::idl::IEntityIterator* pInheritanceIterator = m_pDefEntity->GetInheritance();
if (pInheritanceIterator)
{
for (uint32_t uiIndex = 0; uiIndex < pInheritanceIterator->GetCount(); uiIndex++)
DetectUnionJointContainerForSwitchVar(rcontext, pSwitchVarEntity,
pInheritanceIterator->GetEntityByIndex(uiIndex));
}
// Detect for a union
sdv::idl::IUnionEntity* pUnion = GetInterface<sdv::idl::IUnionEntity>(pEntity);
if (pUnion && pUnion->GetSwitchInterpretation() == sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable)
{
sdv::u8string ssVarName;
sdv::IInterfaceAccess* pVarEntity = nullptr;
sdv::IInterfaceAccess* pContainerEntity = nullptr;
pUnion->GetSwitchVar(ssVarName, pVarEntity, pContainerEntity);
sdv::idl::IEntityInfo* pContainerEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pContainerEntity);
sdv::idl::IEntityInfo* pVarEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pVarEntity);
sdv::idl::IEntityInfo* pVarEntityParentInfo =
GetInterface<sdv::idl::IEntityInfo>(pVarEntityInfo ? pVarEntityInfo->GetParent() : nullptr);
if (pContainerEntityInfo && pVarEntityParentInfo && pVarEntityParentInfo->GetScopedName() == ssCurrentScopedDefName)
ProcessUnionJointContainerForSwitchVar(rcontext, pSwitchVarEntity, pContainerEntity);
}
// Run through the child entities and do detection.
sdv::idl::IEntityIterator* pChildIterator = m_pDefEntity->GetChildren();
if (pChildIterator)
{
for (uint32_t uiIndex = 0; uiIndex < pChildIterator->GetCount(); uiIndex++)
DetectUnionJointContainerForSwitchVar(rcontext, pSwitchVarEntity, pChildIterator->GetEntityByIndex(uiIndex));
}
}
template <typename TDefEntityContext>
inline void CDefinitionGeneratorBase<TDefEntityContext>::ProcessUnionJointContainerForSwitchVar(
TDefEntityContext& /*rcontext*/, sdv::IInterfaceAccess* /*pSwitchVarEntity*/,
sdv::IInterfaceAccess* /*pContainerEntity*/)
{}
#endif // !defined DEFINITION_GENERATOR_BASE_INL

View File

@@ -0,0 +1,254 @@
#include "proxy_generator.h"
#include "../exception.h"
#include <fstream>
CProxyGenerator::CProxyGenerator(sdv::IInterfaceAccess* pParser) : CPSClassGeneratorBase(pParser)
{}
CProxyGenerator::~CProxyGenerator()
{}
std::string CProxyGenerator::GetNameAppendix() const
{
return "proxy";
}
std::string CProxyGenerator::GetClassDefFileComments() const
{
return "This file contains the proxy definition for the interfaces.";
}
std::string CProxyGenerator::GetClassImplFileComments() const
{
return "This file contains the proxy implementation for the interfaces.";
}
std::string CProxyGenerator::GetClassDefBegin(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
/**
* @brief Proxy class implementation for the %interface_name%.
*/
class %class_name% : public sdv::ps::CProxyHandler<%interface_name%>, public sdv::ps::IProxyControl
{
public:
/**
* @brief Constructor
*/
%class_name%();
/**
* @brief Destructor
*/
virtual ~%class_name%() override = default;
// Object class name
DECLARE_OBJECT_CLASS_NAME("Proxy_%interface_id%")
DECLARE_OBJECT_CLASS_ALIAS("Proxy_%alias_name%")
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(sdv::ps::CProxyHandler<%interface_name%>)
SDV_INTERFACE_ENTRY(IProxyControl)
END_SDV_INTERFACE_MAP()
/**
* @brief Get the target interface from the proxy object. Overload of sdv::ps::IProxyControl::GetTargetInterface.
* @return The target interface.
*/
sdv::interface_t GetTargetInterface() override;
/**
* @brief Direct access to the target interface from the proxy object.
* @return Reference to the target interface.
*/
%interface_name%& Access();
private:
/**
* @brief Interface access implementation
*/
class CInterfaceAccess : public %interface_name%
{
public:
/**
* @brief Constructor
*/
CInterfaceAccess(%class_name%& rHandler);
/**
* @brief Destructor
*/
~CInterfaceAccess() = default;
)code";
}
std::string CProxyGenerator::GetClassDefEnd(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
private:
%class_name%& m_rHandler; ///< Proxy handler class.
};
CInterfaceAccess m_access; ///< Interface access object.
};
DEFINE_SDV_OBJECT(%class_name%)
)code";
}
std::string CProxyGenerator::GetConstructImplBegin(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
%class_name%::%class_name%() : m_access(*this)
{}
sdv::interface_t %class_name%::GetTargetInterface()
{
return &Access();
}
%interface_name%& %class_name%::Access()
{
return m_access;
}
%class_name%::CInterfaceAccess::CInterfaceAccess(%class_name%& rHandler) : m_rHandler(rHandler)
{
)code";
}
std::string CProxyGenerator::GetConstructImplEnd(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(}
)code";
}
std::string CProxyGenerator::GetConstructFuncImpl(const SFuncInfo& /*rsFunc*/, CKeywordMap& /*rmapKeywords*/) const
{
// The proxy doesn't implement construction code.
return std::string();
}
std::string CProxyGenerator::GetFuncDef(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const
{
rmapKeywords.insert(std::make_pair("func_const", rsFunc.bIsConst ? " const" : ""));
return R"code(
/** Implementation of %func_name%. */
virtual %func_decl_type% %func_name%(%param_pack_def%)%func_const% override;
)code";
}
std::string CProxyGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords, const CExceptionVector& rvecExceptions) const
{
rmapKeywords.insert(std::make_pair("func_const", rsFunc.bIsConst ? " const" : ""));
rmapKeywords.insert(std::make_pair("retval_init_comment", rsFunc.ssDecl != "void" ? R"code(
// Initialize return value)code" : ""));
rmapKeywords.insert(std::make_pair("call_return", rsFunc.nOutputParamCnt ? " = " : ""));
rmapKeywords.insert(std::make_pair("deserialize", rsFunc.nOutputParamCnt ? R"code(// Deserialize output parameters)code" : ""));
rmapKeywords.insert(std::make_pair("return_from_func", rsFunc.ssDecl != "void" ? R"code(
return return_value;)code" : ""));
std::stringstream sstreamExceptions;
sstreamExceptions << R"code(// Fire serialized exceptions caught during the call
sdv::exception_id except_id = 0;
desOutput.peek_front(except_id);
)code";
if (!rvecExceptions.empty())
sstreamExceptions << R"code(switch (except_id)
{
)code";
else
sstreamExceptions << R"code(sdv::XUnknownException exception;
exception.unknown_id = except_id;
throw exception;)code";
for (const std::string& rssException : rvecExceptions)
{
sstreamExceptions << "case sdv::GetExceptionId<" << rssException << R"code(>():
{
)code" << rssException << R"code( exception;
desOutput >> exception;
throw exception;
}
)code";
}
if (!rvecExceptions.empty())
sstreamExceptions << R"code(default:
{
sdv::XUnknownException exception;
exception.unknown_id = except_id;
throw exception;
}
})code";
rmapKeywords.insert(std::make_pair("exception_handling", sstreamExceptions.str()));
return R"code(
%func_decl_type% %class_name%::CInterfaceAccess::%func_name%(%param_pack_def%)%func_const%
{
// Clear raw data bypass (needed for streaming large data).
sdv::ps::GetRawDataBypass().clear();%retval_init_comment%%param_init%
// Serialize input parameters
sdv::serializer serInput;%stream_param_input%
// Execute a call to the interface stub.
sdv::deserializer desOutput;
sdv::ps::ECallResult eResult = m_rHandler.DoCall(%func_index%, serInput, desOutput);
if (eResult == sdv::ps::ECallResult::result_ok)
{
%deserialize%%stream_param_output%%return_from_func%
} else if (eResult == sdv::ps::ECallResult::result_exception)
{
%exception_handling%
} else
throw sdv::ps::XMarshallIntegrity();
}
)code";
}
std::string CProxyGenerator::GetFuncImplParamInit(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
return (rsParam.eDirection == SParamInfo::EDirection::ret && rsParam.bValidType) ?
R"code(
%param_decl_type% return_value = %param_default_val%;)code" : "";
}
std::string CProxyGenerator::GetFuncImplStreamParamInput(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
switch (rsParam.eDirection)
{
case SParamInfo::EDirection::inout:
case SParamInfo::EDirection::in:
return R"code(
serInput << %param_name%;)code";
break;
default:
return std::string();
break;
}
}
std::string CProxyGenerator::GetFuncImplStreamParamOutput(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
switch (rsParam.eDirection)
{
case SParamInfo::EDirection::ret:
return R"code(
desOutput >> return_value;)code";
break;
case SParamInfo::EDirection::inout:
case SParamInfo::EDirection::out:
return R"code(
desOutput >> %param_name%;)code";
break;
default:
break;
}
return std::string();
}
std::string CProxyGenerator::GetFuncImplParamTerm(const SFuncInfo& /*rsFunc*/, const SParamInfo& /*rsParam*/, CKeywordMap& /*rmapKeywords*/) const
{
return std::string();
}

View File

@@ -0,0 +1,108 @@
#ifndef PROXY_GENERATOR_H
#define PROXY_GENERATOR_H
#include "ps_class_generator_base.h"
/**
* @brief Proxy generator class.
*/
class CProxyGenerator : public CPSClassGeneratorBase
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CProxyGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CProxyGenerator() override;
private:
/**
* @brief Return the name addition to be added to the filename and class definition. Overload of
* CPSClassGeneratorBase::GetNameAppendix.
*/
virtual std::string GetNameAppendix() const override;
/**
* @brief Get definition file comments to be written in the file header. Overload of
* CPSClassGeneratorBase::GetClassDefFileComments.
*/
virtual std::string GetClassDefFileComments() const override;
/**
* @brief Get implementation file comments to be written in the file header. Overload of
* CPSClassGeneratorBase::GetClassImplFileComments.
*/
virtual std::string GetClassImplFileComments() const override;
/**
* @brief Get begin of class definition to be inserted into the header file. Overload of
* CPSClassGeneratorBase::GetClassDefBegin.
*/
virtual std::string GetClassDefBegin(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get end of class definition to be inserted into the header file. Overload of
* CPSClassGeneratorBase::GetClassDefEnd.
*/
virtual std::string GetClassDefEnd(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get begin of constructor implementation to be inserted into the cpp file. Overload of
* CPSClassGeneratorBase::GetConstructImplBegin.
*/
virtual std::string GetConstructImplBegin(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get end of constructor implementation to be inserted into the cpp file. Overload of
* CPSClassGeneratorBase::GetConstructImplEnd.
*/
virtual std::string GetConstructImplEnd(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the constructor body for a function (attribute or operation). Overload of
* CPSClassGeneratorBase::GetConstructFuncImpl.
*/
virtual std::string GetConstructFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the function definition (attribute or operation). Overload of CPSClassGeneratorBase::GetFuncDef.
*/
virtual std::string GetFuncDef(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImpl.
*/
virtual std::string GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords, const CExceptionVector& rvecExceptions) const override;
/**
* @brief Get parameter initialization of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplParamInit.
*/
virtual std::string GetFuncImplParamInit(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get input parameter streaming of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplStreamParamInput.
*/
virtual std::string GetFuncImplStreamParamInput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get output parameter streaming of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplStreamParamOutput.
*/
virtual std::string GetFuncImplStreamParamOutput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get parameter termination of the unpack portion of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplParamTerm.
*/
virtual std::string GetFuncImplParamTerm(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
};
#endif // !defined(PROXY_GENERATOR_H)

View File

@@ -0,0 +1,628 @@
#include "ps_class_generator_base.h"
#include "../exception.h"
#include <fstream>
#include <thread>
#include <chrono>
CPSClassGeneratorBase::CPSClassGeneratorBase(sdv::IInterfaceAccess* pParser) : CGenContext(pParser)
{}
bool CPSClassGeneratorBase::Generate()
{
// Create target directory if it doesn't exist. Since rqce conditions could exist due to parallel processing, do this
// five times.
std::filesystem::path pathPSTarget = GetOutputDir() / "ps";
for (size_t nCnt = 0; nCnt < 5; nCnt++)
{
if (!std::filesystem::exists(pathPSTarget))
std::filesystem::create_directories(pathPSTarget);
else
break;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
if (!std::filesystem::exists(pathPSTarget))
throw CCompileException("Cannot create proxy/stub directory: ", pathPSTarget.generic_u8string());
std::filesystem::path pathSerDesTarget = GetOutputDir() / "serdes";
for (size_t nCnt = 0; nCnt < 5; nCnt++)
{
if (!std::filesystem::exists(pathSerDesTarget))
std::filesystem::create_directories(pathSerDesTarget);
else
break;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
if (!std::filesystem::exists(pathSerDesTarget))
throw CCompileException("Cannot create serdes directory: ", pathSerDesTarget.generic_u8string());
// Add "_proxy" to the path and replace the extension by ".cpp" and ".h";
std::filesystem::path pathPSFileBase = pathPSTarget / GetSource().filename();
pathPSFileBase.replace_extension("");
std::filesystem::path pathFileNameDef = ".." / pathPSFileBase.filename();
pathFileNameDef += ".h";
pathPSFileBase += std::string("_") + GetNameAppendix();
std::filesystem::path pathFileCpp = pathPSFileBase;
pathFileCpp += ".cpp";
std::filesystem::path pathFileHdr = pathPSFileBase;
pathFileHdr += ".h";
std::filesystem::path pathSerDesFileBase = pathSerDesTarget / GetSource().filename();
pathSerDesFileBase.replace_extension("");
std::filesystem::path pathSerDesFile = pathSerDesFileBase;
pathSerDesFile += "_serdes.h";
if (g_log_control.GetVerbosityMode() == EVerbosityMode::report_all)
{
std::cout << "Target header file: " << pathFileHdr.generic_u8string() << std::endl;
std::cout << "Target source file: " << pathFileCpp.generic_u8string() << std::endl;
}
// Open the file for writing
std::ofstream streamCpp(pathFileCpp);
std::ofstream streamHdr(pathFileHdr);
// Add file headers
streamHdr << Header(pathFileHdr, GetClassDefFileComments());
streamCpp << Header(pathFileCpp, GetClassImplFileComments());
// Add safeguard
streamHdr << Safeguard(pathFileHdr, true);
// Include proxy stub base header
streamHdr << "// Proxy/stub interfaces." << std::endl;
streamHdr << "#include <interfaces/core_ps.h>" << std::endl;
streamHdr << "#include <support/pssup.h>" << std::endl;
// Include definition header in header file
streamHdr << "#include \"" << pathFileNameDef.generic_u8string() << "\"" << std::endl;
streamHdr << std::endl;
// Include definition header in cpp file
streamCpp << "#include \"" << pathFileHdr.filename().generic_u8string() << "\"" << std::endl;
// Include serdes header in cpp file
streamCpp << "#include \"../serdes/" << pathSerDesFile.filename().generic_u8string() << "\"" << std::endl;
streamCpp << "#include <support/serdes.h>" << std::endl;
streamCpp << "#include <support/pssup.h>" << std::endl;
streamCpp << std::endl;
// Run through the entities and create the proxy code of every interface...
sdv::idl::IDefinitionEntity* pDefinition = GetInterface<sdv::idl::IDefinitionEntity>(GetParser());
if (!pDefinition) throw CCompileException("Internal error: the parser doesn't have a root definition.");
sdv::idl::IEntityIterator* pIterator = pDefinition->GetChildren();
if (!pIterator) throw CCompileException("Internal error: the parser doesn't support entity iteration.");
ProcessEntities(streamHdr, streamCpp, pIterator);
// End of safeguard
streamHdr << Safeguard(pathFileHdr, false);
return true;
}
void CPSClassGeneratorBase::ProcessEntities(std::ostream& rstreamHdr, std::ostream& rstreamCpp,
sdv::idl::IEntityIterator* pIterator)
{
if (!pIterator) throw CCompileException("Internal error: processing entities without iterator.");
for (uint32_t uiIndex = 0; uiIndex < pIterator->GetCount(); uiIndex++)
{
// Get the entity
sdv::IInterfaceAccess* pEntity = pIterator->GetEntityByIndex(uiIndex);
if (!pEntity) throw CCompileException("Internal error: processing non-existent entity.");
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
const sdv::idl::IEntityContext* pContext = GetInterface<sdv::idl::IEntityContext>(pEntity);
if (!pContext) throw CCompileException("Internal error: the entity doesn't expose context information.");
sdv::idl::IDefinitionEntity* pDefinition = GetInterface<sdv::idl::IDefinitionEntity>(pEntity);
const sdv::idl::IInterfaceEntity* pInterface = GetInterface<sdv::idl::IInterfaceEntity>(pEntity);
// Only process entities in the source code
if (pContext->GetLocation() != sdv::idl::IEntityContext::ELocation::source)
continue;
// Forward declaration
if (pEntityInfo->ForwardDeclaration())
continue;
// Process interfaces only... but only when not local
if (pInterface && pInterface->IsLocal()) continue;
switch (pEntityInfo->GetType())
{
case sdv::idl::EEntityType::type_interface:
StreamInterface(rstreamHdr, rstreamCpp, pEntity);
break;
default:
break;
}
// Does the entity have children?
sdv::idl::IEntityIterator* pChildIterator = pDefinition ? pDefinition->GetChildren() : nullptr;
if (pChildIterator) ProcessEntities(rstreamHdr, rstreamCpp, pChildIterator);
}
}
void CPSClassGeneratorBase::StreamInterface(std::ostream& rstreamHdr, std::ostream& rstreamCpp,
sdv::IInterfaceAccess* pEntity)
{
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
std::string ssClassName = QualifyName(pEntityInfo->GetScopedName()) + "__" + GetNameAppendix();
// TODO: Deal with multiple inheritance
std::string ssAliasName = pEntityInfo->GetScopedName();
for (size_t nPos = ssAliasName.find("::"); nPos != std::string::npos; nPos = ssAliasName.find("::"))
ssAliasName.replace(nPos, 2, "_");
CKeywordMap mapKeywords = {
{"class_name", ssClassName},
{"alias_name", ssAliasName},
{"interface_name", pEntityInfo->GetScopedName()},
{"interface_id", std::to_string(pEntityInfo->GetId())}
};
// Generate class definition and constructor/destructor
rstreamHdr << ReplaceKeywords(GetClassDefBegin(mapKeywords), mapKeywords);
rstreamCpp << ReplaceKeywords(GetConstructImplBegin(mapKeywords), mapKeywords);
// Stream the interface content
std::stringstream sstreamImpl;
uint32_t uiFuncIndex = 0;
StreamInterfaceContent(rstreamHdr, rstreamCpp, sstreamImpl, mapKeywords, pEntity, uiFuncIndex);
// Finalize the interface
rstreamHdr << ReplaceKeywords(GetClassDefEnd(mapKeywords), mapKeywords);
rstreamCpp << ReplaceKeywords(GetConstructImplEnd(mapKeywords), mapKeywords);
rstreamCpp << sstreamImpl.str();
}
void CPSClassGeneratorBase::StreamInterfaceContent(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody,
std::ostream& rstreamClassImpl, const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt)
{
// Stream base interfaces first
sdv::idl::IDefinitionEntity* pDefinition = GetInterface<sdv::idl::IDefinitionEntity>(pEntity);
sdv::idl::IEntityIterator* pInheritanceIterator = pDefinition ? pDefinition->GetInheritance() : nullptr;
for (uint32_t uiIndex = 0; pInheritanceIterator && uiIndex < pInheritanceIterator->GetCount(); uiIndex++)
{
sdv::IInterfaceAccess* pBaseEntity = pInheritanceIterator->GetEntityByIndex(uiIndex);
if (!pBaseEntity->GetInterface<sdv::idl::IEntityInfo>())
throw CCompileException("Internal error: the entity inherits from an unknown entity.");
StreamInterfaceContent(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, rmapKeywords, pBaseEntity, ruiFuncCnt);
}
// Run through the children and process attributes and operations
sdv::idl::IEntityIterator* pChildIterator = pDefinition ? pDefinition->GetChildren() : nullptr;
for (uint32_t uiIndex = 0; pChildIterator && uiIndex < pChildIterator->GetCount(); uiIndex++)
{
// Get the entity
sdv::IInterfaceAccess* pChildEntity = pChildIterator->GetEntityByIndex(uiIndex);
if (!pEntity) throw CCompileException("Internal error: processing non-existent entity.");
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pChildEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
const sdv::idl::IEntityContext* pContext = GetInterface<sdv::idl::IEntityContext>(pChildEntity);
if (!pContext) throw CCompileException("Internal error: the entity doesn't expose context information.");
// Forward declaration
if (pEntityInfo->ForwardDeclaration())
continue;
switch (pEntityInfo->GetType())
{
case sdv::idl::EEntityType::type_attribute:
StreamAttribute(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, rmapKeywords, pChildEntity, ruiFuncCnt);
break;
case sdv::idl::EEntityType::type_operation:
StreamOperation(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, rmapKeywords, pChildEntity, ruiFuncCnt);
break;
default:
break;
}
}
}
void CPSClassGeneratorBase::StreamAttribute(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody,
std::ostream& rstreamClassImpl, const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt)
{
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
if (pEntityInfo->GetType() != sdv::idl::EEntityType::type_attribute)
throw CCompileException("Internal error: the entity has incorrect type information.");
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pEntity);
if (!pDeclaration)
throw CCompileException("Internal error: the entity is a declaration, but doesn't expose declaration information.");
CExceptionVector vecReadExceptions;
sdv::idl::IAttributeEntity* pAttribute = GetInterface<sdv::idl::IAttributeEntity>(pEntity);
if (!pAttribute) throw CCompileException("Internal error: operation is not exposing operation information.");
sdv::idl::IEntityIterator* pExceptionIterator = pAttribute->GetReadExceptions();
for (uint32_t uiIndex = 0; pExceptionIterator && uiIndex < pExceptionIterator->GetCount(); uiIndex++)
{
// Get the parameter entity
sdv::IInterfaceAccess* pExceptionEntity = pExceptionIterator->GetEntityByIndex(uiIndex);
if (!pExceptionEntity) throw CCompileException("Internal error: processing non-existent exception entity.");
const sdv::idl::IEntityInfo* pExceptionEntityInfo = pExceptionEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pExceptionEntityInfo) throw CCompileException("Internal error: processing non-existent exception entity.");
vecReadExceptions.push_back(pExceptionEntityInfo->GetScopedName());
}
// Stream the getter function
CKeywordMap mapKeywordsGetter = rmapKeywords;
mapKeywordsGetter.insert(std::make_pair("func_name", std::string("get_") + pEntityInfo->GetName()));
StreamFunction(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, mapKeywordsGetter, pEntity, ruiFuncCnt, true,
std::vector<sdv::IInterfaceAccess*>(), vecReadExceptions);
// Stream the setter function if not readonly.
if (!pDeclaration->IsReadOnly())
{
CExceptionVector vecWriteExceptions;
pExceptionIterator = pAttribute->GetWriteExceptions();
for (uint32_t uiIndex = 0; pExceptionIterator && uiIndex < pExceptionIterator->GetCount(); uiIndex++)
{
// Get the parameter entity
sdv::IInterfaceAccess* pExceptionEntity = pExceptionIterator->GetEntityByIndex(uiIndex);
if (!pExceptionEntity) throw CCompileException("Internal error: processing non-existent exception entity.");
const sdv::idl::IEntityInfo* pExceptionEntityInfo = pExceptionEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pExceptionEntityInfo) throw CCompileException("Internal error: processing non-existent exception entity.");
vecWriteExceptions.push_back(pExceptionEntityInfo->GetScopedName());
}
CKeywordMap mapKeywordsSetter = rmapKeywords;
mapKeywordsSetter.insert(std::make_pair("func_name", std::string("set_") + pEntityInfo->GetName()));
StreamFunction(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, mapKeywordsSetter, nullptr, ruiFuncCnt, false,
std::vector<sdv::IInterfaceAccess*>({ pEntity }), vecWriteExceptions);
}
}
void CPSClassGeneratorBase::StreamOperation(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody,
std::ostream& rstreamClassImpl, const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt)
{
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pEntity);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
if (pEntityInfo->GetType() != sdv::idl::EEntityType::type_operation)
throw CCompileException("Internal error: the entity has incorrect type information.");
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pEntity);
if (!pDeclaration)
throw CCompileException("Internal error: the entity is a declaration, but doesn't expose declaration information.");
// Build a parameter vector (if there are any).
std::vector<sdv::IInterfaceAccess*> vecParams;
sdv::idl::IOperationEntity* pOperation = GetInterface<sdv::idl::IOperationEntity>(pEntity);
if (!pOperation) throw CCompileException("Internal error: operation is not exposing operation information.");
sdv::idl::IEntityIterator* pParamIterator = pOperation->GetParameters();
for (uint32_t uiIndex = 0; pParamIterator && uiIndex < pParamIterator->GetCount(); uiIndex++)
{
// Get the parameter entity
sdv::IInterfaceAccess* pParamEntity = pParamIterator->GetEntityByIndex(uiIndex);
if (!pParamEntity) throw CCompileException("Internal error: processing non-existent parameter entity.");
const sdv::idl::IParameterEntity* pParameter = GetInterface<sdv::idl::IParameterEntity>(pParamEntity);
if (!pParameter)
throw CCompileException("Internal error: the entity is a parameter, but doesn't expose parameter information.");
vecParams.push_back(pParamEntity);
}
CExceptionVector vecExceptions;
sdv::idl::IEntityIterator* pExceptionIterator = pOperation ? pOperation->GetExceptions() : nullptr;
for (uint32_t uiIndex = 0; pExceptionIterator && uiIndex < pExceptionIterator->GetCount(); uiIndex++)
{
// Get the parameter entity
sdv::IInterfaceAccess* pExceptionEntity = pExceptionIterator->GetEntityByIndex(uiIndex);
if (!pExceptionEntity) throw CCompileException("Internal error: processing non-existent exception entity.");
const sdv::idl::IEntityInfo* pExceptionEntityInfo = pExceptionEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pExceptionEntityInfo) throw CCompileException("Internal error: processing non-existent exception entity.");
vecExceptions.push_back(pExceptionEntityInfo->GetScopedName());
}
// Stream the operation
CKeywordMap mapKeywordsOperation = rmapKeywords;
mapKeywordsOperation.insert(std::make_pair("func_name", pEntityInfo->GetName()));
StreamFunction(rstreamClassDef, rstreamConstrBody, rstreamClassImpl, mapKeywordsOperation, pEntity, ruiFuncCnt,
pDeclaration->IsReadOnly(), vecParams, vecExceptions);
}
void CPSClassGeneratorBase::StreamFunction(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody,
std::ostream& rstreamClassImpl, const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pRetParam,
uint32_t& ruiFuncCnt, bool bConst, const std::vector<sdv::IInterfaceAccess*>& rvecParams, const CExceptionVector& rvecExceptions)
{
// Get the parameter information and build the parameter pack definitions
std::vector<SParamInfo> vecParamInfos;
std::stringstream sstreamParamPackDef, sstreamParamPackUse;
SParamInfo sReturnInfo = GetParamInfo(pRetParam, true);
if (sReturnInfo.bValidType)
vecParamInfos.push_back(sReturnInfo);
size_t nInputCnt = 0;
size_t nOutputCnt = vecParamInfos.size();
for (sdv::IInterfaceAccess* pParam : rvecParams)
{
// Get parameter info
SParamInfo sParamInfo = GetParamInfo(pParam);
// Add to parameter pack definition
switch (sParamInfo.eDirection)
{
case SParamInfo::EDirection::in:
if (!sstreamParamPackDef.str().empty()) sstreamParamPackDef << ", ";
if (!sstreamParamPackUse.str().empty()) sstreamParamPackUse << ", ";
if ((sParamInfo.bIsPointer || sParamInfo.bIsComplex) && !sParamInfo.bIsInterface)
sstreamParamPackDef << "const ";
sstreamParamPackDef << sParamInfo.ssDeclType;
if (sParamInfo.bIsComplex && !sParamInfo.bIsInterface)
sstreamParamPackDef << "&";
sstreamParamPackDef << " " << sParamInfo.ssName;
sstreamParamPackUse << sParamInfo.ssName;
nInputCnt++;
break;
case SParamInfo::EDirection::inout:
nInputCnt++;
if (!sstreamParamPackDef.str().empty()) sstreamParamPackDef << ", ";
if (!sstreamParamPackUse.str().empty()) sstreamParamPackUse << ", ";
sstreamParamPackDef << sParamInfo.ssDeclType << "& " << sParamInfo.ssName;
sstreamParamPackUse << sParamInfo.ssName;
nOutputCnt++;
nInputCnt++;
break;
case SParamInfo::EDirection::out:
if (!sstreamParamPackDef.str().empty()) sstreamParamPackDef << ", ";
if (!sstreamParamPackUse.str().empty()) sstreamParamPackUse << ", ";
sstreamParamPackDef << sParamInfo.ssDeclType << "& " << sParamInfo.ssName;
sstreamParamPackUse << sParamInfo.ssName;
nOutputCnt++;
break;
default:
// Do not add anything
break;
}
// Store in vector
vecParamInfos.push_back(std::move(sParamInfo));
}
// In case there are no parameters and no return values, add at least one parameter to be able to receive exceptions.
if (vecParamInfos.empty())
vecParamInfos.push_back(SParamInfo());
// Get function information
SFuncInfo sFuncInfo{};
sFuncInfo.ssName = ReplaceKeywords("%func_name%", rmapKeywords);
sFuncInfo.ssDecl = sReturnInfo.ssDeclType;
sFuncInfo.ssDeclType = sReturnInfo.ssDeclType;
sFuncInfo.ssDefRetValue = sReturnInfo.ssDefaultValue;
sFuncInfo.bIsConst = bConst;
sFuncInfo.nInputParamCnt = nInputCnt;
sFuncInfo.nOutputParamCnt = nOutputCnt;
// Stream the getter function
CKeywordMap mapKeywordsFunction = rmapKeywords;
mapKeywordsFunction.insert(std::make_pair("func_decl_type", sReturnInfo.ssDeclType));
mapKeywordsFunction.insert(std::make_pair("func_default_ret_value", sReturnInfo.ssDefaultValue));
mapKeywordsFunction.insert(std::make_pair("func_index", std::to_string(ruiFuncCnt)));
mapKeywordsFunction.insert(std::make_pair("param_pack_def", sstreamParamPackDef.str()));
mapKeywordsFunction.insert(std::make_pair("param_pack_use", sstreamParamPackUse.str()));
mapKeywordsFunction.insert(std::make_pair("total_param_cnt", std::to_string(vecParamInfos.size())));
// Stream constructor implementation
rstreamConstrBody << ReplaceKeywords(GetConstructFuncImpl(sFuncInfo, mapKeywordsFunction), mapKeywordsFunction);
// Stream func prototype
rstreamClassDef << ReplaceKeywords(GetFuncDef(sFuncInfo, mapKeywordsFunction), mapKeywordsFunction);
// Stream the parameter init code.
std::stringstream sstreamParamInit;
size_t nIndex = 0;
for (const SParamInfo& rsParam : vecParamInfos)
{
CKeywordMap mapKeywordsParam = mapKeywordsFunction;
mapKeywordsParam.insert(std::make_pair("param_name", rsParam.ssName));
mapKeywordsParam.insert(std::make_pair("param_decl_type", rsParam.ssDeclType));
mapKeywordsParam.insert(std::make_pair("param_index", std::to_string(nIndex)));
mapKeywordsParam.insert(std::make_pair("param_default_val", rsParam.ssDefaultValue));
mapKeywordsParam.insert(std::make_pair("param_size", rsParam.ssSize));
sstreamParamInit << ReplaceKeywords(GetFuncImplParamInit(sFuncInfo, rsParam, mapKeywordsParam), mapKeywordsParam);
nIndex++;
}
// Stream the parameter input code.
std::stringstream sstreamParamInput;
nIndex = 0;
for (const SParamInfo& rsParam : vecParamInfos)
{
CKeywordMap mapKeywordsParam = mapKeywordsFunction;
mapKeywordsParam.insert(std::make_pair("param_name", rsParam.ssName));
mapKeywordsParam.insert(std::make_pair("param_decl_type", rsParam.ssDeclType));
mapKeywordsParam.insert(std::make_pair("param_index", std::to_string(nIndex)));
mapKeywordsParam.insert(std::make_pair("param_default_val", rsParam.ssDefaultValue));
mapKeywordsParam.insert(std::make_pair("param_size", rsParam.ssSize));
sstreamParamInput << ReplaceKeywords(GetFuncImplStreamParamInput(sFuncInfo, rsParam, mapKeywordsParam), mapKeywordsParam);
nIndex++;
}
// Stream the parameter input code.
std::stringstream sstreamParamOutput;
nIndex = 0;
for (const SParamInfo& rsParam : vecParamInfos)
{
CKeywordMap mapKeywordsParam = mapKeywordsFunction;
mapKeywordsParam.insert(std::make_pair("param_name", rsParam.ssName));
mapKeywordsParam.insert(std::make_pair("param_decl_type", rsParam.ssDeclType));
mapKeywordsParam.insert(std::make_pair("param_index", std::to_string(nIndex)));
mapKeywordsParam.insert(std::make_pair("param_default_val", rsParam.ssDefaultValue));
mapKeywordsParam.insert(std::make_pair("param_size", rsParam.ssSize));
sstreamParamOutput << ReplaceKeywords(GetFuncImplStreamParamOutput(sFuncInfo, rsParam, mapKeywordsParam), mapKeywordsParam);
nIndex++;
}
// Stream the parameter term code.
std::stringstream sstreamParamTerm;
nIndex = 0;
for (const SParamInfo& rsParam : vecParamInfos)
{
CKeywordMap mapKeywordsParam = mapKeywordsFunction;
mapKeywordsParam.insert(std::make_pair("param_name", rsParam.ssName));
mapKeywordsParam.insert(std::make_pair("param_decl_type", rsParam.ssDeclType));
mapKeywordsParam.insert(std::make_pair("param_index", std::to_string(nIndex)));
mapKeywordsParam.insert(std::make_pair("param_default_val", rsParam.ssDefaultValue));
mapKeywordsParam.insert(std::make_pair("param_size", rsParam.ssSize));
sstreamParamInit << ReplaceKeywords(GetFuncImplParamTerm(sFuncInfo, rsParam, mapKeywordsParam), mapKeywordsParam);
nIndex++;
}
// Stream func implementation
CKeywordMap mapKeywordsFunctionImpl = mapKeywordsFunction;
mapKeywordsFunctionImpl.insert(std::make_pair("param_init", sstreamParamInit.str()));
mapKeywordsFunctionImpl.insert(std::make_pair("stream_param_input", sstreamParamInput.str()));
mapKeywordsFunctionImpl.insert(std::make_pair("stream_param_output", sstreamParamOutput.str()));
mapKeywordsFunctionImpl.insert(std::make_pair("param_term", sstreamParamTerm.str()));
rstreamClassImpl << ReplaceKeywords(GetFuncImpl(sFuncInfo, mapKeywordsFunctionImpl, rvecExceptions), mapKeywordsFunctionImpl);
// Increase the function index
ruiFuncCnt++;
}
CPSClassGeneratorBase::SParamInfo CPSClassGeneratorBase::GetParamInfo(sdv::IInterfaceAccess* pParam, bool bIsRetValue /*= false*/) const
{
SParamInfo sInfo;
if (bIsRetValue)
sInfo.eDirection = SParamInfo::EDirection::ret;
if (!pParam)
{
// Special case... void return parameter
if (!bIsRetValue) throw CCompileException("Internal error: function parameter cannot be void.");
sInfo.ssDeclType = "void";
sInfo.eDirection = SParamInfo::EDirection::ret;
return sInfo;
}
// Get the entity interfaces.
const sdv::idl::IEntityInfo* pEntityInfo = GetInterface<sdv::idl::IEntityInfo>(pParam);
if (!pEntityInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
const sdv::idl::IDeclarationEntity* pDeclaration = GetInterface<sdv::idl::IDeclarationEntity>(pParam);
if (!pDeclaration)
throw CCompileException("Internal error: the entity is a declaration, but doesn't expose declaration information.");
const sdv::idl::IParameterEntity* pParameter = GetInterface<sdv::idl::IParameterEntity>(pParam);
sInfo.ssName = bIsRetValue ? "return_value" : pEntityInfo->GetName();
static_cast<SCDeclInfo&>(sInfo) = GetCDeclTypeStr(pDeclaration->GetDeclarationType(), std::string(), true);
if (sInfo.bIsDynamic)
{
sInfo.ssSize = std::string("(") + sInfo.ssName + " ? static_cast<uint32_t>(std::char_traits<" + sInfo.ssDeclType +
">::length(" + sInfo.ssName + ") + 1) * sizeof(" + sInfo.ssDeclType + ") : 0)";
sInfo.eAllocType = SParamInfo::EAllocType::indirect;
} else
sInfo.ssSize = std::string("static_cast<uint32_t>(sizeof(") + sInfo.ssDeclType + "))";
if (!bIsRetValue || sInfo.ssDeclType != "void")
{
// GCC-issue: Types defined as "long long", "long int", "long long int", "long double" cannot be initialized using brackets.
if (sInfo.ssDeclType.substr(0, 4) == "long")
sInfo.ssDefaultValue = sInfo.bIsPointer ? "nullptr" : std::string("static_cast<") + sInfo.ssDeclType + ">(0)";
else
sInfo.ssDefaultValue = sInfo.bIsPointer ? "nullptr" : sInfo.ssDeclType + "{}";
}
if (!bIsRetValue)
{
// Stream the parameter direction. All but the input parameter need to support the ouput of values.
switch (pParameter ? pParameter->GetDirection() : sdv::idl::IParameterEntity::EParameterDirection::input)
{
case sdv::idl::IParameterEntity::EParameterDirection::output:
sInfo.eDirection = SParamInfo::EDirection::out;
break;
case sdv::idl::IParameterEntity::EParameterDirection::in_out:
sInfo.eDirection = SParamInfo::EDirection::inout;
break;
case sdv::idl::IParameterEntity::EParameterDirection::input:
default:
sInfo.eDirection = SParamInfo::EDirection::in;
break;
}
}
return sInfo;
}
void CPSClassGeneratorBase::StreamMarshallDecl(std::ofstream& rstream, const CKeywordMap& rmapKeywords, uint32_t uiFuncIndex,
uint32_t uiParamCnt)
{
CKeywordMap mapKeywordsMarshall = rmapKeywords;
mapKeywordsMarshall.insert(std::make_pair("index", std::to_string(uiFuncIndex)));
mapKeywordsMarshall.insert(std::make_pair("paramcnt", std::to_string(uiParamCnt)));
// Code generation
std::string ssDeclCode = R"code( // Declare the marshall structure
sdv::core::SMarshall sPacket{};
union { uint16_t uiWord; uint8_t rguiBytes[2]; } uEndian = {1};
sPacket.uiEndian = uEndian.rguiBytes[1];
sPacket.uiPadding = 0;
sPacket.uiVersion = 100;
sPacket.tIfcId = %interface_name%::_id;
sPacket.uiFuncIndex = %index%;
)code";
rstream << ReplaceKeywords(ssDeclCode, mapKeywordsMarshall);
if (uiParamCnt)
{
std::string ssParamDeclCode = R"code( sPacket.uiCount = %paramcnt%;
sdv::core::SMarshall::SParam rgsParams[%paramcnt%] = {};
sPacket.rgsParams = rgsParams;
)code";
rstream << ReplaceKeywords(ssParamDeclCode, mapKeywordsMarshall);
}
}
bool CPSClassGeneratorBase::RuntimeProcessingRequired(sdv::IInterfaceAccess* pEntity)
{
// Get the entity interfaces.
sdv::idl::IDeclarationEntity* pDeclaration = pEntity->GetInterface<sdv::idl::IDeclarationEntity>();
if (!pDeclaration) throw CCompileException("Internal error: expecting a declaration.");
// Request the type
sdv::IInterfaceAccess* pTypeObj = pDeclaration->GetDeclarationType();
if (!pTypeObj) throw CCompileException("Internal error: expecting a declaration type.");
const sdv::idl::IDeclarationType* pDeclType = pTypeObj->GetInterface<sdv::idl::IDeclarationType>();
if (!pDeclType) throw CCompileException("Internal error: expecting a declaration type.");
sdv::idl::EDeclType eType = pDeclType->GetBaseType();
sdv::IInterfaceAccess* pType = pDeclType->GetTypeDefinition();
// Check whether the entity requires runtime processing.
switch (eType)
{
case sdv::idl::EDeclType::decltype_interface:
case sdv::idl::EDeclType::decltype_string:
case sdv::idl::EDeclType::decltype_u8string:
case sdv::idl::EDeclType::decltype_u16string:
case sdv::idl::EDeclType::decltype_u32string:
case sdv::idl::EDeclType::decltype_wstring:
return true;
default:
break;
}
// If there is a pType, this can either be a typedef or a definition.
const sdv::idl::IDeclarationEntity* pTypedefDeclaration = pType->GetInterface<sdv::idl::IDeclarationEntity>();
// Forward the request in case the type is a declaration
if (pTypedefDeclaration) return RuntimeProcessingRequired(pType);
// Get the definition and check for children
sdv::idl::IDefinitionEntity* pDefinition = pType->GetInterface<sdv::idl::IDefinitionEntity>();
sdv::idl::IEntityIterator* pChildIterator =
pDefinition ? pType->GetInterface<sdv::idl::IEntityIterator>() : nullptr;
for (uint32_t uiIndex = 0; pChildIterator && uiIndex < pChildIterator->GetCount(); uiIndex++)
{
sdv::IInterfaceAccess* pChildEntity = pChildIterator->GetEntityByIndex(uiIndex);
if (!pChildEntity) throw CCompileException("Internal error: definition doesn't have a valid child entity.");
const sdv::idl::IEntityInfo* pChildEntityInfo = pChildEntity->GetInterface<sdv::idl::IEntityInfo>();
if (!pChildEntityInfo) throw CCompileException("Internal error: definition doesn't have valid child entity info.");
if (pChildEntityInfo->GetType() != sdv::idl::EEntityType::type_variable) continue; // Only variables are of interest.
const sdv::idl::IDeclarationEntity* pChildDeclaration = pChildEntity->GetInterface<sdv::idl::IDeclarationEntity>();
if (!pChildDeclaration) throw CCompileException("Internal error: variable doesn't expose a declaration interface.");
if (pChildDeclaration->IsReadOnly()) continue; // Static const variables are counting.
// Check the child
if (RuntimeProcessingRequired(pChildEntity))
return true; // At least one member of the variable requires runtime processing.
}
// No variables requiring runtime processing detected
return false;
}

View File

@@ -0,0 +1,325 @@
#ifndef PS_CLASS_GENERATOR_BASE_H
#define PS_CLASS_GENERATOR_BASE_H
#include "context.h"
#include <vector>
/**
* @brief Proxy/stub class generator base implementation.
*/
class CPSClassGeneratorBase : public CGenContext
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CPSClassGeneratorBase(sdv::IInterfaceAccess* pParser);
/**
* @brief Generate the proxy.
* @return Returns whether generation was successful.
*/
virtual bool Generate();
protected:
/**
* @brief Return the name addition to be added to the filename and class definition.
* @return The name appendix string.
*/
virtual std::string GetNameAppendix() const = 0;
/**
* @brief Get definition file comments to be written in the file header.
* @return String with class definition comments.
*/
virtual std::string GetClassDefFileComments() const = 0;
/**
* @brief Get implementation file comments to be written in the file header.
* @return String with class implementation comments.
*/
virtual std::string GetClassImplFileComments() const = 0;
/**
* @brief Get begin of class definition to be inserted into the header file.
* @remarks The following keywords are defined: %class_name% and %interface_name%.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with class definition begin.
*/
virtual std::string GetClassDefBegin(CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get end of class definition to be inserted into the header file.
* @remarks The following keywords are defined: %class_name% and %interface_name%.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with class definition end.
*/
virtual std::string GetClassDefEnd(CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get begin of constructor implementation to be inserted into the cpp file.
* @remarks The following keywords are defined: %class_name% and %interface_name%.
* @param[in, out] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with constructor implementation begin.
*/
virtual std::string GetConstructImplBegin(CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get end of constructor implementation to be inserted into the cpp file.
* @remarks The following keywords are defined: %class_name% and %interface_name%.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with constructor implementation end.
*/
virtual std::string GetConstructImplEnd(CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Function information structure
*/
struct SFuncInfo
{
std::string ssName; ///< Function name.
std::string ssDecl; ///< Return value declaration type (could be void).
std::string ssDeclType; ///< Return value declaration base type.
std::string ssDefRetValue; ///< Default return value (or empty if decl type is void).
bool bIsConst = false; ///< Set when the function is declared as const function.
size_t nInputParamCnt = 0; ///< Input parameter count.
size_t nOutputParamCnt = 0; ///< Output parameter count.
};
/**
* @brief Parameter information structure
*/
struct SParamInfo : SCDeclInfo
{
std::string ssName; ///< Parameter name
std::string ssDefaultValue; ///< Parameter default value (or empty for void return value)
std::string ssSize; ///< Parameter size
enum class EDirection { in, out, inout, ret, ignored } eDirection = EDirection::ignored; ///< Parameter direction or return value
enum class EAllocType { direct, indirect, ifc} eAllocType = EAllocType::direct; ///< Parameter allocation type
};
/**
* @brief Get the constructor body for a function (attribute or operation).
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* and %out_param_cnt%.
* @param[in] rsFunc Reference to the function information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with constructor function body.
*/
virtual std::string GetConstructFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get the function definition (attribute or operation).
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* and %out_param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @param[in] rsFunc Reference to the function information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with the function definition.
*/
virtual std::string GetFuncDef(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get the function implementation (attribute or operation).
* @details The function implementation uses the specific keywords %param_init%, %stream_input_param%, %stream_output_param%,
* and %param_term% to insert code from the parameter streaming functions.
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* and %out_param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @param[in] rsFunc Reference to the function information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @param[in] rvecExceptions Vector containing the exceptions defined for this function.
* @return String with the function implementation.
*/
virtual std::string GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords, const CExceptionVector& rvecExceptions) const = 0;
/**
* @brief Get parameter initialization of the function implementation (attribute or operation). The content of this function
* is paced in the keyword %param_init% of the GetFuncImpl function.
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* %out_param_cnt%, %param_name%, %param_decl_type%, %param_index%, %param_default_val%, %param_size% and %param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @remarks The %param_index% is the parameter index incl. optional return value at index 0.
* @param[in] rsFunc Reference to the function information structure.
* @param[in] rsParam Reference to a parameter information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with the function parameter initialization.
*/
virtual std::string GetFuncImplParamInit(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get input parameter streaming of the function implementation (attribute or operation). The content of this function
* is paced in the keyword %stream_param_input% of the GetFuncImpl function.
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* %out_param_cnt%, %param_name%, %param_decl_type%, %param_index%, %param_default_val%, %param_size% and %param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @remarks The %param_index% is the parameter index incl. optional return value at index 0.
* @param[in] rsFunc Reference to the function information structure.
* @param[in] rsParam Reference to a parameter information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with the function input parameters.
*/
virtual std::string GetFuncImplStreamParamInput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get output parameter streaming of the function implementation (attribute or operation). The content of this function
* is paced in the keyword %stream_param_output% of the GetFuncImpl function.
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* %out_param_cnt%, %param_name%, %param_decl_type%, %param_index%, %param_default_val%, %param_size% and %param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @remarks The %param_index% is the parameter index incl. optional return value at index 0.
* @param[in] rsFunc Reference to the function information structure.
* @param[in] rsParam Reference to a parameter information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with the function output parameters.
*/
virtual std::string GetFuncImplStreamParamOutput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const = 0;
/**
* @brief Get parameter termination of the function implementation (attribute or operation). The content of this function
* is paced in the keyword %param_term% of the GetFuncImpl function.
* @remarks The following keywords are defined: %class_name%, %interface_name%, %func_decl_type%,
* %func_default_ret_value%, %func_name%, %func_index%, %param_pack_def%, %param_pack_use%, %total_param_cnt%, %in_param_cnt%,
* %out_param_cnt%, %param_name%, %param_decl_type%, %param_index%, %param_default_val%, %param_size% and %param_cnt%.
* @remarks The %out_param_cnt% includes the return parameter.
* @remarks The %param_index% is the parameter index incl. optional return value at index 0.
* @param[in] rsFunc Reference to the function information structure.
* @param[in] rsParam Reference to a parameter information structure.
* @param[inout] rmapKeywords Reference to the keyword map. This allows inserting additional keywords local for the returned
* code snippet.
* @return String with the function parameter termination.
*/
virtual std::string GetFuncImplParamTerm(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const = 0;
private:
/**
* @brief Process the entities.
* @param[in] rstreamHdr Reference to the stream of the target header file.
* @param[in] rstreamCpp Reference to the stream of the target C++ file.
* @param[in] pIterator Pointer to the iterator interface.
*/
void ProcessEntities(std::ostream& rstreamHdr, std::ostream& rstreamCpp, sdv::idl::IEntityIterator* pIterator);
/**
* @brief Stream definition and implementation if the entity is an interface definition.
* @param[in] rstreamHdr Reference to the stream of the target header file.
* @param[in] rstreamCpp Reference to the stream of the target C++ file.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamInterface(std::ostream& rstreamHdr, std::ostream& rstreamCpp, sdv::IInterfaceAccess* pEntity);
/**
* @brief Stream attributes and operations of an interface definition and all derived interface definitions.
* @param[in] rstreamClassDef Reference to the class definition stream.
* @param[in] rstreamConstrBody Reference to the constructor body stream.
* @param[in] rstreamClassImpl Reference to the class implementation stream.
* @param[in] rmapKeywords Map with keywords to replace. Keyword "class" and "interface" are defined.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in, out] ruiFuncCnt Reference to the function counter used to set the index. Will be updated.
*/
void StreamInterfaceContent(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody, std::ostream& rstreamClassImpl,
const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt);
/**
* @brief Stream attribute declaration if the entity is an attribute.
* attention Comments are not streamed for parameters.
* @param[in] rstreamClassDef Reference to the class definition stream.
* @param[in] rstreamConstrBody Reference to the constructor body stream.
* @param[in] rstreamClassImpl Reference to the class implementation stream.
* @param[in] rmapKeywords Map with keywords to replace. Keyword "class" and "interface" are defined.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in, out] ruiFuncCnt Reference to the function counter used to set the index. Will be updated.
*/
void StreamAttribute(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody, std::ostream& rstreamClassImpl,
const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt);
/**
* @brief Stream operation declaration if the entity is an operation.
* @param[in] rstreamClassDef Reference to the class definition stream.
* @param[in] rstreamConstrBody Reference to the constructor body stream.
* @param[in] rstreamClassImpl Reference to the class implementation stream.
* @param[in] rmapKeywords Map with keywords to replace. Keyword "class" and "interface" are defined.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in, out] ruiFuncCnt Reference to the function counter used to set the index. Will be updated.
*/
void StreamOperation(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody, std::ostream& rstreamClassImpl,
const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pEntity, uint32_t& ruiFuncCnt);
/**
* @brief Stream function declaration (for attributes and operations).
* @details Functions are streamed in this order:
* - Constructor function impl
* - Function definition
* - Function impl begin
* - For each parameter, param init impl
* - Pass #1 impl begin
* - For each parameter, pass #1 impl
* - Pass #1 impl end
* - Pass #2 impl begin
* - For each parameter, pass #2 impl
* - Pass #2 impl end
* - Function impl end
* @param[in] rstreamClassDef Reference to the class definition stream.
* @param[in] rstreamConstrBody Reference to the constructor body stream.
* @param[in] rstreamClassImpl Reference to the class implementation stream.
* @param[in] rmapKeywords Map with keywords to replace. Additional keyword "func_name" is defined.
* @param[in] pRetParam Pointer to the IInterfaceAccess pointer of the entity holding the return parameter.
* @param[in, out] ruiFuncCnt Reference to the function counter used to set the index. Will be updated.
* @param[in] bConst When set, the function is marked as a const-function.
* @param[in] rvecParams Reference to the vector containing the parameter entities defined for this function.
* @param[in] rvecExceptions Reference to the vector containing the exceptions defined for this function.
*/
void StreamFunction(std::ostream& rstreamClassDef, std::ostream& rstreamConstrBody, std::ostream& rstreamClassImpl,
const CKeywordMap& rmapKeywords, sdv::IInterfaceAccess* pRetParam, uint32_t& ruiFuncCnt, bool bConst,
const std::vector<sdv::IInterfaceAccess*>& rvecParams, const CExceptionVector& rvecExceptions);
/**
* @brief Get parameter information.
* @param[in] pParam Entity representing the parameter (not necessarily a parameter entity). If NULL, expecting it to be a
* "void" return value.
* @param[in] bIsRetValue When set, the parameter is marked as return value.
* @return The parameter information structure.
*/
SParamInfo GetParamInfo(sdv::IInterfaceAccess* pParam, bool bIsRetValue = false) const;
/**
* @brief Stream SMarshall declaration.
* @param[in] rstream Reference to the stream of the target C++ file.
* @param[in] rmapKeywords Map with keywords to replace.
* @param[in] uiFuncIndex Index of the function within the interface.
* @param[in] uiParamCnt Parameter count.
*/
void StreamMarshallDecl(std::ofstream& rstream, const CKeywordMap& rmapKeywords, uint32_t uiFuncIndex, uint32_t uiParamCnt);
/**
* @brief Does the provided entity or any contained entities data types where the interpretation can only be done during
* runtime?
* @details Data types that require runtime processing are dynamic arrays (arrays where the size is determined by another
* entity), interfaces, strings and sequences.
* @param[in] pEntity Pointer to the entity to check for runtime processing requirements.
* @return Returns whether runtime processing is required.
*/
static bool RuntimeProcessingRequired(sdv::IInterfaceAccess* pEntity);
};
#endif // !defined(PS_CLASS_GENERATOR_BASE_H)

View File

@@ -0,0 +1,118 @@
#include "context.h"
#include "ps_cpp_generator.h"
#include "../exception.h"
#include <cassert>
#include <cctype>
#include <fstream>
#include <algorithm>
#include <set>
#include <mutex>
CPsCppGenerator::CPsCppGenerator(sdv::IInterfaceAccess* pParser) : CGenContext(pParser), m_mtx("SDV_IDL_COMPILER_GENERATE_PS")
{}
CPsCppGenerator::~CPsCppGenerator()
{}
bool CPsCppGenerator::Generate()
{
// Synchronize proxy/stub code generation among processes.
std::unique_lock<ipc::named_mutex> lock(m_mtx);
// Create "proxy" directory
std::filesystem::path pathPSTarget = GetOutputDir() / "ps";
if (!std::filesystem::exists(pathPSTarget) && !std::filesystem::create_directory(pathPSTarget))
throw CCompileException("Cannot create proxy/stub directory: ", pathPSTarget.generic_u8string());
// The source string
std::string ssSource;
// File with "CMakeLists.txt" function; read completely if existing
std::filesystem::path pathFile = pathPSTarget / "proxystub.cpp";
if (std::filesystem::exists(pathFile))
{
std::ifstream stream;
stream.open(pathFile);
if (!stream.is_open()) throw CCompileException("Failed to open the proxystub.cpp file for reading.");
// Read the complete source
std::stringstream sstream;
sstream << stream.rdbuf();
ssSource = std::move(sstream.str());
}
// Create the file in memory
if (ssSource.empty())
{
std::stringstream sstream;
// Add file header
sstream << "/**" << std::endl;
sstream << " * @file proxstub.cpp" << std::endl;
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
sstream << " * @date " << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << std::endl;
sstream << " * This file was generated by the SDV IDL compiler" << std::endl;
sstream << " *" << std::endl;
sstream << " * Allow including all proxy-stub source code files to be included through this file." << std::endl;
sstream << " */" << std::endl;
sstream << std::endl;
ssSource = std::move(sstream.str());
}
// Search for each #include preprocessor directive
// And build a map of text includes
struct SChunkPos { size_t nPos = 0; size_t nLen = 0; };
std::set<std::string> setFiles;
size_t nPos = 0;
while (nPos != std::string::npos)
{
// Find the directive
nPos = ssSource.find("#include", nPos);
if (nPos == std::string::npos) continue;
nPos += 8;
// Skip whitespace
while (nPos < ssSource.size() && std::isspace(ssSource[nPos])) nPos++;
if (nPos >= ssSource.size()) continue;
// Check for quote
if (ssSource[nPos] != '\"') continue;
nPos++;
// Extract the include file and add to the set
size_t nFilePos = nPos;
while (nPos < ssSource.size() && ssSource[nPos] != '\"') nPos++;
if (nPos >= ssSource.size()) continue;
setFiles.insert(ssSource.substr(nFilePos, nPos - nFilePos));
}
// Insert additional files if needed
size_t nSourceSize = ssSource.size();
std::filesystem::path pathPSFileBase = GetSource().filename();
pathPSFileBase.replace_extension("");
std::string ssFileBase = pathPSFileBase.generic_u8string();
if (setFiles.find(ssFileBase + "_stub.cpp") == setFiles.end())
{
std::stringstream sstream;
sstream << std::endl;
sstream << "// Adding proxy and stub code for " << GetSource().filename().generic_u8string() << std::endl;
sstream << "#include \"" << ssFileBase << "_stub.cpp" << "\"" << std::endl;
sstream << "#include \"" << ssFileBase << "_proxy.cpp" << "\"" << std::endl;
ssSource += sstream.str();
}
// Write the file again if needed
if (nSourceSize != ssSource.size())
{
std::ofstream stream;
stream.open(pathFile, std::ofstream::trunc);
if (!stream.is_open()) throw CCompileException("Failed to open the proxystub.cpp file for writing.");
// Write the complete source
stream << ssSource;
}
// Done!
return true;
}

View File

@@ -0,0 +1,33 @@
#ifndef PS_CPP_GENERATOR_H
#define PS_CPP_GENERATOR_H
#include "../../../global/ipc_named_mutex.h"
/**
* @brief Prox/stub CPP file generator class.
*/
class CPsCppGenerator : public CGenContext
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CPsCppGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CPsCppGenerator() override;
/**
* @brief Generate the definition.
* @return Returns whether the generation was successful.
*/
bool Generate();
private:
ipc::named_mutex m_mtx; ///< Guarantee exclusive access while writing the PS file.
};
#endif // !defined PS_CPP_GENERATOR_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
#ifndef SERDES_GENERATOR_H
#define SERDES_GENERATOR_H
#include "definition_generator_base.h"
#include <set>
#include <fstream>
/**
* @brief Definition stream context.
*/
class CSerdesContext : public CDefEntityContext<CSerdesContext>
{
public:
/**
* @brief Constructor assigning the generator context.
* @param[in] rGenContext Reference to the context to assign.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
*/
CSerdesContext(const CGenContext& rGenContext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Copy constructor assigning a new definition entity.
* @param[in] rcontext Original context to copy from.
* @param[in] pEntity Pointer to the definition entity this context belongs to.
* @param[in] rssDeclName Reference to the declaration name to be added to the member scope.
*/
CSerdesContext(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity, const std::string& rssDeclName = std::string());
/**
* @brief Join a context into this context. Overload of CDefEntityContext::operator<<.
* @param[in] rcontext Reference to the context to join.
* @return Reference to this context containing the joined result.
*/
virtual CSerdesContext& operator<<(const CSerdesContext& rcontext) override;
/**
* @brief Get the member scoped name when streaming declarations using a container higher in the hierarchy.
* @return The member scope to use for streaming. Types are separated by a scope-serparator '::' and members are separated by a
* dot '.' separation character.
* @param[in] rssDeclName Reference to the string holding the declaration name to use for a full scoped name.
* @param[in] bFullScope When set, add the container scoped name as well. Otherwise omit the container scoped name.
*/
std::string ComposeMemberScope(const std::string& rssDeclName, bool bFullScope = false) const;
/**
* @brief All following code is part of the serdes namespace.
*/
void EnableSerDesNamespace();
/**
* @brief All following code is not part of the serdes namespace.
*/
void DisableSerDesNamespace();
/**
* @brief Get a reference to the serializer/deserializer code stream.
* @return Reference to the definition body stream object.
*/
std::stringstream& GetSerDesCodeStream();
/**
* @brief Get serializer/deserializer code.
* @return Returns a string containing the serializer/deserializer code collected within this context.
*/
std::string GetSerDesCode() const;
/**
* @brief Function part enumeration
*/
enum class EFuncStreamPart
{
header, ///< Function header
body, ///< Function body
footer, ///< Function footer
};
/**
* @brief Get a reference to the size function stream.
* @param[in] ePart The function part to return.
* @return Reference to the serializer function stream object.
*/
std::stringstream& GetSizeFuncStream(EFuncStreamPart ePart = EFuncStreamPart::body);
/**
* @brief Get a reference to the serializer function stream.
* @param[in] ePart The function part to return.
* @return Reference to the serializer function stream object.
*/
std::stringstream& GetSerFuncStream(EFuncStreamPart ePart = EFuncStreamPart::body);
/**
* @brief Get a reference to the deserializer function stream.
* @param[in] ePart The function part to return.
* @return Reference to the deserializer function stream object.
*/
std::stringstream& GetDesFuncStream(EFuncStreamPart ePart = EFuncStreamPart::body);
/**
* @brief Get the size function code.
* @param[in] ePart The function part to return.
* @return String with the function code to.
*/
std::string GetSizeFuncCode(EFuncStreamPart ePart = EFuncStreamPart::body) const;
/**
* @brief Get the serializer function code.
* @param[in] ePart The function part to return.
* @return String with the function code to.
*/
std::string GetSerFuncCode(EFuncStreamPart ePart = EFuncStreamPart::body) const;
/**
* @brief Get a reference to the deserializer function stream.
* @param[in] ePart The function part to return.
* @return String with the function code to.
*/
std::string GetDesFuncCode(EFuncStreamPart ePart = EFuncStreamPart::body) const;
/**
* @brief Join the serialization and deserialization function body content to the body content within this stream.
* @param[in] rcontext Reference to the context containing of the function bodies.
* @param[in] bDoNotIncludeNewline When set, do not insert a newline if needed.
*/
void JoinFuncBodyStreams(const CSerdesContext& rcontext, bool bDoNotIncludeNewline = false);
/**
* @brief Stream the class definition with inserted serializer and deserializer functions to the definition stream and clear the
* serializer and deserializer streams when finished.
* @param[in] rssClassBegin The class definition part to stream before the serializer functions are streamed.
* @param[in] rssClassEnd The class definition part to stream after the serializer functions are streamed.
* @param[in] rmapKeywords Use the map of keywords for keyword replacement within the texts.
*/
void StreamAndClearSerFuncStreams(const std::string& rssClassBegin, const std::string& rssClassEnd,
const CGenContext::CKeywordMap& rmapKeywords);
/**
* @brief Does the function need variable streaming?
* @return Returns whether variable streaming is required.
*/
bool NeedsVariableStreaming() const;
private:
bool m_bSerDesByContainer = false; ///< When one of the member declarations requires serialization by a
///< container that declares this definition, this boolean is set.
std::stringstream m_sstreamSerDesCode; ///< Serializer/deserializer code stream.
std::stringstream m_sstreamSizeFuncHdr; ///< Content of the size function header.
std::stringstream m_sstreamSizeFuncFtr; ///< Content of the size function footer.
std::stringstream m_sstreamSizeFunc; ///< Content of the size function.
std::stringstream m_sstreamSerFuncHdr; ///< Content of the serializer function header.
std::stringstream m_sstreamSerFuncFtr; ///< Content of the serializer function footer.
std::stringstream m_sstreamSerFunc; ///< Content of the serializer function.
std::stringstream m_sstreamDesFuncHdr; ///< Content of the deserializer function header.
std::stringstream m_sstreamDesFuncFtr; ///< Content of the deserializer function footer.
std::stringstream m_sstreamDesFunc; ///< Content of the deserializer function.
size_t m_nTempDeclCnt = 0; ///< Temporary variable declaration counter. Used to identify generate
///< unique temporary variables.
std::string m_ssMemberScope; ///< The member scope to use when streaming declarations.
bool m_bSerDesNamespace = false; ///< When set, the serdes namespace is enabled.
bool m_bNotStreamable = false; ///< When set, this definition entity is not streamable directly and
///< should be part of the streaming of any container holding the
///< declaration of this entity.
};
/**
* @brief Serializer/deserializer code generator class.
*/
class CSerdesGenerator : public CDefinitionGeneratorBase<CSerdesContext>
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CSerdesGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CSerdesGenerator() override;
private:
/**
* @brief Return the information for target file creation. Overload of CDefinitionGeneratorBase::GetTargetFileInfo.
* @param[out] rssTargetSubDir Reference to the string containing the target sub-directory to be added to the output directory.
* Could be empty to target the output directory.
* @param[out] rssTargetFileEnding Reference to string containing the file ending (file name and extension) to be placed at the
* end of the source file name replacing the extension.
*/
virtual void GetTargetFileInfo(std::string& rssTargetSubDir, std::string& rssTargetFileEnding) override;
/**
* @brief Return the file header text for automatic file generation. Overload of CDefinitionGeneratorBase::GetFileHeaderText.
* @return The header text to place into the file.
*/
virtual std::string GetFileHeaderText() const override;
/**
* @brief Stream the code into the file. Called once after processing. Overload of CDefinitionGeneratorBase::StreamIntoFile.
* @param[in, out] rcontext Reference to the stream context.
* @param[in, out] rfstream Reference to the file stream to stream into
*/
virtual void StreamIntoFile(CSerdesContext& rcontext, std::ofstream& rfstream) override;
/**
* @brief Stream the include section for the file. Overload of CDefinitionGeneratorBase::StreamIncludeSection.
* @param[in, out] rcontext Reference to the stream context to stream into.
*/
virtual void StreamIncludeSection(CSerdesContext& rcontext) override;
/**
* @brief Stream the meta entity. Overload of CDefinitionGeneratorBase::StreamMetaEntity.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the interface of the meta entity.
*/
virtual void StreamMetaEntity(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity) override;
/**
* @brief Stream declaration if the entity is a declaration. Overload of CDefinitionGeneratorBase::StreamDeclaration.
* @param[in, out] rcontext Reference to the stream context.
* @param[in] pEntity Pointer to the interface of the declaration entity.
* @return Returns true when the streaming was successful or false when streaming was not successful and should be canceled.
*/
virtual bool StreamDeclaration(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity) override;
/**
* @brief Stream definition if the entity is a definition. Overload of CDefinitionGeneratorBase::StreamDefinition.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] bInline When set the definition is part of a declaration.
* @param[in] bAnonymousDecl When set, the definition is part of an anonymous declaration (only valid for unions).
*/
virtual void StreamDefinition(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity, bool bInline = false,
bool bAnonymousDecl = false) override;
/**
* @brief Stream definition content (the declaration within the definition).
* @param[in, out] rcontext Reference to the stream context.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
* @param[in] bSuppressComments When set, do not stream the comment.
* @return Returns true when the streaming was successful or false when streaming was not successful and should be canceled.
*/
bool StreamDefinitionContent(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity, bool bSuppressComments = false);
/**
* @brief Stream interface definition.
* @param[in, out] rcontext Reference to the stream context.
* @param[in] pEntity Pointer to the IInterfaceAccess pointer of the entity.
*/
void StreamInterface(CSerdesContext& rcontext, sdv::IInterfaceAccess* pEntity);
/**
* @brief Process the union member that, together with the switch variable, has a mutual container from the entity in the
* context. Overload of CDefinitionGeneratorBase::ProcessUnionInContainerContext.
* @param[in, out] rcontext Reference to the stream context to stream into.
* @param[in] rssMemberScopeUnionDecl Reference to the member scope of the union declaration (could be empty when the union
* switch is not variable based).
* @param[in] rssMemberScopeSwitchVar Reference to the member scope of the switch variable (could be empty when the union
* switch is not variable based).
* @param[in] pUnionDef Pointer to the union definition entity.
* @param[in] rvecArrayIndices Reference to the vector containing the array indices of the declaration to use for the detection.
* If the declaration is not declared as array, the vector should be empty. If the declaration is declared as an array and the
* amount of dimensions is below the amount of dimensions within the provided vector, the detection function is called for each
* array dimension extending the vector with the index to do the detection for.
*/
virtual void ProcessUnionInContainerContext(CSerdesContext& rcontext, std::string rssMemberScopeUnionDecl,
std::string rssMemberScopeSwitchVar, sdv::IInterfaceAccess* pUnionDef,
const std::vector<SArrayIterationInfo>& rvecArrayIndices = std::vector<SArrayIterationInfo>()) override;
/**
* @brief For a switch variable, process the joint container of both switch variable and union. Start with the highest parent
* running through all children. Overload of CDefinitionGeneratorBase::ProcessUnionJointContainerForSwitchVar.
* @param[in, out] rcontext Reference to the definition stream context of the switch variable to stream into.
* @param[in] pSwitchVarEntity Interface to the switch var declaration.
* @param[in] pContainerEntity Interface to the container definition.
*/
virtual void ProcessUnionJointContainerForSwitchVar(CSerdesContext& rcontext,
sdv::IInterfaceAccess* pSwitchVarEntity, sdv::IInterfaceAccess* pContainerEntity) override;
std::set<std::string> m_setHistory; ///< Set of all the scoped names that have been processed.
std::set<std::string> m_setNonStreamableDef; ///< Set of non-streamable definition entities. Streaming should take
///< place in the container implementing the declaration.
/// Definition entities that cannot be streamed directly (in case of a direct or indirect declaration of a union entity or a
/// switch variable entity) should be streamed in a container instead. The key in the map represents the definition scoped name.
/// The value contains a list of container entities (scoped names).
std::map<std::string, std::list<std::string>> m_mapInlineDef;
};
#endif // !defined SERDES_GENERATOR_H

View File

@@ -0,0 +1,262 @@
#include "stub_generator.h"
#include "../exception.h"
#include <fstream>
CStubGenerator::CStubGenerator(sdv::IInterfaceAccess* pParser) : CPSClassGeneratorBase(pParser)
{}
CStubGenerator::~CStubGenerator()
{}
std::string CStubGenerator::GetNameAppendix() const
{
return "stub";
}
std::string CStubGenerator::GetClassDefFileComments() const
{
return "This file contains the stub definition for the interfaces.";
}
std::string CStubGenerator::GetClassImplFileComments() const
{
return "This file contains the stub implementation for the interfaces.";
}
std::string CStubGenerator::GetClassDefBegin(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
/**
* @brief Proxy class implementation for the %interface_name%.
*/
class %class_name% : public sdv::ps::CStubHandler<%interface_name%>, public sdv::ps::IStubLink
{
public:
/**
* @brief Constructor
* @param[in] pInterface Pointer to the target interface this proxy has to operate. Must not be NULL.
*/
%class_name%();
/**
* @brief Destructor
*/
virtual ~%class_name%() override = default;
// Object class name
DECLARE_OBJECT_CLASS_NAME("Stub_%interface_id%")
DECLARE_OBJECT_CLASS_ALIAS("Stub_%alias_name%")
// Interface map
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_CHAIN_BASE(sdv::ps::CStubHandler<%interface_name%>)
SDV_INTERFACE_ENTRY(IStubLink)
END_SDV_INTERFACE_MAP()
/**
* @brief Link the object target interface to the stub-object. Overload of IStubLink::Link.
* @remarks Only one link can exists at the time.
* @param[in] pInterface Interface to be linked.
*/
void Link(/*in*/ sdv::interface_t ifc) override;
/**
* @brief Unlink the linked interface. Overload of IStubLink::Unlink.
*/
void Unlink() override;
)code";
}
std::string CStubGenerator::GetClassDefEnd(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
private:
%interface_name%* m_ifc = nullptr; ///< Pointer to the marshalled interface.
};
DEFINE_SDV_OBJECT(%class_name%)
)code";
}
std::string CStubGenerator::GetConstructImplBegin(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
%class_name%::%class_name%()
{
)code";
}
std::string CStubGenerator::GetConstructImplEnd(CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
}
void %class_name%::Link(/*in*/ sdv::interface_t ifc)
{
m_ifc = ifc.template get<%interface_name%>();
assert(m_ifc);
}
void %class_name%::Unlink()
{
m_ifc = nullptr;
}
)code";
}
std::string CStubGenerator::GetConstructFuncImpl(const SFuncInfo& /*rsFunc*/, CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
RegisterDispatchFunc([this](sdv::EEndian eEndian, const sdv::pointer<uint8_t>& rptrInputParams, sdv::pointer<uint8_t>& rptrOutputParams) -> sdv::ps::ECallResult
{
return stub_%func_name%(eEndian, rptrInputParams, rptrOutputParams);
});
)code";
}
std::string CStubGenerator::GetFuncDef(const SFuncInfo& /*rsFunc*/, CKeywordMap& /*rmapKeywords*/) const
{
return R"code(
/** Implementation of stub_%func_name%. */
sdv::ps::ECallResult stub_%func_name%(sdv::EEndian eEndian, const sdv::pointer<uint8_t>& rptrInputParams, sdv::pointer<uint8_t>&rptrOutputParams);
)code";
}
std::string CStubGenerator::GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords, const CExceptionVector& rvecExceptions) const
{
rmapKeywords.insert(std::make_pair("func_return", rsFunc.ssDeclType != "void" ? "return_value = " : ""));
rmapKeywords.insert(std::make_pair("argument_endianess", rsFunc.nInputParamCnt || rsFunc.nOutputParamCnt || rvecExceptions.size() ? " eEndian" : ""));
rmapKeywords.insert(std::make_pair("argument_input_params", rsFunc.nInputParamCnt ? " rptrInputParams" : ""));
rmapKeywords.insert(std::make_pair("argument_output_params", rsFunc.nOutputParamCnt || rvecExceptions.size() ? " rptrOutputParams" : ""));
rmapKeywords.insert(std::make_pair("param_init_comments", rsFunc.nInputParamCnt || rsFunc.nOutputParamCnt ? R"code(
// Initialize parameters
// CppCheck warns about parameter that could be declared as const. This is not wanted here. Suppress the warning.
// cppcheck-suppress constVariablePointer)code" : ""));
std::stringstream sstream;
sstream << R"code(
sdv::ps::ECallResult %class_name%::stub_%func_name%(sdv::EEndian%argument_endianess%, const sdv::pointer<uint8_t>&%argument_input_params%, sdv::pointer<uint8_t>&%argument_output_params%)
{
if (!m_ifc) throw sdv::XNoInterface(); // Error, interface must be assigned.%param_init_comments%%param_init%)code";
if (rsFunc.nInputParamCnt)
sstream << R"code(
// Deserialize parameters
if (eEndian == sdv::EEndian::big_endian)
{
sdv::deserializer<sdv::EEndian::big_endian> desInput;
desInput.attach(rptrInputParams);%stream_param_input%
} else
{
sdv::deserializer<sdv::EEndian::little_endian> desInput;
desInput.attach(rptrInputParams);%stream_param_input%
})code";
// Call function. Add try/catch if exceptions are used.
if (rvecExceptions.size())
{
sstream << R"code(
try
{
// Call the function
%func_return%m_ifc->%func_name%(%param_pack_use%);
})code";
for (const std::string& rssException : rvecExceptions)
{
sstream << " catch (const " << rssException << "& rexcept)";
sstream << R"code(
{
if (eEndian == sdv::EEndian::big_endian)
{
sdv::serializer<sdv::EEndian::big_endian> serOutput;
serOutput << rexcept;
rptrOutputParams = std::move(serOutput.buffer());
return sdv::ps::ECallResult::result_exception;
} else
{
sdv::serializer<sdv::EEndian::little_endian> serOutput;
serOutput << rexcept;
rptrOutputParams = std::move(serOutput.buffer());
return sdv::ps::ECallResult::result_exception;
}
})code";
}
} else
{
sstream << R"code(
// Call the function
%func_return%m_ifc->%func_name%(%param_pack_use%);)code";
}
if (rsFunc.nOutputParamCnt) sstream << R"code(
// Serializer
if (eEndian == sdv::EEndian::big_endian)
{
sdv::serializer<sdv::EEndian::big_endian> serOutput;%stream_param_output%
rptrOutputParams = std::move(serOutput.buffer());
return sdv::ps::ECallResult::result_ok;
} else
{
sdv::serializer<sdv::EEndian::little_endian> serOutput;%stream_param_output%
rptrOutputParams = std::move(serOutput.buffer());
return sdv::ps::ECallResult::result_ok;
})code";
else
sstream << R"code(
return sdv::ps::ECallResult::result_ok;)code";
sstream << R"code(
}
)code";
return sstream.str();
}
std::string CStubGenerator::GetFuncImplParamInit(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
if (!rsParam.bValidType) return {};
// Do not initialize the return value; this will be initialized later.
if (rsParam.ssName == "return_value")
return R"code(
%param_decl_type% %param_name%;)code";
else
return R"code(
%param_decl_type% %param_name% = %param_default_val%;)code";
}
std::string CStubGenerator::GetFuncImplStreamParamInput(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
if (!rsParam.bValidType) return "";
switch (rsParam.eDirection)
{
case SParamInfo::EDirection::in:
case SParamInfo::EDirection::inout:
return R"code(
desInput >> %param_name%;)code";
default:
return "";
}
}
std::string CStubGenerator::GetFuncImplStreamParamOutput(const SFuncInfo& /*rsFunc*/, const SParamInfo& rsParam, CKeywordMap& /*rmapKeywords*/) const
{
if (!rsParam.bValidType) return "";
switch (rsParam.eDirection)
{
case SParamInfo::EDirection::ret:
case SParamInfo::EDirection::out:
case SParamInfo::EDirection::inout:
return R"code(
serOutput << %param_name%;)code";
default:
return "";
}
}
std::string CStubGenerator::GetFuncImplParamTerm(const SFuncInfo& /*rsFunc*/, const SParamInfo& /*rsParam*/, CKeywordMap& /*rmapKeywords*/) const
{
return std::string();
}

View File

@@ -0,0 +1,108 @@
#ifndef STUB_GTENERATOR_H
#define STUB_GTENERATOR_H
#include "ps_class_generator_base.h"
/**
* @brief Stub generator class.
*/
class CStubGenerator : public CPSClassGeneratorBase
{
public:
/**
* @brief Constructor
* @param[in] pParser Pointer to the parser object.
*/
CStubGenerator(sdv::IInterfaceAccess* pParser);
/**
* @brief Destructor
*/
virtual ~CStubGenerator() override;
private:
/**
* @brief Return the name addition to be added to the filename and class definition. Overload of
* CPSClassGeneratorBase::GetNameAppendix.
*/
virtual std::string GetNameAppendix() const override;
/**
* @brief Get definition file comments to be written in the file header. Overload of
* CPSClassGeneratorBase::GetClassDefFileComments.
*/
virtual std::string GetClassDefFileComments() const override;
/**
* @brief Get implementation file comments to be written in the file header. Overload of
* CPSClassGeneratorBase::GetClassImplFileComments.
*/
virtual std::string GetClassImplFileComments() const override;
/**
* @brief Get begin of class definition to be inserted into the header file. Overload of
* CPSClassGeneratorBase::GetClassDefBegin.
*/
virtual std::string GetClassDefBegin(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get end of class definition to be inserted into the header file. Overload of
* CPSClassGeneratorBase::GetClassDefEnd.
*/
virtual std::string GetClassDefEnd(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get begin of constructor implementation to be inserted into the cpp file. Overload of
* CPSClassGeneratorBase::GetConstructImplBegin.
*/
virtual std::string GetConstructImplBegin(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get end of constructor implementation to be inserted into the cpp file. Overload of
* CPSClassGeneratorBase::GetConstructImplEnd.
*/
virtual std::string GetConstructImplEnd(CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the constructor body for a function (attribute or operation). Overload of
* CPSClassGeneratorBase::GetConstructFuncImpl.
*/
virtual std::string GetConstructFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the function definition (attribute or operation). Overload of CPSClassGeneratorBase::GetFuncDef.
*/
virtual std::string GetFuncDef(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImpl.
*/
virtual std::string GetFuncImpl(const SFuncInfo& rsFunc, CKeywordMap& rmapKeywords, const CExceptionVector& rvecExceptions) const override;
/**
* @brief Get parameter initialization of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplParamInit.
*/
virtual std::string GetFuncImplParamInit(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get input parameter streaming of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplStreamParamInput.
*/
virtual std::string GetFuncImplStreamParamInput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get output parameter streaming of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplStreamParamOutput.
*/
virtual std::string GetFuncImplStreamParamOutput(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
/**
* @brief Get parameter termination of the unpack portion of the function implementation (attribute or operation). Overload of
* CPSClassGeneratorBase::GetFuncImplParamTerm.
*/
virtual std::string GetFuncImplParamTerm(const SFuncInfo& rsFunc, const SParamInfo& rsParam, CKeywordMap& rmapKeywords) const override;
};
#endif // !defined(STUB_GTENERATOR_H)