mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-04-20 03:08:17 +00:00
167
sdv_executables/sdv_idl_compiler/generator/cmake_generator.cpp
Normal file
167
sdv_executables/sdv_idl_compiler/generator/cmake_generator.cpp
Normal 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;
|
||||
}
|
||||
34
sdv_executables/sdv_idl_compiler/generator/cmake_generator.h
Normal file
34
sdv_executables/sdv_idl_compiler/generator/cmake_generator.h
Normal 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
|
||||
499
sdv_executables/sdv_idl_compiler/generator/context.cpp
Normal file
499
sdv_executables/sdv_idl_compiler/generator/context.cpp
Normal 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;
|
||||
}
|
||||
187
sdv_executables/sdv_idl_compiler/generator/context.h
Normal file
187
sdv_executables/sdv_idl_compiler/generator/context.h
Normal 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)
|
||||
1813
sdv_executables/sdv_idl_compiler/generator/definition_generator.cpp
Normal file
1813
sdv_executables/sdv_idl_compiler/generator/definition_generator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
254
sdv_executables/sdv_idl_compiler/generator/proxy_generator.cpp
Normal file
254
sdv_executables/sdv_idl_compiler/generator/proxy_generator.cpp
Normal 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();
|
||||
}
|
||||
|
||||
108
sdv_executables/sdv_idl_compiler/generator/proxy_generator.h
Normal file
108
sdv_executables/sdv_idl_compiler/generator/proxy_generator.h
Normal 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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
118
sdv_executables/sdv_idl_compiler/generator/ps_cpp_generator.cpp
Normal file
118
sdv_executables/sdv_idl_compiler/generator/ps_cpp_generator.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
1167
sdv_executables/sdv_idl_compiler/generator/serdes_generator.cpp
Normal file
1167
sdv_executables/sdv_idl_compiler/generator/serdes_generator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
289
sdv_executables/sdv_idl_compiler/generator/serdes_generator.h
Normal file
289
sdv_executables/sdv_idl_compiler/generator/serdes_generator.h
Normal 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
|
||||
262
sdv_executables/sdv_idl_compiler/generator/stub_generator.cpp
Normal file
262
sdv_executables/sdv_idl_compiler/generator/stub_generator.cpp
Normal 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();
|
||||
}
|
||||
108
sdv_executables/sdv_idl_compiler/generator/stub_generator.h
Normal file
108
sdv_executables/sdv_idl_compiler/generator/stub_generator.h
Normal 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)
|
||||
Reference in New Issue
Block a user