mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-02-05 15:18:45 +00:00
26
sdv_executables/CMakeLists.txt
Normal file
26
sdv_executables/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# Include cross-compilation toolchain file
|
||||
include(../cross-compile-tools.cmake)
|
||||
|
||||
# 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(SDVServices VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# Include export into the include directory path
|
||||
include_directories(../export)
|
||||
|
||||
# Add executable projects
|
||||
add_subdirectory(sdv_idl_compiler)
|
||||
add_subdirectory(sdv_dbc_util)
|
||||
add_subdirectory(sdv_vss_util)
|
||||
add_subdirectory(sdv_control)
|
||||
add_subdirectory(sdv_core)
|
||||
add_subdirectory(sdv_iso)
|
||||
add_subdirectory(sdv_packager)
|
||||
add_subdirectory(sdv_local_shutdown)
|
||||
add_subdirectory(sdv_trace_mon)
|
||||
|
||||
# Appending all executables to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} PARENT_SCOPE)
|
||||
119
sdv_executables/error_msg.h
Normal file
119
sdv_executables/error_msg.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef EXECUTABLES_ERROR_MSG
|
||||
#define EXECUTABLES_ERROR_MSG
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
// The define NO_ERROR could have been defined already by Windows. Suppress the definition during the error message creation.
|
||||
// Then re-enable the define. This only works, because the newly assigned value and the value used by Windows is identical.
|
||||
#ifdef NO_ERROR
|
||||
#pragma push_macro("NO_ERROR")
|
||||
#undef NO_ERROR
|
||||
#define SUPPRESS_NO_ERROR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro for making an error message definition.
|
||||
* @details This macro creates three variables for the use of error reporting:<br>
|
||||
* <identifier> The assigned error code (application return code).<br>
|
||||
* <identifier>_MSG The assigned error message.<br>
|
||||
* <identifier>_DESC The assigned error explanation.<br>
|
||||
* @param id The ID of the message (integer)
|
||||
* @param identifier The identifier used for the message assignment.
|
||||
* @param topic The string to explain the error in one sentence.
|
||||
* @param description The string to provide detailed information about the error.
|
||||
*/
|
||||
#define MAKE_ERROR_MSG(id, identifier, topic, description) \
|
||||
[[maybe_unused]] static const int identifier = id; \
|
||||
[[maybe_unused]] static const char* identifier##_MSG = topic; \
|
||||
[[maybe_unused]] static const char* identifier##_DESC = description;
|
||||
|
||||
////////// GENERIC ERROR CODES ////////////
|
||||
|
||||
MAKE_ERROR_MSG(0, NO_ERROR, "No error.", "Execution succeeded expectinly.")
|
||||
MAKE_ERROR_MSG(-1, NOT_IMPLEMENTED, "Not implemented.", "The function is not implemented.")
|
||||
MAKE_ERROR_MSG(-2, CMDLN_ARG_ERR, "Command line argument error.", "An incorrect argument was supplied on the command line.")
|
||||
MAKE_ERROR_MSG(-3, CMDLN_SILENT_VERBOSE, "Cannot supply both silent and verbose options.", "Both silent and verbose were supplied, which cannot be used at the same time.")
|
||||
MAKE_ERROR_MSG(-100, PROCESS_TIMEOUT, "Potential deadlock detected; termination enforced.", "The process watchdog has detected a potential deadlock and initiated the process termination.")
|
||||
|
||||
////////// CONNECTION AND CORE SERVICE ACCESS ERROR CODES ////////////
|
||||
|
||||
MAKE_ERROR_MSG(-124, CONNECT_SDV_SERVER_ERROR, "Could not connect to SDV Server.", "Failed to connect to a running SDV service instance.")
|
||||
MAKE_ERROR_MSG(-131, PROCESS_CONTROL_SERVICE_ACCESS_ERROR, "Process control service is not accessible.", "The process control service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-132, MODULE_CONTROL_SERVICE_ACCESS_ERROR, "Module control service is not accessible.", "The module control service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-133, REPOSITORY_SERVICE_ACCESS_ERROR, "Repository service is not accessible.", "The repository service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-134, CONFIG_SERVICE_ACCESS_ERROR, "Configuration service is not accessible.", "The configuration service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-135, COMMUNICATION_CONTROL_SERVICE_ACCESS_ERROR, "Communication control service is not accessible.", "The communication control service service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-136, APP_CONTROL_SERVICE_ACCESS_ERROR, "Application control service is not accessible.", "The application control service could not be accessed.")
|
||||
MAKE_ERROR_MSG(-170, CANNOT_FIND_OBJECT, "The object cannot be found.", "A search for an object with supplied name was not successful.")
|
||||
|
||||
|
||||
////////// LOCAL APP CONTROL ERROR CODES ////////////
|
||||
|
||||
MAKE_ERROR_MSG(-204, APP_CONTROL_STARTUP_ERROR, "Cannot start application control.", "Application control start was initiated, but returned an error.")
|
||||
MAKE_ERROR_MSG(-205, APP_CONTROL_START_LOOP_FAIELD, "Starting the running loop failed.", "Failed to enter the processing loop for a server application.")
|
||||
MAKE_ERROR_MSG(-206, APP_CONTROL_DUPLICATE_INSTANCE, "Another process with specified instance is already running.", "Another core process initiated the application control with the same instance. Only one core process per instance is allowed.")
|
||||
MAKE_ERROR_MSG(-210, APP_CONTROL_INVALID_ISOLATION_CONFIG, "An invalid isolation configuration was supplied.", "The application control configuration section contains an invalid isolation configuration.")
|
||||
MAKE_ERROR_MSG(-218, SETTING_FILE_VERSION_INVALID, "Settings file has an invalid version.", "Settings file contains an invalid/incompatible version number.")
|
||||
MAKE_ERROR_MSG(-222, REGISTER_PROCESS_MONITOR_ERROR, "Failed to register the process monitor.", "During the registration of the process monitor, an error occurred.")
|
||||
MAKE_ERROR_MSG(-214, LINK_REPO_SERVICE_ERROR, "Cannot link the core repository to the isolated repository.", "Failed to link the core repository to the repository of the isolated application.")
|
||||
MAKE_ERROR_MSG(-230, ISOLATION_INVALID_OBJECT_TYPE, "An object of this type cannot be run isolated.", "The isolation of an objeczt is supported for complex services and utilities.")
|
||||
MAKE_ERROR_MSG(-231, ISOLATION_FAILED, "The isolation of the object failed.", "The request to run an object in an isolated environment failed.")
|
||||
MAKE_ERROR_MSG(-240, REGISTER_FOREIGN_OBJECT_FAILED, "The registration of a foreign object failed.", "An running object registration as a foreign object was not successful.")
|
||||
|
||||
|
||||
////////// SDV CONTROL ERROR CODES ////////////
|
||||
|
||||
MAKE_ERROR_MSG(-821, STARTUP_CORE_ERROR, "Could not start the SDV core process.", "Failed to start the SDV core process.")
|
||||
MAKE_ERROR_MSG(-822, CORE_NOT_STARTED, "The SDV core process was not running.", "A request for the status of a SDV core process returned that the process was not running.")
|
||||
MAKE_ERROR_MSG(-823, SHUTDOWN_CORE_ERROR, "Could not start the SDV core process.", "Failed to start the SDV core process.")
|
||||
MAKE_ERROR_MSG(-840, START_OBJECT_ERROR, "Could not start the object.", "Failed to start an object.")
|
||||
MAKE_ERROR_MSG(-841, STOP_OBJECT_ERROR, "Could not stop the object.", "Failed to stop/destroy an object.")
|
||||
|
||||
|
||||
////////// SDV PACKAGER ERROR CODES ////////////
|
||||
|
||||
MAKE_ERROR_MSG(-1005, CMDLN_INSTALL_NAME_MISSING, "No installation name provided.", "The installation name was not supplied at the command line. This is needed for packing, direct installation and uninstallation.")
|
||||
MAKE_ERROR_MSG(-1006, CMDLN_SOURCE_LOCATION_ERROR, "Source location cannot be found or is not a directory.", "The supplied source location is not a valid directory.")
|
||||
MAKE_ERROR_MSG(-1007, CMDLN_OUTPUT_LOCATION_ERROR, "Output location cannot be found or is not a directory.", "The supplied output location is not a valid directory.")
|
||||
MAKE_ERROR_MSG(-1004, CMDLN_TARGET_LOCATION_ERROR, "Target location cannot be found or is not a directory.", "The supplied target location is not a valid directory.")
|
||||
MAKE_ERROR_MSG(-1008, CMDLN_MULTIPLE_CFG_FILES, "Only one configuration file can be generated.", "Multiple configuration files were supplied at the command line. Only one configuration file can be generated at the time.")
|
||||
MAKE_ERROR_MSG(-1009, CMDLN_CREATE_ONLY_MANIFEST_DIRECT_INSTALL_ERROR, "create_manifest_only-flag is not compatible with direct_install-flag.", "Command line flag for only creation of a manifest cannot be combined with the flag for direct installation.")
|
||||
MAKE_ERROR_MSG(-1010, CMDLN_NOTHING_TO_DO, "No action supplied; nothing to do.", "No command was supplied on the command line. There is nothing to do.")
|
||||
MAKE_ERROR_MSG(-1011, CMDLN_UPDATE_OVERWRITE_ERROR, "Cannot specify update and overwrite at the same time.", "Update and overwrite were specified at the same time. This is not valid.")
|
||||
MAKE_ERROR_MSG(-1012, CMDLN_SOURCE_FILE_ERROR, "Source file cannot be found or is invalid.", "The supplied source file name is not a valid file.")
|
||||
MAKE_ERROR_MSG(-1013, CMDLN_SOURCE_FILE_MISSING, "No source file specified.", "There was no source file specified at the command line.")
|
||||
MAKE_ERROR_MSG(-1014, CMDLN_TOO_MANY_SOURCE_FILES, "Too many source files were specified.", "Too many source files were specified at the command line. Only one file is supported at the time.")
|
||||
MAKE_ERROR_MSG(-1015, CMDLN_INCOMPATIBLE_ARGUMENTS, "Incompatible arguments were supplied, not fitting the command.", "Some arguments cannot be combined with the command on the command line.")
|
||||
MAKE_ERROR_MSG(-1016, CMDLN_MISSING_SHOW_COMMAND, "Missing show command.", "The command SHOW was supplied on the command line, but not what to show.")
|
||||
MAKE_ERROR_MSG(-1017, CMDLN_INVALID_CONFIG_STRING, "The configuration string is invalid.", "The configuration string should consist of path (only for local) followed by +component,component,....")
|
||||
MAKE_ERROR_MSG(-1018, SAVE_INSTALL_MANIFEST_ERROR, "Failed to save the installation manifest.", "Saving the installation manifest returned with an error.")
|
||||
MAKE_ERROR_MSG(-1019, SAVE_SETTINGS_FILE_ERROR, "Failed to save application settings file.", "Saving the application settings file returned with an error.")
|
||||
MAKE_ERROR_MSG(-1020, SAVE_CONFIG_FILE_ERROR, "Failed to save the config file.", "Saving the configuration file returned with an error.")
|
||||
MAKE_ERROR_MSG(-1021, CANNOT_REMOVE_INSTALL_DIR, "Cannot remove existing installation directory.", "Failed to remove an existing installation directory.")
|
||||
MAKE_ERROR_MSG(-1022, CREATE_INSTALL_DIR_ERROR, "Cannot create installation directory.", "Failed to create the installation directory.")
|
||||
MAKE_ERROR_MSG(-1023, CREATE_TARGET_DIR_ERROR, "Cannot create target root directory.", "Failed to create the target root directory.")
|
||||
MAKE_ERROR_MSG(-1024, CREATE_CONFIG_DIR_ERROR, "Cannot create config target directory.", "Failed to create the config target directory.")
|
||||
MAKE_ERROR_MSG(-1026, NO_SOURCE_FILES, "No source files were found.", "No source files were found to add to the package.")
|
||||
MAKE_ERROR_MSG(-1027, PACKAGE_CREATION_ERROR, "A compose package error has occurred.", "An error has occurred during the package creation.")
|
||||
MAKE_ERROR_MSG(-1028, PACKAGE_READ_ERROR, "A read package error has occurred.", "An error has occurred while reading the package.")
|
||||
|
||||
////////// SDV TRACE MONITOR ERROR CODES ////////////
|
||||
MAKE_ERROR_MSG(-5500, TRACE_MON_REG_HNDLR_ERROR, "Failed to register application control handler.", "The OS returned an error during the registration of the application control handler.")
|
||||
MAKE_ERROR_MSG(-5501, TRACE_MON_FIFO_OPEN_ERROR, "Failed to open the trace fifo.", "Failure trying to open a connection to the trace fifo.")
|
||||
|
||||
|
||||
|
||||
MAKE_ERROR_MSG(-2051, LOAD_DBC_FILE_ERROR, "Cannot load the DBC file.", "Trying to read the DBC file failed.")
|
||||
MAKE_ERROR_MSG(-2052, COMPILE_ERROR, "Failed to compile.", "An compilation attempt failed.")
|
||||
MAKE_ERROR_MSG(-2052, BASIC_SERVICE_DATA_ERROR, "Cannot find vehicle device.", "Creating basic service component failed.")
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef SUPPRESS_NO_ERROR
|
||||
#pragma pop_macro("NO_ERROR")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // !defined EXECUTABLES_ERROR_MSG
|
||||
23
sdv_executables/sdv_control/CMakeLists.txt
Normal file
23
sdv_executables/sdv_control/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# Define project
|
||||
project (sdv_control VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# Add include directories
|
||||
include_directories(../export)
|
||||
|
||||
# Define the executable
|
||||
add_executable(sdv_control
|
||||
main.cpp
|
||||
"list_elements.cpp"
|
||||
"list_elements.h"
|
||||
"startup_shutdown.h"
|
||||
"startup_shutdown.cpp"
|
||||
"context.h"
|
||||
"print_table.h" "start_stop_service.cpp" "start_stop_service.h" "installation.h" "installation.cpp")
|
||||
|
||||
target_link_libraries(sdv_control ${CMAKE_DL_LIBS})
|
||||
|
||||
# Build dependencies
|
||||
add_dependencies(sdv_control core_services)
|
||||
|
||||
# Appending the executable to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} sdv_control PARENT_SCOPE)
|
||||
52
sdv_executables/sdv_control/context.h
Normal file
52
sdv_executables/sdv_control/context.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef CONTEXT_H
|
||||
#define CONTEXT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <support/string.h>
|
||||
#include <support/sequence.h>
|
||||
|
||||
/**
|
||||
* @brief SDV context
|
||||
*/
|
||||
struct SContext
|
||||
{
|
||||
bool bSilent = false; ///< Silence flag
|
||||
bool bVerbose = false; ///< Verbose flag
|
||||
bool bServerSilent = false; ///< Silence flag of server
|
||||
bool bServerVerbose = false; ///< Verbose flag of server
|
||||
uint32_t uiInstanceID = 1000; ///< Instance ID
|
||||
bool bListNoHdr = false; ///< Do not print a header with the listing table.
|
||||
bool bListShort = false; ///< Print only a shortened list with one column.
|
||||
sdv::sequence<sdv::u8string> seqCmdLine; ///< The commands provided on the command line.
|
||||
std::filesystem::path pathInstallDir; ///< Optional installation directory.
|
||||
};
|
||||
|
||||
#include <cctype> // std::tolower
|
||||
#include <algorithm> // std::equal
|
||||
|
||||
/**
|
||||
* @brief Compare whether two characters are identical when both are converted to lower case.
|
||||
* @remarks Cannot deal with Unicode letters comprising of more than one characters.
|
||||
* @param[in] cLeft First character
|
||||
* @param[in] cRight Second character
|
||||
* @return The case independent equality of the characters.
|
||||
*/
|
||||
inline bool ichar_equals(char cLeft, char cRight)
|
||||
{
|
||||
return std::tolower(static_cast<unsigned char>(cLeft)) ==
|
||||
std::tolower(static_cast<unsigned char>(cRight));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare for case-independent equality.
|
||||
* @param[in] rssLeft Reference to the left string.
|
||||
* @param[in] rssRight Reference to the right string.
|
||||
* @return The case-independent equality of the strings.
|
||||
*/
|
||||
inline bool iequals(const std::string& rssLeft, const std::string& rssRight)
|
||||
{
|
||||
return std::equal(rssLeft.begin(), rssLeft.end(), rssRight.begin(), rssRight.end(), ichar_equals);
|
||||
}
|
||||
|
||||
#endif // !defined CONTEXT_H
|
||||
124
sdv_executables/sdv_control/installation.cpp
Normal file
124
sdv_executables/sdv_control/installation.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "installation.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
void InstallationHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "INSTALL", "UPDATE" or "UNINSTALL".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing install/update/uninstall command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "INSTALL"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control INSTALL <name> [files...] [options...]\n\n"
|
||||
"Make a new installation with a set of files. This command succeeds when the files contain at least one component "
|
||||
"module and another installation with the same name is not existing. Complex services are automatically added to the "
|
||||
"configuration.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "UPDATE"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control UPDATE <name> [files...] [options...]\n\n"
|
||||
"Update an existing installation. This will not remove any configuration (unless a component is not available any "
|
||||
"more after, or a new component was added by the update.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "UNINSTALL"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control UNINSTALL <name> [files...] [options...]\n\n"
|
||||
"Remove an existing installation. This will remove the configuration for the components as well. Dependent components "
|
||||
"become inactive and will be activated again when the component is installed again.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid install/update/uninstall command..." << std::endl;
|
||||
}
|
||||
|
||||
int Install(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "INSTALL"
|
||||
if (rsContext.seqCmdLine.size() < 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for installation command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "INSTALL"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command : " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Followed by the installation name
|
||||
//std::string ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPO_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->CreateObject(ssClass, ssName, {});
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << START_OBJECT_ERROR_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return START_OBJECT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int Update(const SContext& /*rsContext*/)
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int Uninstall(const SContext& /*rsContext*/)
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
39
sdv_executables/sdv_control/installation.h
Normal file
39
sdv_executables/sdv_control/installation.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef INSTALLATION_H
|
||||
#define INSTALLATION_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for installing, updating and uninstalling components.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void InstallationHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Install components.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Install(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Update installation.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Update(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Uninstall components.
|
||||
* @details The command line context.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int Uninstall(const SContext& rsContext);
|
||||
|
||||
#endif // !defined INSTALLATION_H
|
||||
416
sdv_executables/sdv_control/list_elements.cpp
Normal file
416
sdv_executables/sdv_control/list_elements.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
#include "list_elements.h"
|
||||
#include "print_table.h"
|
||||
#include <interfaces/config.h>
|
||||
#include <support/sdv_core.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include "../../global/flags.h"
|
||||
#include "../error_msg.h"
|
||||
|
||||
void ListHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "LIST"
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing listing command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "LIST"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Which list command help is requested
|
||||
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
|
||||
if (rsContext.seqCmdLine.size() >= 2)
|
||||
{
|
||||
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
|
||||
}
|
||||
|
||||
// Print help if requested
|
||||
if (!rsContext.bSilent)
|
||||
{
|
||||
switch (eListCommand)
|
||||
{
|
||||
case EListCommand::modules:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST MODULES [options...]\n\nShow a list of all loaded modules.\n");
|
||||
break;
|
||||
case EListCommand::classes:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CLASSES [options...]\n\nShow a list of available component classes.\n");
|
||||
break;
|
||||
case EListCommand::components:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST COMPONENTS [options...]\n\nShow a list of all loaded components.\n");
|
||||
break;
|
||||
case EListCommand::installations:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST INSTALLATIONS [options...]\n\nShow a list of all installations.\n");
|
||||
break;
|
||||
case EListCommand::connections:
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control LIST CONNECTIONS [options...]\n\nShow a list of all connected applications.\n");
|
||||
break;
|
||||
default:
|
||||
CCommandLine::PrintHelpText(std::cout, R"code(Usage: sdv_control LIST <list_command> [options...]
|
||||
|
||||
Supported listing commands:
|
||||
LIST MODULES Show a list of loaded server modules.
|
||||
LIST CLASSES Show a list of available component classes.
|
||||
LIST COMPONENTS Show a list of instantiated server components
|
||||
LIST INSTALLATIONS Show a list of installations.
|
||||
LIST CONNECTIONS Show a list of current connections.
|
||||
|
||||
)code");
|
||||
break;
|
||||
}
|
||||
std::cout << "Options:\n";
|
||||
std::cout << " --no_header Do not print a header for the listing table.\n";
|
||||
std::cout << " --short Print only the most essential information as one column.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
int ListElements(const SContext& rsContext, std::ostream& rstream /*= std::cout*/)
|
||||
{
|
||||
// First argument should be "LIST"
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "LIST"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Which list command help is requested
|
||||
enum class EListCommand { unknown, modules, classes, components, installations, connections } eListCommand = EListCommand::unknown;
|
||||
if (rsContext.seqCmdLine.size() >= 2)
|
||||
{
|
||||
if (iequals(rsContext.seqCmdLine[1], "MODULES")) eListCommand = EListCommand::modules;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CLASSES")) eListCommand = EListCommand::classes;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "COMPONENTS")) eListCommand = EListCommand::components;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "INSTALLATIONS")) eListCommand = EListCommand::installations;
|
||||
else if (iequals(rsContext.seqCmdLine[1], "CONNECTIONS")) eListCommand = EListCommand::connections;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
{
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Missing listing command.." << std::endl << std::endl;
|
||||
ListHelp(rsContext);
|
||||
}
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << "." << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
int iRet = -100;
|
||||
switch (eListCommand)
|
||||
{
|
||||
case EListCommand::modules:
|
||||
iRet = ListModules(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::classes:
|
||||
iRet = ListClasses(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::components:
|
||||
iRet = ListComponents(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::installations:
|
||||
iRet = ListInstallations(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
case EListCommand::connections:
|
||||
iRet = ListConnections(rsContext, ptrRepository, rstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
int ListModules(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IModuleInfo* pModuleInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).
|
||||
GetInterface<sdv::core::IModuleInfo>();
|
||||
if (!pModuleInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << MODULE_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return MODULE_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Relative path from exe
|
||||
auto fnPrintRelPath = [](const sdv::u8string& rssPath)
|
||||
{
|
||||
std::filesystem::path path = rssPath.c_str();
|
||||
if (path.is_relative()) return path.generic_u8string();
|
||||
return path.lexically_relative(GetExecDirectory()).generic_u8string();
|
||||
};
|
||||
|
||||
// Create the module list
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 1>> vecShortModuleList;
|
||||
vecShortModuleList.push_back({ "Path" });
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
vecShortModuleList.push_back({ fnPrintRelPath(rsModuleInfo.ssPath) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortModuleList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 5>> vecModuleList;
|
||||
vecModuleList.push_back({ "Module ID", "Filename", "Version", "Active", "Path" });
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
vecModuleList.push_back({
|
||||
std::to_string(static_cast<int64_t>(rsModuleInfo.tModuleID)),
|
||||
rsModuleInfo.ssFilename,
|
||||
std::to_string(rsModuleInfo.uiVersion / 100) + "." + std::to_string(rsModuleInfo.uiVersion % 100),
|
||||
(rsModuleInfo.bActive ? " +" : " -"),
|
||||
fnPrintRelPath(rsModuleInfo.ssPath) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecModuleList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListClasses(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IModuleInfo* pModuleInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).
|
||||
GetInterface<sdv::core::IModuleInfo>();
|
||||
if (!pModuleInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << MODULE_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return MODULE_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Class type
|
||||
auto fnPrintClassType = [](sdv::EObjectType eType)
|
||||
{
|
||||
switch (eType)
|
||||
{
|
||||
case sdv::EObjectType::SystemObject: return "SystemObject";
|
||||
case sdv::EObjectType::Device: return "Device";
|
||||
case sdv::EObjectType::BasicService: return "BasicService";
|
||||
case sdv::EObjectType::ComplexService: return "ComplexService";
|
||||
case sdv::EObjectType::Application: return "Application";
|
||||
case sdv::EObjectType::Proxy: return "Proxy";
|
||||
case sdv::EObjectType::Stub: return "Stub";
|
||||
case sdv::EObjectType::Utility: return "Utility";
|
||||
default: return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
// Class flags
|
||||
auto fnPrintClassFlags = [](uint32_t uiFlags)
|
||||
{
|
||||
hlpr::flags<sdv::EObjectFlags> flags(uiFlags);
|
||||
std::stringstream sstream;
|
||||
if (flags.check(sdv::EObjectFlags::singleton))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Singleton";
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Dependencies
|
||||
auto fnPrintList = [](const sdv::sequence<sdv::u8string>& rseqList)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
for (const sdv::u8string& rss : rseqList)
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << rss;
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Create the module list
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 2>> vecShortClassList;
|
||||
vecShortClassList.push_back({ "Class name", "Aliases"});
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
{
|
||||
sdv::sequence<sdv::SClassInfo> seqClasses = pModuleInfo->GetClassList(rsModuleInfo.tModuleID);
|
||||
for (const sdv::SClassInfo& rsClassInfo : seqClasses)
|
||||
vecShortClassList.push_back({ rsClassInfo.ssClassName, fnPrintList(rsClassInfo.seqClassAliases) });
|
||||
}
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortClassList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 7>> vecClassList;
|
||||
vecClassList.push_back({ "Class name", "Aliases", "Default name", "Type", "Flags", "Module ID", "Dependencies" });
|
||||
sdv::sequence<sdv::core::SModuleInfo> seqModules = pModuleInfo->GetModuleList();
|
||||
for (const sdv::core::SModuleInfo& rsModuleInfo : seqModules)
|
||||
{
|
||||
sdv::sequence<sdv::SClassInfo> seqClasses = pModuleInfo->GetClassList(rsModuleInfo.tModuleID);
|
||||
for (const sdv::SClassInfo& rsClassInfo : seqClasses)
|
||||
vecClassList.push_back({
|
||||
rsClassInfo.ssClassName,
|
||||
fnPrintList(rsClassInfo.seqClassAliases),
|
||||
rsClassInfo.ssDefaultObjectName,
|
||||
fnPrintClassType(rsClassInfo.eType),
|
||||
fnPrintClassFlags(rsClassInfo.uiFlags),
|
||||
std::to_string(static_cast<int64_t>(rsModuleInfo.tModuleID)),
|
||||
fnPrintList(rsClassInfo.seqDependencies) });
|
||||
}
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecClassList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IRepositoryInfo* pRepoInfo = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryInfo>();
|
||||
if (!pRepoInfo)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Class type
|
||||
auto fnPrintClassType = [](sdv::EObjectType eType)
|
||||
{
|
||||
switch (eType)
|
||||
{
|
||||
case sdv::EObjectType::SystemObject: return "SystemObject";
|
||||
case sdv::EObjectType::Device: return "Device";
|
||||
case sdv::EObjectType::BasicService: return "BasicService";
|
||||
case sdv::EObjectType::ComplexService: return "ComplexService";
|
||||
case sdv::EObjectType::Application: return "Application";
|
||||
case sdv::EObjectType::Proxy: return "Proxy";
|
||||
case sdv::EObjectType::Stub: return "Stub";
|
||||
case sdv::EObjectType::Utility: return "Utility";
|
||||
default: return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
// Object flags
|
||||
auto fnPrintObjectFlags = [](uint32_t uiFlags)
|
||||
{
|
||||
hlpr::flags<sdv::core::EObjectInfoFlags> flags(uiFlags);
|
||||
std::stringstream sstream;
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_controlled))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Controlled";
|
||||
}
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_foreign))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Foreign";
|
||||
}
|
||||
if (flags.check(sdv::core::EObjectInfoFlags::object_isolated))
|
||||
{
|
||||
if (!sstream.str().empty()) sstream << ", ";
|
||||
sstream << "Isolated";
|
||||
}
|
||||
return std::string("{") + sstream.str() + std::string("}");
|
||||
};
|
||||
|
||||
// Create the object list
|
||||
if (rsContext.bListShort)
|
||||
{
|
||||
std::vector<std::array<std::string, 6>> vecShortObjectList;
|
||||
vecShortObjectList.push_back({ "Object name" });
|
||||
sdv::sequence<sdv::core::SObjectInfo> seqObjects = pRepoInfo->GetObjectList();
|
||||
for (const sdv::core::SObjectInfo& rsObjectInfo : seqObjects)
|
||||
vecShortObjectList.push_back({ rsObjectInfo.ssObjectName });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecShortObjectList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::array<std::string, 6>> vecObjectList;
|
||||
vecObjectList.push_back({ "Object ID", "Class name", "Object name", "Type", "Flags", "Module ID" });
|
||||
sdv::sequence<sdv::core::SObjectInfo> seqObjects = pRepoInfo->GetObjectList();
|
||||
for (const sdv::core::SObjectInfo& rsObjectInfo : seqObjects)
|
||||
vecObjectList.push_back({
|
||||
std::to_string(static_cast<int64_t>(rsObjectInfo.tModuleID)),
|
||||
rsObjectInfo.sClassInfo.ssClassName,
|
||||
rsObjectInfo.ssObjectName,
|
||||
fnPrintClassType(rsObjectInfo.sClassInfo.eType),
|
||||
fnPrintObjectFlags(rsObjectInfo.uiFlags),
|
||||
std::to_string(static_cast<int64_t>(rsObjectInfo.tModuleID)) });
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecObjectList, rstream, rsContext.bListNoHdr);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream)
|
||||
{
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = rptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::installation::IAppInstall* pAppInstall = nullptr;
|
||||
if (pObjectAccess)
|
||||
pAppInstall = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ConfigService")).
|
||||
GetInterface<sdv::installation::IAppInstall>();
|
||||
if (!pAppInstall)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONFIG_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return CONFIG_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object list
|
||||
std::vector<std::array<std::string, 1>> vecInstallList;
|
||||
vecInstallList.push_back({"Installation"});
|
||||
sdv::sequence<sdv::u8string> seqInstallations = pAppInstall->GetInstallations();
|
||||
for (const sdv::u8string& rssInstallation : seqInstallations)
|
||||
vecInstallList.push_back({
|
||||
rssInstallation});
|
||||
|
||||
// Print the module list
|
||||
PrintTable(vecInstallList, rstream, rsContext.bListNoHdr);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ListConnections(const SContext& /*rsContext*/, const sdv::TObjectPtr& /*rptrRepository*/, std::ostream& /*rstream = std::cout */ )
|
||||
{
|
||||
std::cout << "ERROR: " << NOT_IMPLEMENTED_MSG << " :-(" << std::endl;
|
||||
return NOT_IMPLEMENTED;
|
||||
}
|
||||
69
sdv_executables/sdv_control/list_elements.h
Normal file
69
sdv_executables/sdv_control/list_elements.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef LIST_ELEMENTS_H
|
||||
#define LIST_ELEMENTS_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for listing elements.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void ListHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief List elements in a table. Base function. The elements to list are to be parsed from the arguments. The context could
|
||||
* indicate additional flags.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListElements(const SContext& rsContext, std::ostream& rstream = std::cout);
|
||||
|
||||
/**
|
||||
* @brief List the loaded server modules.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListModules(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the available component classes.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListClasses(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the instantiated server components.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListComponents(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the installations.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListInstallations(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
/**
|
||||
* @brief List the current connections.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @param[in] rptrRepository Reference to the saerver repository.
|
||||
* @param[in] rstream The output stream to use for printing (table only).
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ListConnections(const SContext& rsContext, const sdv::TObjectPtr& rptrRepository, std::ostream& rstream);
|
||||
|
||||
#endif // !defined LIST_ELEMENTS_H
|
||||
223
sdv_executables/sdv_control/main.cpp
Normal file
223
sdv_executables/sdv_control/main.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "../../global/process_watchdog.h"
|
||||
#include <support/sdv_core.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.cpp"
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include <support/mem_access.h>
|
||||
#include <support/sdv_core.h>
|
||||
#include <support/app_control.h>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include "context.h"
|
||||
#include "startup_shutdown.h"
|
||||
#include "list_elements.h"
|
||||
#include "start_stop_service.h"
|
||||
#include "installation.h"
|
||||
#include "../error_msg.h"
|
||||
|
||||
/**
|
||||
* @brief Add a slag to the string.
|
||||
* @param[in] rssString The string to add a flag to.
|
||||
* @param[in] rssFlag The flag text to add.
|
||||
*/
|
||||
void AddFlagString(std::string& rssString, const std::string& rssFlag)
|
||||
{
|
||||
if (!rssString.empty()) rssString += " | ";
|
||||
rssString += rssFlag;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
|
||||
#else
|
||||
extern "C" int main(int iArgc, const char* rgszArgv[])
|
||||
#endif
|
||||
{
|
||||
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
|
||||
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
|
||||
// threaded and a termination is initiated.
|
||||
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
|
||||
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
|
||||
CProcessWatchdog watchdog;
|
||||
|
||||
// If not set, set the runtime location to the EXE directory.
|
||||
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
|
||||
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
|
||||
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
|
||||
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
|
||||
|
||||
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
|
||||
SContext sContext;
|
||||
bool bError = false;
|
||||
bool bHelp = false;
|
||||
bool bVersion = false;
|
||||
std::string ssArgError;
|
||||
try
|
||||
{
|
||||
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help. Use <COMMAND> --help for specific help on the command.");
|
||||
rArgHelpDef.AddSubOptionName("help");
|
||||
auto& rArgSilentDef = cmdln.DefineOption("s", sContext.bSilent, "Do not show any information on std::cout. Not compatible with 'verbose'.");
|
||||
rArgSilentDef.AddSubOptionName("silent");
|
||||
auto& rArgVerboseDef = cmdln.DefineOption("v", sContext.bVerbose, "Provide verbose information. Not compatible with 'silent'.");
|
||||
rArgVerboseDef.AddSubOptionName("verbose");
|
||||
cmdln.DefineSubOption("version", bVersion, "Show version information.");
|
||||
cmdln.DefineSubOption("instance", sContext.uiInstanceID, "The instance ID of the SDV instance (default ID is 1000).");
|
||||
cmdln.DefineSubOption("server_silent", sContext.bServerSilent, "Only used with STARTUP command: Server is started using "
|
||||
"silent option. Not compatible with 'server_verbose'.");
|
||||
cmdln.DefineSubOption("server_verbose", sContext.bServerVerbose, "Only used with STARTUP command: Server is started using "
|
||||
"verbose option. Not compatible with 'server_silent'.");
|
||||
cmdln.DefineSubOption("install_dir", sContext.pathInstallDir, "Only used with STARTUP command: Installation directory "
|
||||
"(absolute or relative to the sdv_core executable).");
|
||||
cmdln.DefineSubOption("no_header", sContext.bListNoHdr, "Only used with LIST command: Do not print a header for the "
|
||||
"listing table.");
|
||||
cmdln.DefineSubOption("short", sContext.bListShort, "Only used with LIST command: Print only the most essential "
|
||||
"information as one column.");
|
||||
cmdln.DefineDefaultArgument(sContext.seqCmdLine, "COMMAND");
|
||||
|
||||
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
|
||||
} catch (const SArgumentParseException& rsExcept)
|
||||
{
|
||||
ssArgError = rsExcept.what();
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if (!sContext.bSilent)
|
||||
{
|
||||
std::cout << "SDV Server Control Utility" << std::endl;
|
||||
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
|
||||
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
if (!ssArgError.empty() && !sContext.bSilent)
|
||||
std::cerr << "ERROR: " << ssArgError << std::endl;
|
||||
|
||||
if (!bHelp && !bVersion && sContext.seqCmdLine.empty())
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: Missing command!" << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
enum class ECommand { unknown, startup, shutdown, list, install, update, uninstall, start, stop } eCommand = ECommand::unknown;
|
||||
if (!sContext.seqCmdLine.empty())
|
||||
{
|
||||
if (iequals(sContext.seqCmdLine[0], "STARTUP")) eCommand = ECommand::startup;
|
||||
else if (iequals(sContext.seqCmdLine[0], "SHUTDOWN")) eCommand = ECommand::shutdown;
|
||||
else if (iequals(sContext.seqCmdLine[0], "LIST")) eCommand = ECommand::list;
|
||||
else if (iequals(sContext.seqCmdLine[0], "INSTALL")) eCommand = ECommand::install;
|
||||
else if (iequals(sContext.seqCmdLine[0], "UPDATE")) eCommand = ECommand::update;
|
||||
else if (iequals(sContext.seqCmdLine[0], "UNINSTALL")) eCommand = ECommand::uninstall;
|
||||
else if (iequals(sContext.seqCmdLine[0], "START")) eCommand = ECommand::start;
|
||||
else if (iequals(sContext.seqCmdLine[0], "STOP")) eCommand = ECommand::stop;
|
||||
else
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: Invalid command: " << sContext.seqCmdLine[0] << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHelp)
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
{
|
||||
if (bError)
|
||||
std::cout << std::endl;
|
||||
switch (eCommand)
|
||||
{
|
||||
case ECommand::startup:
|
||||
case ECommand::shutdown:
|
||||
StartupShutdownHelp(sContext);
|
||||
break;
|
||||
case ECommand::start:
|
||||
case ECommand::stop:
|
||||
StartStopServiceHelp(sContext);
|
||||
break;
|
||||
case ECommand::list:
|
||||
ListHelp(sContext);
|
||||
break;
|
||||
case ECommand::install:
|
||||
case ECommand::update:
|
||||
case ECommand::uninstall:
|
||||
InstallationHelp(sContext);
|
||||
break;
|
||||
default:
|
||||
cmdln.PrintHelp(std::cout, R"code(Supported commands:
|
||||
STARTUP Start the core application server
|
||||
SHUTDOWN Stop the core application server
|
||||
LIST List module/classes/component/installation/connection information.
|
||||
INSTALL Install a new application or service.
|
||||
UPDATE Update an existing installation.
|
||||
UNINSTALL Uninstall an installed application or service.
|
||||
START Start a service (complex services only).
|
||||
STOP Stop a service (complex services only).
|
||||
)code");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bError ? CMDLN_ARG_ERR : NO_ERROR;
|
||||
}
|
||||
if (bError) return CMDLN_ARG_ERR;
|
||||
|
||||
if (bVersion)
|
||||
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
|
||||
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
|
||||
|
||||
if (sContext.seqCmdLine.empty()) return NO_ERROR; // Done.
|
||||
|
||||
// Start the application control
|
||||
if (sContext.bVerbose)
|
||||
std::cout << "Starting local application control.." << std::endl;
|
||||
sdv::app::CAppControl appcontrol;
|
||||
std::string ssAppConfig = std::string(R"code(
|
||||
[Application]
|
||||
Mode = "Maintenance"
|
||||
Instance = )code") + std::to_string(sContext.uiInstanceID) + R"code(
|
||||
)code";
|
||||
if (!appcontrol.Startup(ssAppConfig))
|
||||
{
|
||||
if (!sContext.bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_STARTUP_ERROR_MSG << std::endl;
|
||||
return APP_CONTROL_STARTUP_ERROR;
|
||||
}
|
||||
|
||||
int iRet = 0;
|
||||
switch (eCommand)
|
||||
{
|
||||
case ECommand::startup:
|
||||
iRet = StartupSDVServer(sContext);
|
||||
break;
|
||||
case ECommand::shutdown:
|
||||
iRet = ShutdownSDVServer(sContext);
|
||||
break;
|
||||
case ECommand::list:
|
||||
iRet = ListElements(sContext);
|
||||
break;
|
||||
case ECommand::start:
|
||||
iRet = StartService(sContext);
|
||||
break;
|
||||
case ECommand::stop:
|
||||
iRet = StopService(sContext);
|
||||
break;
|
||||
case ECommand::install:
|
||||
iRet = Install(sContext);
|
||||
break;
|
||||
case ECommand::update:
|
||||
iRet = Update(sContext);
|
||||
break;
|
||||
case ECommand::uninstall:
|
||||
iRet = Uninstall(sContext);
|
||||
break;
|
||||
default:
|
||||
std::cout << "Command missing :-(" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sContext.bVerbose) std::cout << "Shutting down local application control.." << std::endl;
|
||||
appcontrol.Shutdown();
|
||||
|
||||
return iRet;
|
||||
}
|
||||
83
sdv_executables/sdv_control/print_table.h
Normal file
83
sdv_executables/sdv_control/print_table.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef TABLE_H
|
||||
#define TABLE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @brief Print a table of a vector of rows.
|
||||
* @tparam nSize The array size.
|
||||
* @details the first line is the header.
|
||||
* @param[in] rvecRows Reference to the vector of rows.
|
||||
* @param[in] rstream The output stream to use for printing.
|
||||
* @param[in] bNoHeader When set, skip the first row (the header row).
|
||||
*/
|
||||
template <size_t nSize>
|
||||
void PrintTable(const std::vector<std::array<std::string, nSize>>& rvecRows, std::ostream& rstream, bool bNoHeader = false)
|
||||
{
|
||||
// Calculate the maximum length of the column by going through each cell.
|
||||
bool bSkipFirst = bNoHeader;
|
||||
size_t rgnLength[nSize] = {};
|
||||
for (const auto& rrgssRow : rvecRows)
|
||||
{
|
||||
if (bSkipFirst)
|
||||
{
|
||||
bSkipFirst = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
{
|
||||
if (rrgssRow[nIndex].size() > rgnLength[nIndex])
|
||||
rgnLength[nIndex] = rrgssRow[nIndex].size();
|
||||
}
|
||||
}
|
||||
|
||||
// Print a cell
|
||||
auto fnPrintCell = [&](size_t nIndex, const std::string& rssText)
|
||||
{
|
||||
// Print the text
|
||||
rstream << rssText;
|
||||
|
||||
// Check index
|
||||
if (nIndex == nSize - 1) // Last column; nl needed
|
||||
rstream << std::endl;
|
||||
else // Separator needed
|
||||
rstream << std::string(rgnLength[nIndex] - rssText.size() + 2, ' ');
|
||||
};
|
||||
|
||||
// Print each line
|
||||
bSkipFirst = bNoHeader;
|
||||
bool bInitialLine = !bNoHeader;
|
||||
for (const auto& rrgssRow : rvecRows)
|
||||
{
|
||||
if (bSkipFirst)
|
||||
{
|
||||
bSkipFirst = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start with a space if a header is present
|
||||
if (!bNoHeader)
|
||||
rstream << " ";
|
||||
|
||||
// Print the text
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
fnPrintCell(nIndex, rrgssRow[nIndex]);
|
||||
|
||||
// Need a vertical separator?
|
||||
if (bInitialLine)
|
||||
{
|
||||
size_t nSeparatorLength = 1;
|
||||
for (size_t nIndex = 0; nIndex < nSize; nIndex++)
|
||||
nSeparatorLength += rgnLength[nIndex] + 2;
|
||||
nSeparatorLength--;
|
||||
rstream << std::string(nSeparatorLength, '-') << std::endl;
|
||||
bInitialLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined TABLE_H
|
||||
176
sdv_executables/sdv_control/start_stop_service.cpp
Normal file
176
sdv_executables/sdv_control/start_stop_service.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "start_stop_service.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
void StartStopServiceHelp(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "START" or "STOP".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing start/stop command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "START"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control START <name> [options...]\n"
|
||||
" sdv_control START <class> <name> [options...]\n\n"
|
||||
"Start a complex service with the supplied object name as is defined in the configuration (first usage) or the "
|
||||
"supplied class name and with object name assignment and add to the configuration (second usage).\n"
|
||||
"Only complex services can be started. If the service depends on not running other services, these are started as "
|
||||
"well.\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "STOP"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control STOP <name> [options...]\n"
|
||||
" sdv_control STOP <ID> [options...]\n"
|
||||
" sdv_control STOP <class> [options...]\n"
|
||||
" sdv_control STOP <module> [options...]\n\n"
|
||||
"Stop the complex service(s) with the supplied object name (first usage), with supplied object ID (second usage), with "
|
||||
"supplied class name (third usage) or contained in the module with the supplied module name (fourth usage).\n"
|
||||
"Only complex services can be stopped. Dependent services are stopped as well. If one of object to be stopped is not a "
|
||||
"complex service, the command fails.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid start/stop command..." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
int StartService(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "START"
|
||||
if (rsContext.seqCmdLine.size() < 2)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for START command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Too many parameters for START command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "START"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command: " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->CreateObject(ssClass, ssName, {});
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << START_OBJECT_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return START_OBJECT_ERROR;
|
||||
}
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int StopService(const SContext& rsContext)
|
||||
{
|
||||
// First argument should be "STOP"
|
||||
if (rsContext.seqCmdLine.size() < 2)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Not enough parameters for STOP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 3)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Too many parameters for STOP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
if (!iequals(rsContext.seqCmdLine[0], "STOP"))
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid command : " << rsContext.seqCmdLine[0] << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
// Determine the service to start
|
||||
sdv::u8string ssClass, ssName;
|
||||
if (rsContext.seqCmdLine.size() == 3)
|
||||
{
|
||||
ssClass = rsContext.seqCmdLine[1];
|
||||
ssName = rsContext.seqCmdLine[2];
|
||||
} else
|
||||
ssName = rsContext.seqCmdLine[1];
|
||||
|
||||
// Try to connect
|
||||
sdv::TObjectPtr ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " Instance #" << rsContext.uiInstanceID << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REPOSITORY_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return REPOSITORY_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
// Create the object
|
||||
sdv::core::TObjectID tObjectID = pRepoControl->DestroyObject(ssName);
|
||||
if (!tObjectID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << STOP_OBJECT_ERROR_MSG << " Object name: " << ssName << std::endl;
|
||||
return STOP_OBJECT_ERROR;
|
||||
}
|
||||
|
||||
// All good...
|
||||
return NO_ERROR;
|
||||
}
|
||||
30
sdv_executables/sdv_control/start_stop_service.h
Normal file
30
sdv_executables/sdv_control/start_stop_service.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef START_STOP_SERVICE_H
|
||||
#define START_STOP_SERVICE_H
|
||||
|
||||
#include "context.h"
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <support/interface_ptr.h>
|
||||
|
||||
/**
|
||||
* @brief Help for start or stop a complex service.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void StartStopServiceHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Start the service.
|
||||
* @details The command line context includes the service to start or stop.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StartService(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Stop the complex service.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StopService(const SContext& rsContext);
|
||||
|
||||
#endif // !defined START_STOP_SERVICE_H
|
||||
206
sdv_executables/sdv_control/startup_shutdown.cpp
Normal file
206
sdv_executables/sdv_control/startup_shutdown.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "startup_shutdown.h"
|
||||
#include "../../global/cmdlnparser/cmdlnparser.h"
|
||||
#include <interfaces/process.h>
|
||||
#include <support/interface_ptr.h>
|
||||
#include <support/local_service_access.h>
|
||||
#include <interfaces/com.h>
|
||||
#include <interfaces/app.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
sdv::process::TProcessID g_tServerProcessID = 0;
|
||||
|
||||
/**
|
||||
* @brief Process lifetime monitor struct
|
||||
*/
|
||||
struct SProcessLifetimeCallback : sdv::IInterfaceAccess, sdv::process::IProcessLifetimeCallback
|
||||
{
|
||||
// Interface map
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(sdv::process::IProcessLifetimeCallback)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Called when the process was terminated.
|
||||
* @remarks The process return value is not always valid. The validity depends on the support of the underlying system.
|
||||
* @param[in] tProcessID The process ID of the process being terminated.
|
||||
* @param[in] iRetValueParam Process return value or 0 when not supported.
|
||||
*/
|
||||
virtual void ProcessTerminated([[maybe_unused]] /*in*/ sdv::process::TProcessID tProcessID, /*in*/ int64_t iRetValueParam) override
|
||||
{
|
||||
iRetValue = iRetValueParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the process return value or 0 when no value was set.
|
||||
* @return The process return value.
|
||||
*/
|
||||
int64_t GetRetValue() const
|
||||
{
|
||||
return iRetValue;
|
||||
}
|
||||
|
||||
int64_t iRetValue = 0; ///< Process return value to be updated by the process monitor.
|
||||
};
|
||||
|
||||
void StartupShutdownHelp(const SContext& rsContext)
|
||||
{
|
||||
// First and only argument should be "STARTUP" or "SHUTDOWN".
|
||||
if (rsContext.seqCmdLine.size() < 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: missing startup/shutdown command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (rsContext.seqCmdLine.size() > 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: too many commands following startup/shutdown command..." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "STARTUP"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control STARTUP [options...]\n\n"
|
||||
"Start the SDV server with the supplied instance ID. If no instance ID is supplied, use the default instance "
|
||||
"ID #1000.\n\n"
|
||||
"Options:\n"
|
||||
" --server_silent Server is started using silent option. Not compatible with 'server_verbose'.\n"
|
||||
" --server_verbose Server is started using verbose option. Not compatible with 'server_silent'.\n"
|
||||
" --install_dir Installation directory (absolute or relative to the sdv_core executable).\n\n");
|
||||
return;
|
||||
}
|
||||
if (iequals(rsContext.seqCmdLine[0], "SHUTDOWN"))
|
||||
{
|
||||
CCommandLine::PrintHelpText(std::cout, "Usage: sdv_control SHUTDOWN [options...]\n\nStop the SDV server with the supplied "
|
||||
"instance ID. If no instance ID is supplied, use the default instance ID #1000.\n\n");
|
||||
return;
|
||||
}
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: invalid startup/shutdown command..." << std::endl;
|
||||
}
|
||||
|
||||
int StartupSDVServer(const SContext& rsContext)
|
||||
{
|
||||
if (rsContext.seqCmdLine.size() != 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid arguments following STARTUP command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Starting the SDV Server..." << std::endl;
|
||||
|
||||
// Get the process control service
|
||||
sdv::process::IProcessControl* pProcessControl = sdv::core::GetObject<sdv::process::IProcessControl>("ProcessControlService");
|
||||
sdv::process::IProcessLifetime* pProcessLifetime = sdv::core::GetObject<sdv::process::IProcessLifetime>("ProcessControlService");
|
||||
if (!pProcessControl || !pProcessLifetime)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << PROCESS_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return PROCESS_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
sdv::sequence<sdv::u8string> seqArgTemp;
|
||||
if (rsContext.bVerbose)
|
||||
std::cout << "Instance ID: " << rsContext.uiInstanceID << std::endl;
|
||||
seqArgTemp.push_back("-server");
|
||||
seqArgTemp.push_back("--instance" + std::to_string(rsContext.uiInstanceID));
|
||||
seqArgTemp.push_back("--no_banner");
|
||||
if (rsContext.bServerSilent) seqArgTemp.push_back("--silent");
|
||||
if (rsContext.bServerVerbose) seqArgTemp.push_back("--verbose");
|
||||
if (!rsContext.pathInstallDir.empty())
|
||||
seqArgTemp.push_back("--install_dir\"" + rsContext.pathInstallDir.generic_u8string() + "\"");
|
||||
g_tServerProcessID = pProcessControl->Execute("sdv_core", seqArgTemp, sdv::process::EProcessRights::parent_rights);
|
||||
if (!g_tServerProcessID)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << STARTUP_CORE_ERROR_MSG << std::endl;
|
||||
return STARTUP_CORE_ERROR;
|
||||
}
|
||||
|
||||
// Register the process monitor...
|
||||
SProcessLifetimeCallback sProcessLifetimeCallback;
|
||||
uint32_t uiCookie = pProcessLifetime->RegisterMonitor(g_tServerProcessID, &sProcessLifetimeCallback);
|
||||
if (!uiCookie)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << REGISTER_PROCESS_MONITOR_ERROR_MSG << std::endl;
|
||||
return REGISTER_PROCESS_MONITOR_ERROR;
|
||||
}
|
||||
|
||||
if (rsContext.bVerbose)
|
||||
std::cout << "Process ID: " << g_tServerProcessID << std::endl;
|
||||
|
||||
// Wait for 3 seconds to see if the process terminates... (which should not occur).
|
||||
bool bTerminated = pProcessLifetime->WaitForTerminate(g_tServerProcessID, 3000);
|
||||
pProcessLifetime->UnregisterMonitor(uiCookie);
|
||||
if (bTerminated)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CORE_NOT_STARTED_MSG << " Instance: #" << rsContext.uiInstanceID << " Exit code: " <<
|
||||
sProcessLifetimeCallback.iRetValue << std::endl;
|
||||
return CORE_NOT_STARTED;
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << " SDV Server instance #:" << rsContext.uiInstanceID <<
|
||||
std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "SDV Server #" << rsContext.uiInstanceID << " has successfully started..." << std::endl;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int ShutdownSDVServer(const SContext& rsContext)
|
||||
{
|
||||
if (rsContext.seqCmdLine.size() != 1)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CMDLN_ARG_ERR_MSG << " Invalid arguments following SHUTDOWN command." << std::endl;
|
||||
return CMDLN_ARG_ERR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Connecting to the SDV #" << rsContext.uiInstanceID << " server..." << std::endl;
|
||||
|
||||
// Try to connect
|
||||
auto ptrRepository = sdv::com::ConnectToLocalServerRepository(rsContext.uiInstanceID);
|
||||
if (!ptrRepository)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << CONNECT_SDV_SERVER_ERROR_MSG << std::endl;
|
||||
return CONNECT_SDV_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Requesting shutdown..." << std::endl;
|
||||
sdv::core::IObjectAccess* pObjAccess = ptrRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
sdv::app::IAppShutdownRequest* pShutdownRequest = nullptr;
|
||||
if (pObjAccess)
|
||||
pShutdownRequest = sdv::TInterfaceAccessPtr(pObjAccess->GetObject("AppControlService")).
|
||||
GetInterface<sdv::app::IAppShutdownRequest>();
|
||||
if (pShutdownRequest)
|
||||
pShutdownRequest->RequestShutdown();
|
||||
ptrRepository.Clear();
|
||||
if (!pShutdownRequest)
|
||||
{
|
||||
if (!rsContext.bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_SERVICE_ACCESS_ERROR_MSG << std::endl;
|
||||
return APP_CONTROL_SERVICE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
if (!rsContext.bSilent)
|
||||
std::cout << "Shutdown initiated..." << std::endl;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
sdv::process::TProcessID GetServerProcessID()
|
||||
{
|
||||
return g_tServerProcessID;
|
||||
}
|
||||
39
sdv_executables/sdv_control/startup_shutdown.h
Normal file
39
sdv_executables/sdv_control/startup_shutdown.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef STARTUP_SHUTDOWN_H
|
||||
#define STARTUP_SHUTDOWN_H
|
||||
|
||||
#include "context.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <support/sequence.h>
|
||||
#include <support/string.h>
|
||||
#include <interfaces/process.h>
|
||||
|
||||
/**
|
||||
* @brief Help for startup or shutdown the server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
*/
|
||||
void StartupShutdownHelp(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Startup the SDV server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int StartupSDVServer(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Shutdown the SDV Server.
|
||||
* @param[in] rsContext Reference to the context.
|
||||
* @return The application exit code. 0 is no error.
|
||||
*/
|
||||
int ShutdownSDVServer(const SContext& rsContext);
|
||||
|
||||
/**
|
||||
* @brief Get the server process ID after a startup of the server.
|
||||
* @remarks The process ID is set when server execution is initiated. The presence of the process ID doesn't guarantee a successful
|
||||
* running of the server.
|
||||
* @return The process ID if the process execution was initiated. Or zero when the execution failed.
|
||||
*/
|
||||
sdv::process::TProcessID GetServerProcessID();
|
||||
|
||||
#endif // !defined STARTUP_SHUTDOWN_H
|
||||
16
sdv_executables/sdv_core/CMakeLists.txt
Normal file
16
sdv_executables/sdv_core/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# Define project
|
||||
project(sdv_core VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# build test application
|
||||
add_executable(sdv_core main.cpp)
|
||||
if (WIN32)
|
||||
target_link_libraries(sdv_core ${CMAKE_THREAD_LIBS_INIT} Ws2_32 Winmm Rpcrt4.lib)
|
||||
else()
|
||||
target_link_libraries(sdv_core ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} rt)
|
||||
endif()
|
||||
|
||||
# Build dependencies
|
||||
add_dependencies(sdv_core core_services)
|
||||
|
||||
# Appending the executable to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} sdv_core PARENT_SCOPE)
|
||||
192
sdv_executables/sdv_core/main.cpp
Normal file
192
sdv_executables/sdv_core/main.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
#include <support/sdv_core.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.cpp"
|
||||
#include "../../global/exec_dir_helper.h"
|
||||
#include <support/app_control.h>
|
||||
#include "../error_msg.h"
|
||||
|
||||
/**
|
||||
* @brief Main function of the executable.
|
||||
* @param[in] iArgc Amount of arguments provided.
|
||||
* @param[in] rgszArgv Array of C-string pointers. The first entry is the name or path to this executable.
|
||||
* @return Returns the executable's exit code.
|
||||
*/
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
|
||||
#else
|
||||
extern "C" int main(int iArgc, const char* rgszArgv[])
|
||||
#endif
|
||||
{
|
||||
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
|
||||
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
|
||||
// threaded and a termination is initiated.
|
||||
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
|
||||
// NOTE EVE 27.05.2025: in release builds, starting and ending the thread right after each other causes incorrect behavior and
|
||||
// leads in some cases to create a deadlock in the join-function. The solution is to add delays in the thread processing.
|
||||
bool bThreadStarted = false;
|
||||
std::thread thread = std::thread([&]()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
bThreadStarted = true;
|
||||
});
|
||||
while (!bThreadStarted) {std::this_thread::sleep_for(std::chrono::milliseconds(100));}
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
|
||||
// If not set, set the runtime location to the EXE directory.
|
||||
if (sdv::app::CAppControl::GetFrameworkRuntimeDirectory().empty())
|
||||
sdv::app::CAppControl::SetFrameworkRuntimeDirectory(GetExecDirectory());
|
||||
if (sdv::app::CAppControl::GetComponentInstallDirectory().empty())
|
||||
sdv::app::CAppControl::SetComponentInstallDirectory(GetExecDirectory());
|
||||
|
||||
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
|
||||
bool bHelp = false;
|
||||
bool bError = false;
|
||||
bool bSilent = false;
|
||||
bool bNoBanner = false;
|
||||
bool bVerbose = false;
|
||||
bool bVersion = false;
|
||||
bool bStandalone = false;
|
||||
bool bServer = false;
|
||||
std::filesystem::path pathConfig;
|
||||
uint32_t uiInstanceID = 1000; // Default instance is 1000
|
||||
std::filesystem::path pathInstallDir;
|
||||
std::string ssArgError;
|
||||
try
|
||||
{
|
||||
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help");
|
||||
rArgHelpDef.AddSubOptionName("help");
|
||||
auto& rArgSilentDef = cmdln.DefineOption("s", bSilent, "Do not show any information on STDOUT. Not compatible with 'verbose'.");
|
||||
rArgSilentDef.AddSubOptionName("silent");
|
||||
auto& rArgVerboseDef = cmdln.DefineOption("v", bVerbose, "Provide verbose information. Not compatible with 'silent'.");
|
||||
rArgVerboseDef.AddSubOptionName("verbose");
|
||||
cmdln.DefineSubOption("no_banner", bNoBanner, "Do not show banner information. Ignored when silent is activated.");
|
||||
cmdln.DefineSubOption("version", bVersion, "Show version information.");
|
||||
cmdln.DefineSubOption("instance", uiInstanceID, "The instance ID of the SDV instance (default ID is 1000).");
|
||||
cmdln.DefineOption("local", bStandalone, "Start the local version (default - no IPC available).");
|
||||
cmdln.DefineOption("server", bServer, "Start the server version (not compatible with the local version).");
|
||||
cmdln.DefineSubOption("install_dir", pathInstallDir, "Installation directory (absolute or relative to this executable).");
|
||||
cmdln.DefineDefaultArgument(pathConfig, "Configuration file to start running (compulsory; applicable for local version only).");
|
||||
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
|
||||
} catch (const SArgumentParseException& rsExcept)
|
||||
{
|
||||
ssArgError = rsExcept.what();
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if (!bSilent && !bNoBanner)
|
||||
{
|
||||
std::cout << "SDV core application" << std::endl;
|
||||
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
|
||||
std::cout << "Author: Erik Verhoeven" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
if (!ssArgError.empty() && !bSilent)
|
||||
std::cerr << "ERROR: " << ssArgError << std::endl;
|
||||
|
||||
if (bServer && bStandalone)
|
||||
{
|
||||
std::cerr << "ERROR: The commandline options -server and -local cannot be supplied at the same time." << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
bStandalone = !bServer;
|
||||
|
||||
if (!pathConfig.empty() && bServer)
|
||||
{
|
||||
std::cerr << "ERROR: Cannot supply a configuration when running as server." << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
else if (pathConfig.empty() && bStandalone)
|
||||
{
|
||||
std::cerr << "ERROR: Needing a configuration when running as local application." << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if (bHelp)
|
||||
{
|
||||
if (!bSilent)
|
||||
{
|
||||
if (bError)
|
||||
std::cout << std::endl;
|
||||
cmdln.PrintHelp(std::cout, "The core application is used to start the service framework for use by applications. The "
|
||||
"safe version using component isolation and installation manifests should be started with the -safe option and is "
|
||||
"for use in the vehicle. For local simulation the stand-alone version can be used.\n");
|
||||
}
|
||||
return bError ? CMDLN_ARG_ERR : NO_ERROR;
|
||||
}
|
||||
if (bError) return CMDLN_ARG_ERR;
|
||||
|
||||
if (bVersion || bVerbose)
|
||||
std::cout << "Version: " << (SDVFrameworkBuildVersion / 100) << "." << (SDVFrameworkBuildVersion % 100) << " build " <<
|
||||
SDVFrameworkSubbuildVersion << " interface " << SDVFrameworkInterfaceVersion << std::endl;
|
||||
if (!bSilent)
|
||||
{
|
||||
std::cout << "Running as: " << (bServer ? "server" : "local") << std::endl;
|
||||
std::cout << "Instance ID: " << uiInstanceID << std::endl;
|
||||
if (bStandalone)
|
||||
std::cout << "Config: " << pathConfig.generic_u8string() << std::endl;
|
||||
}
|
||||
if (bVerbose)
|
||||
std::cout << "Installation directory: " << pathInstallDir.generic_u8string() << std::endl;
|
||||
|
||||
// Create the startup config
|
||||
std::stringstream sstreamConfig;
|
||||
sstreamConfig << "[Application]" << std::endl;
|
||||
sstreamConfig << "Mode = \"" << (bServer ? "Main" : "Standalone") << "\"" << std::endl;
|
||||
sstreamConfig << "Instance = " << uiInstanceID << std::endl;
|
||||
if (!pathConfig.empty())
|
||||
sstreamConfig << "Config = \"" << pathConfig.generic_u8string() << "\"" << std::endl;
|
||||
if (!pathInstallDir.empty())
|
||||
{
|
||||
if (pathInstallDir.is_relative())
|
||||
sstreamConfig << "InstallDir = \"" << pathInstallDir.generic_u8string() << "\"" << std::endl;
|
||||
else
|
||||
sstreamConfig << "InstallDir = \"" << pathInstallDir.lexically_relative(GetExecDirectory()).generic_u8string() <<
|
||||
"\"" << std::endl;
|
||||
}
|
||||
|
||||
// Add console information
|
||||
if (bVerbose || bSilent)
|
||||
{
|
||||
sstreamConfig << "[Console]" << std::endl;
|
||||
sstreamConfig << "Report = ";
|
||||
if (bSilent) sstreamConfig << "\"Silent\"";
|
||||
else
|
||||
sstreamConfig << "\"Verbose\"";
|
||||
sstreamConfig << std::endl;
|
||||
}
|
||||
|
||||
if (bVerbose)
|
||||
std::cout << "Starting up..." << std::endl;
|
||||
|
||||
// Start the application control
|
||||
sdv::app::CAppControl appcontrol;
|
||||
if (!appcontrol.Startup(sstreamConfig.str()))
|
||||
{
|
||||
if (!bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_STARTUP_ERROR_MSG << std::endl;
|
||||
return APP_CONTROL_STARTUP_ERROR;
|
||||
}
|
||||
|
||||
// Start the running loop
|
||||
if (!appcontrol.RunLoop())
|
||||
{
|
||||
if (!bSilent)
|
||||
std::cerr << "ERROR: " << APP_CONTROL_DUPLICATE_INSTANCE_MSG << std::endl;
|
||||
return APP_CONTROL_DUPLICATE_INSTANCE;
|
||||
}
|
||||
|
||||
if (bVerbose)
|
||||
{
|
||||
std::cout << "Shutdown request received..." << std::endl;
|
||||
std::cout << "Shutting down..." << std::endl;
|
||||
}
|
||||
|
||||
// Shutdwown
|
||||
appcontrol.Shutdown();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
29
sdv_executables/sdv_dbc_util/CMakeLists.txt
Normal file
29
sdv_executables/sdv_dbc_util/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
# Define project
|
||||
project (sdv_dbc_util VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# Add include directories
|
||||
include_directories(../export)
|
||||
|
||||
# Define the executable
|
||||
add_executable(sdv_dbc_util
|
||||
main.cpp
|
||||
can_dl.h
|
||||
can_dl.cpp
|
||||
fmu.h
|
||||
fmu.cpp
|
||||
cmake_generator.cpp
|
||||
cmake_generator.h
|
||||
codegen_base.cpp
|
||||
"fmu_templates.h")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(sdv_dbc_util ${CMAKE_DL_LIBS} Rpcrt4.lib)
|
||||
else()
|
||||
target_link_libraries(sdv_dbc_util ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
# Build dependencies
|
||||
add_dependencies(sdv_dbc_util CompileCoreIDL)
|
||||
|
||||
# Appending the executable to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} sdv_dbc_util PARENT_SCOPE)
|
||||
1721
sdv_executables/sdv_dbc_util/can_dl.cpp
Normal file
1721
sdv_executables/sdv_dbc_util/can_dl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
198
sdv_executables/sdv_dbc_util/can_dl.h
Normal file
198
sdv_executables/sdv_dbc_util/can_dl.h
Normal file
@@ -0,0 +1,198 @@
|
||||
#ifndef CAN_DL_H
|
||||
#define CAN_DL_H
|
||||
|
||||
#include "../global/dbcparser/dbcparser.h"
|
||||
#include <fstream>
|
||||
#include "codegen_base.h"
|
||||
|
||||
/**
|
||||
* @brief CAN data link generator class.
|
||||
*/
|
||||
class CCanDataLinkGen : public CCodeGeneratorBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rpathOutputDir Reference to the outpur directory.
|
||||
* @param[in] rparser Reference to the DBC parser containing the definitions.
|
||||
* @param[in] rssVersion Reference to a string representing a version of the dbc file (could be empty).
|
||||
* @param[in] rssIfcName Reference to the string holding the interface name (could be empty).
|
||||
* @param[in] nIfcIdx The interface index (valid if no name is provided).
|
||||
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
|
||||
* sending and receiving functions for all nodes.
|
||||
*/
|
||||
CCanDataLinkGen(const std::filesystem::path& rpathOutputDir, const dbc::CDbcParser& rparser, const std::string& rssVersion,
|
||||
const std::string& rssIfcName, size_t nIfcIdx, const std::vector<std::string>& rvecNodes);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Keyword map for keyword replacement in a string.
|
||||
*/
|
||||
typedef std::map<std::string, std::string> CKeywordMap;
|
||||
|
||||
/**
|
||||
* @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 validates that the string represents a float
|
||||
* @param[in] rssInput Reference to the string representing a float.
|
||||
* @return Returns the input string. If '.' not found it adds ".0" to the string
|
||||
*/
|
||||
std::string StringMustBeFloatValue(const std::string& rssInput);
|
||||
|
||||
/**
|
||||
* @brief Composes a dbc file version information string
|
||||
* @param[in] rssVersion Reference to a string representing a version of the dbc file.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeDBCFileVersion(const std::string& rssVersion);
|
||||
|
||||
/**
|
||||
* @brief Provide code to determine the interface index based on the interface name (if supplied).
|
||||
* @param[in] rssIfcName Reference to the string holding the interface name (could be empty).
|
||||
* @return The code to insert during initialization.
|
||||
*/
|
||||
std::string CodeInitInterfaceIndex(const std::string& rssIfcName);
|
||||
|
||||
/**
|
||||
* @brief Provide code for the RX message definition.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the message definition for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeRxMessageDefinition(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Provide code for the TX message definition.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the message definition for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeTxMessageDefinition(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Provide code for the signal declaration.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide a declaration for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeSignalDecl(const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Initialize the RX message variable.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeInitVarRxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the TX message variable.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeInitVarTxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the RX message structure.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeInitRxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the TX message structure.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeInitTxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Terminate the RX message structure.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeTermRxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Terminate the TX message structure.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeTermTxMessage(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Provide the RX message structure functions.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeRxMessageFunctions(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Provide the TX message structure functions.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeTxMessageFunctions(const dbc::SMessageDef& rsMsg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the signal registration.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the registration for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeRegisterRxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Initialize the signal registration.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the registration for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeRegisterTxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Remove the signal registration.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the unregistration for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeUnregisterSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Process the signal data for the specific message.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the processing for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeProcessRxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Initialize the TX trigger with the signal..
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the trigger initialization for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string InitTrigger(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
/**
|
||||
* @brief Compose the message from the signal data.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the composition for.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeComposeTxSignal(const dbc::SMessageDef& rsMsg, const dbc::SSignalDef& rsSig);
|
||||
|
||||
std::filesystem::path m_pathProject; ///< Project file path
|
||||
std::filesystem::path m_pathHeader; ///< Header file path
|
||||
std::filesystem::path m_pathCpp; ///< C++ file path
|
||||
std::ofstream m_fstreamHeader; ///< The header file
|
||||
std::ofstream m_fstreamCpp; ///< The C++ file
|
||||
const dbc::CDbcParser& m_rparser; ///< Reference to the DBC parser.
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // !defined CAN_DL_H
|
||||
141
sdv_executables/sdv_dbc_util/cmake_generator.cpp
Normal file
141
sdv_executables/sdv_dbc_util/cmake_generator.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "cmake_generator.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
CDbcUtilCMakeGenerator::CDbcUtilCMakeGenerator(const std::filesystem::path& rpathOutputDir, const std::string& rssComponent)
|
||||
{
|
||||
if (rssComponent.empty()) return; // TODO: Exception
|
||||
|
||||
// Create project directory
|
||||
if (!rpathOutputDir.empty())
|
||||
m_pathProject = rpathOutputDir;
|
||||
if (!rssComponent.empty())
|
||||
m_pathProject /= "can_dl";
|
||||
std::filesystem::create_directories(m_pathProject);
|
||||
|
||||
// The source string
|
||||
std::string ssSource;
|
||||
|
||||
// File with "CMakeLists.txt" function; read completely if existing
|
||||
std::filesystem::path pathFile = m_pathProject / "CMakeLists.txt";
|
||||
if (std::filesystem::exists(pathFile))
|
||||
{
|
||||
std::ifstream stream;
|
||||
stream.open(pathFile);
|
||||
if (!stream.is_open()) return; // TODO: Exception: 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
|
||||
{
|
||||
ssSource = 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(%component% 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 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(%component% SHARED)
|
||||
|
||||
# Set extension to .sdv
|
||||
set_target_properties(%component% PROPERTIES PREFIX "")
|
||||
set_target_properties(%component% PROPERTIES SUFFIX ".sdv")
|
||||
)code";
|
||||
CKeywordMap mapKeywords;
|
||||
mapKeywords["component"] = rssComponent;
|
||||
ssSource = ReplaceKeywords(ssSource, 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) return; // TODO: Exception: throw CCompileException("Missing 'add_library' keyword.");
|
||||
|
||||
// Search for shared keyword
|
||||
nPos = fnNCFind("shared", nPos);
|
||||
if (nPos == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing 'shared' keyword.");
|
||||
nPos += 6;
|
||||
|
||||
// Build set with files
|
||||
size_t nStop = fnNCFind(")", nPos);
|
||||
if (nStop == std::string::npos) return; // TODO: Exception: 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();
|
||||
if (setFiles.find("datalink.h") == setFiles.end())
|
||||
ssSource.insert(nStop, std::string("\n datalink.h"));
|
||||
if (setFiles.find("datalink.cpp") == setFiles.end())
|
||||
ssSource.insert(nStop, std::string("\n datalink.cpp"));
|
||||
|
||||
// Write the file again if needed
|
||||
if (nSourceSize != ssSource.size())
|
||||
{
|
||||
std::ofstream stream;
|
||||
stream.open(pathFile, std::ofstream::trunc);
|
||||
if (!stream.is_open()) return; // TODO: Exception: throw CCompileException("Failed to open the CMakeLists.txt file for writing.");
|
||||
|
||||
// Write the complete source
|
||||
stream << ssSource;
|
||||
}
|
||||
}
|
||||
|
||||
CDbcUtilCMakeGenerator::~CDbcUtilCMakeGenerator()
|
||||
{}
|
||||
|
||||
30
sdv_executables/sdv_dbc_util/cmake_generator.h
Normal file
30
sdv_executables/sdv_dbc_util/cmake_generator.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef CMAKE_GENERATOR_H
|
||||
#define CMAKE_GENERATOR_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include "codegen_base.h"
|
||||
|
||||
/**
|
||||
* @brief CMake generator class.
|
||||
*/
|
||||
class CDbcUtilCMakeGenerator : public CCodeGeneratorBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rpathOutputDir Reference to the outpur directory.
|
||||
* @param[in] rssComponent Current component this CMake file is for.
|
||||
*/
|
||||
CDbcUtilCMakeGenerator(const std::filesystem::path& rpathOutputDir, const std::string& rssComponent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CDbcUtilCMakeGenerator();
|
||||
|
||||
private:
|
||||
std::filesystem::path m_pathProject; ///< Project file path
|
||||
};
|
||||
|
||||
#endif // !defined CMAKE_GENERATOR_H
|
||||
38
sdv_executables/sdv_dbc_util/codegen_base.cpp
Normal file
38
sdv_executables/sdv_dbc_util/codegen_base.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "codegen_base.h"
|
||||
#include <sstream>
|
||||
|
||||
std::string CCodeGeneratorBase::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)
|
||||
{
|
||||
// Internal error: missing second separator during code building.
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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())
|
||||
{
|
||||
// Internal error: invalid keyword during building code.
|
||||
nPos = nSeparator + 1;
|
||||
continue;
|
||||
}
|
||||
sstream << itKeyword->second;
|
||||
nPos = nSeparator + 1;
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
71
sdv_executables/sdv_dbc_util/codegen_base.h
Normal file
71
sdv_executables/sdv_dbc_util/codegen_base.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef CODEGEN_BASE_H
|
||||
#define CODEGEN_BASE_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
* @brief Code generator base class.
|
||||
*/
|
||||
class CCodeGeneratorBase
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Keyword map for keyword replacement in a string.
|
||||
*/
|
||||
typedef std::map<std::string, std::string> CKeywordMap;
|
||||
|
||||
/**
|
||||
* @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 Generator specific string generator. The std::to_string doesn't handle floating points very well.
|
||||
* @tparam T Type of the variable to stringetize.
|
||||
* @param[in] rtVar Reference to the variable.
|
||||
* @return The generated string object.
|
||||
*/
|
||||
template <typename T>
|
||||
static std::string to_string(const T& rtVar)
|
||||
{
|
||||
std::ostringstream sstream;
|
||||
sstream << rtVar;
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overloading for double.
|
||||
* @param[in] rdVar Reference to the double variable.
|
||||
* @return The generated string object.
|
||||
*/
|
||||
static std::string to_string(const double& rdVar)
|
||||
{
|
||||
std::ostringstream sstream;
|
||||
sstream << rdVar;
|
||||
if (std::round(rdVar) == rdVar) sstream << ".0";
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overloading for float.
|
||||
* @param[in] rfVar Reference to the float variable.
|
||||
* @return The generated string object.
|
||||
*/
|
||||
static std::string to_string(const float& rfVar)
|
||||
{
|
||||
std::ostringstream sstream;
|
||||
sstream << rfVar;
|
||||
if (std::round(rfVar) == rfVar) sstream << ".0";
|
||||
sstream << "f";
|
||||
return sstream.str();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined CODEGEN_BASE_H
|
||||
1205
sdv_executables/sdv_dbc_util/fmu.cpp
Normal file
1205
sdv_executables/sdv_dbc_util/fmu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
398
sdv_executables/sdv_dbc_util/fmu.h
Normal file
398
sdv_executables/sdv_dbc_util/fmu.h
Normal file
@@ -0,0 +1,398 @@
|
||||
#ifndef SOFTCAR_FMU_H
|
||||
#define SOFTCAR_FMU_H
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Rpc.h>
|
||||
#endif
|
||||
|
||||
#include "../global/dbcparser/dbcparser.h"
|
||||
#include <fstream>
|
||||
#include "codegen_base.h"
|
||||
|
||||
/**
|
||||
* @brief Signal definition structure
|
||||
*/
|
||||
struct signalDefinition
|
||||
{
|
||||
std::string message_name; ///< Message name
|
||||
std::string name; ///< Signal name
|
||||
std::string attributes; ///< Attributes
|
||||
uint32_t index = 0; ///< Index
|
||||
bool isInput = false; ///< Is input signal
|
||||
bool isDouble = false; ///< for FMU we distinguish only between integer and double (float)
|
||||
uint32_t uiSize = 0; ///< everything > 8 we declare as isDouble
|
||||
dbc::SSignalDef::EValueType signalType = dbc::SSignalDef::EValueType::signed_integer; ///< Signal type
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief CAN data link generator class.
|
||||
*/
|
||||
class CSoftcarFMUGen : public CCodeGeneratorBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rpathOutputDir Reference to the outpur directory.
|
||||
* @param[in] rparser Reference to the DBC parser containing the definitions.
|
||||
* @param[in] ssModelIdentifier Reference to the modelIdentifier of the FMU.
|
||||
* @param[in] rsVersion Reference to a string representing a version of the dbc file (could be empty).
|
||||
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
|
||||
* sending and receiving functions for all nodes.
|
||||
*/
|
||||
CSoftcarFMUGen(const std::filesystem::path& rpathOutputDir, const dbc::CDbcParser& rparser, const std::string& ssModelIdentifier, const std::string& rsVersion, const std::vector<std::string>& rvecNodes);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Keyword map for keyword replacement in a string.
|
||||
*/
|
||||
typedef std::map<std::string, std::string> CKeywordMap;
|
||||
|
||||
/**
|
||||
* @brief Add keywords to the map.
|
||||
* @param[in] rsModelIdentifier Reference to the modelIdentifier of the FMU.
|
||||
* @param[in] rsVersion Reference to a string representing a version of the dbc file (could be empty).
|
||||
* @param[in] rvecNodes Reference to a list of nodes this data link object is representing. An empty list will implement
|
||||
* @param[in] rmapKeywords Map with keywords to replace.
|
||||
* @return Returns the string with replacements.
|
||||
*/
|
||||
void UpdateKeywordMap(const std::string& rsModelIdentifier, const std::string& rsVersion,
|
||||
const std::vector<std::string>& rvecNodes, CKeywordMap& rmapKeywords) const;
|
||||
|
||||
/**
|
||||
* @brief Create files in the resources folder.
|
||||
* @param[in] rRootPath parent folder
|
||||
* @return Returns the string with replacements.
|
||||
*/
|
||||
void CreateResourcesFiles(const std::filesystem::path& rRootPath) const;
|
||||
|
||||
/**
|
||||
* @brief Create files in the source folder.
|
||||
* @param[in] rRootPath parent folder
|
||||
* @return Returns the string with replacements.
|
||||
*/
|
||||
void CreateSourceFiles(const std::filesystem::path& rRootPath) const;
|
||||
|
||||
/**
|
||||
* @brief Create files in the include folder.
|
||||
* @param[in] rRootPath parent folder
|
||||
* @return Returns the string with replacements.
|
||||
*/
|
||||
void CreateIncludeFiles(const std::filesystem::path& rRootPath) const;
|
||||
|
||||
/**
|
||||
* @brief Create files in the include folder.
|
||||
* @param[in] rRootPath parent folder
|
||||
* @param[in] rsModelIdentifier Reference to the modelIdentifier of the FMU.
|
||||
* @param[in] rmapKeywords Map with keywords to replace.
|
||||
* @return Returns the string with replacements.
|
||||
*/
|
||||
void CreateFMUFiles(const std::filesystem::path& rRootPath, const std::string& rsModelIdentifier, CKeywordMap& rmapKeywords) const;
|
||||
|
||||
/**
|
||||
* @brief Cleanup the directory except of the root cmake file
|
||||
* @param[in] rpathRootDirectory root folder.
|
||||
* @return Returns true if folder exists or could be created, otherwise false.
|
||||
*/
|
||||
bool CleanUpDirectory(const std::filesystem::path& rpathRootDirectory) const;
|
||||
|
||||
/**
|
||||
* @brief Create subfolder if not exists
|
||||
* @param[in] rpathRootDirectory root folder.
|
||||
* @param[in] rpathSubDirectory sub folder.
|
||||
* @return Returns true if folder exists or could be created, otherwise false.
|
||||
*/
|
||||
bool CreateDirectories(const std::filesystem::path& rpathRootDirectory, const std::filesystem::path& rpathSubDirectory) const;
|
||||
|
||||
/**
|
||||
* @brief Create content of the signal_identifier file
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string Code_AllSignalsIdentifierList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Create single signal line of the signal_identifier file
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string Code_SignalIdentifierList(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Replace keywords in a string.
|
||||
* @param[in] rsStr 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& rsStr, const CKeywordMap& rmapKeywords, char cMarker = '%');
|
||||
|
||||
/**
|
||||
* @brief Composes the fmi build description xml
|
||||
* @param[in] rsModelIdentifier Reference to model identifier.*
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeBuildDescriptionXML(const std::string& rsModelIdentifier) const;
|
||||
|
||||
/**
|
||||
* @brief Composes a dbc file version information string
|
||||
* @param[in] rsVersion Reference to a string representing a version of the dbc file.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeDBCFileVersion(const std::string& rsVersion) const;
|
||||
|
||||
/**
|
||||
* @brief returns a basic model identifier if not available
|
||||
* @param[in] rsModelIdentifier Reference to a string representing a version of the dbc file.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelIdentifier(const std::string& rsModelIdentifier) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the fmi xml file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeFMIFile_VariableList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the fmi xml file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeFMIFile_SignalVariableList(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the value reference in the config.h file.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rIndex Reference to the index of the variable starting with 0.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_Rx_ValueReference(const dbc::SMessageDef& rsMsg, uint32_t& rIndex,
|
||||
std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the value reference in the config.h file.
|
||||
* @param[in] rsMsg Reference to the DBC message to provide the code for.
|
||||
* @param[in] rIndex Reference to the index of the variable starting with 0.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_Tx_ValueReference(const dbc::SMessageDef& rsMsg, uint32_t& rIndex,
|
||||
std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the value reference in the config.h file.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the information for.
|
||||
* @param[in] index Reference to the index of the variable starting with 0.
|
||||
* @param[in] rsMessageName Reference to the message name.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_Rx_SignalForValueReference(const dbc::SSignalDef& rsSig, const uint32_t index,
|
||||
const std::string& rsMessageName, std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the value reference in the config.h file.
|
||||
* @param[in] rsSig Reference to the DBC signal to provide the information for.
|
||||
* @param[in] index Reference to the index of the variable starting with 0.
|
||||
* @param[in] rsMessageName Reference to the message name.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_Tx_SignalForValueReference(const dbc::SSignalDef& rsSig, const uint32_t index,
|
||||
const std::string& rsMessageName, std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the model data in the config.h file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_ModelDataList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the model data in the config.h file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeConfigH_SignalForModelData(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the mapping trigger file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeVariableList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of variables for the mapping trigger file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeVariableName(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of global signals definitions for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalDefinitionList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get global signal definitions for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalSignalDefinition(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of registering the global signals for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalRegisterList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Check list of registered global signals for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalRegisterCheckList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get registering the a global signal for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalRegisterSignal(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get check of a global signal for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @param[in] first should be true for the first call, otherwise false.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalRegisterSignalCheck(const signalDefinition& rSignal, bool first) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of resetting the global signals for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalResetList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get resetting the a global signal for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GlobalResetSignal(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of signals for the update event for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_EventUpdateList(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for writing int the update event method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_EventUpdateSignalDefinitionWrite(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for reading the update event method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_EventUpdateSignalDefinitionRead(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of signals for the GetFloat64 method for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GetFloat64(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of signals for the GetInt32 method for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GetInt32(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of signals for the SetFloat64 method for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_SetFloat64(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get List of signals for the SetInt32 method for the model.cpp file.
|
||||
* @param[in] rvecSignalDefinitions Reference to the container for all signal definitions.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_SetInt32(const std::vector<signalDefinition>& rvecSignalDefinitions) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for GetFloat64 method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GetFloat64SignalDefinition(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for GetInt32 method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_GetInt32SignalDefinition(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for SetFloat64 method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_SetFloat64SignalDefinition(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get Signal for SetInt32 method for the model.cpp file.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_SetInt32SignalDefinition(const signalDefinition& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get comment for the OpenAPILoad function for the model.cpp file.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeModelCPP_OpenAPILoadFunction() const;
|
||||
|
||||
/**
|
||||
* @brief Get default value of a tx signal. Used as start value un the build description.
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string CodeGetDefaultValueOfTxSignal(const dbc::SSignalDef& rSignal) const;
|
||||
|
||||
/**
|
||||
* @brief Get minimum and maximum of a signal
|
||||
* @param[in] rSignal Reference to the signal definition.
|
||||
* @param[in] isDouble Reference to bool variable. Signal is either integer or double.
|
||||
* @return The code to insert.
|
||||
*/
|
||||
std::string GetAttributes(const dbc::SSignalDef& rSignal, const bool& isDouble) const;
|
||||
|
||||
/**
|
||||
* @brief returns guid string
|
||||
* @return The guid.
|
||||
*/
|
||||
std::string newUUID() const;
|
||||
|
||||
const dbc::CDbcParser& m_rparser; ///< Reference to the DBC parser.
|
||||
};
|
||||
|
||||
#endif // !defined SOFTCAR_FMU_H
|
||||
2512
sdv_executables/sdv_dbc_util/fmu_fmi_templates.h
Normal file
2512
sdv_executables/sdv_dbc_util/fmu_fmi_templates.h
Normal file
File diff suppressed because it is too large
Load Diff
550
sdv_executables/sdv_dbc_util/fmu_templates.h
Normal file
550
sdv_executables/sdv_dbc_util/fmu_templates.h
Normal file
@@ -0,0 +1,550 @@
|
||||
|
||||
/**
|
||||
* @brief Build description template. File 'buildDescription.xml'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szBuildDescriptionTemplate[] = R"code(<!--
|
||||
@file %buiddescription_path%
|
||||
@date %date%
|
||||
This file is the fmi Build Description xml.
|
||||
This file was generated by the DBC utility from:
|
||||
%dbc_sources%
|
||||
%dbc_version%
|
||||
-->
|
||||
%buildDescription_xml%
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
* @brief CMake build project template. File 'CMakeLists.txt'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szMappingCMakeFileListsTemplate[] = R"code(
|
||||
# @file %cmakefilelists_path%
|
||||
# This file is cmake project file.
|
||||
# This file was generated by the DBC utility from:
|
||||
# %dbc_sources%
|
||||
# %dbc_version%
|
||||
|
||||
|
||||
# Based on CMakeLists.txt from https://github.com/modelica/Reference-FMUs
|
||||
# only FMI 2.0, only CoSimulation
|
||||
# without fumsim
|
||||
|
||||
|
||||
# Only valid for Windows
|
||||
if ( WIN32 )
|
||||
|
||||
# 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
|
||||
|
||||
project (%model_Identifier%Project)
|
||||
|
||||
# Use C++17 support
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Library symbols are hidden by default
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
|
||||
# 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(VAPI_CORE_SDV_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
|
||||
set(MODEL_NAME %model_Identifier%)
|
||||
set(TARGET_NAME ${MODEL_NAME})
|
||||
set(FMU_FULL_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/fmus/${MODEL_NAME}.fmu")
|
||||
|
||||
FUNCTION(cat IN_FILE OUT_FILE)
|
||||
file(READ ${IN_FILE} CONTENTS)
|
||||
file(APPEND ${OUT_FILE} "${CONTENTS}")
|
||||
ENDFUNCTION()
|
||||
|
||||
set(FMI_VERSION 2 CACHE STRING "FMI Version")
|
||||
set_property(CACHE FMI_VERSION PROPERTY STRINGS 2)
|
||||
|
||||
set(FMI_TYPE CS CACHE STRING "FMI Version")
|
||||
set_property(CACHE FMI_TYPE PROPERTY STRINGS CS)
|
||||
set(FMI_TYPE "")
|
||||
|
||||
set (FMI_PLATFORM win32)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set (FMI_PLATFORM win64)
|
||||
endif ()
|
||||
|
||||
SET(HEADERS
|
||||
${MODEL_NAME}/config.h
|
||||
include/cosimulation.h
|
||||
include/model.h
|
||||
)
|
||||
|
||||
SET(HEADERS
|
||||
${HEADERS}
|
||||
include/fmi2Functions.h
|
||||
include/fmi2FunctionTypes.h
|
||||
include/fmi2TypesPlatform.h
|
||||
)
|
||||
|
||||
SET(SOURCES
|
||||
${MODEL_NAME}/model.cpp
|
||||
src/fmi${FMI_VERSION}Functions.c
|
||||
src/cosimulation.c
|
||||
)
|
||||
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml
|
||||
${MODEL_NAME}/buildDescription.xml
|
||||
)
|
||||
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fmus)
|
||||
|
||||
set(FMU_BUILD_DIR temp/${MODEL_NAME})
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE
|
||||
FMI_VERSION=${FMI_VERSION}
|
||||
DISABLE_PREFIX
|
||||
)
|
||||
|
||||
#[[
|
||||
if (MSVC)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
|
||||
endif()
|
||||
]]
|
||||
|
||||
target_compile_definitions(${TARGET_NAME} PRIVATE FMI_COSIMULATION)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE include ${MODEL_NAME})
|
||||
target_link_libraries(${TARGET_NAME} Winmm Ws2_32 Rpcrt4.lib)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${FMU_BUILD_DIR}/binaries/${FMI_PLATFORM}"
|
||||
)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "")
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${MODEL_NAME})
|
||||
|
||||
# modelDescription.xml
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/FMI${FMI_VERSION}${FMI_TYPE}.xml
|
||||
"${FMU_BUILD_DIR}/modelDescription.xml"
|
||||
)
|
||||
|
||||
set(ARCHIVE_FILES "modelDescription.xml" "binaries")
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources")
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}/resources"
|
||||
"${FMU_BUILD_DIR}/resources/"
|
||||
)
|
||||
set(ARCHIVE_FILES ${ARCHIVE_FILES} "resources")
|
||||
endif()
|
||||
|
||||
# When windows robocopy command (using cmd.exe) is used to copy files its important to set the dependencies
|
||||
# to assure that the copy command is finished before the next custom action to avoid copy/file access failures
|
||||
|
||||
# Copy sdv binaries of this FMU
|
||||
set(DEST_DIR "${FMU_BUILD_DIR}/resources")
|
||||
set(SOURCE_DIR_EXAMPLES_BIN "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
add_custom_target(copy_function_sdv_files_${TARGET_NAME} DEPENDS ${TARGET_NAME})
|
||||
add_custom_command(TARGET copy_function_sdv_files_${TARGET_NAME}
|
||||
COMMAND cmd /C "robocopy \"${SOURCE_DIR_EXAMPLES_BIN}\" \"${DEST_DIR}\" *.pdb *.sdv /NP /R:3 /W:5 || exit /b 0"
|
||||
COMMENT "Copying contents from ${SOURCE_DIR_EXAMPLES_BIN} to ${DEST_DIR}, include only *.pdb *.sdv files"
|
||||
)
|
||||
add_dependencies(copy_function_sdv_files_${TARGET_NAME} ${TARGET_NAME})
|
||||
|
||||
|
||||
|
||||
# Copy framework sdv binaries
|
||||
set(SOURCE_DIR_CORE_BIN "${SDV_FRAMEWORK_RUNTIME}")
|
||||
add_custom_target(copy_framework_sdv_files_${TARGET_NAME} DEPENDS copy_function_sdv_files_${TARGET_NAME})
|
||||
add_custom_command(TARGET copy_framework_sdv_files_${TARGET_NAME}
|
||||
COMMAND cmd /C "robocopy \"${SOURCE_DIR_CORE_BIN}\" \"${DEST_DIR}\" *.pdb *.sdv /NP /R:3 /W:5 || exit /b 0"
|
||||
COMMENT "Copying contents from ${SOURCE_DIR_CORE_BIN} to ${DEST_DIR}, include only *.pdb *.sdv files"
|
||||
)
|
||||
add_dependencies(copy_framework_sdv_files_${TARGET_NAME} copy_function_sdv_files_${TARGET_NAME})
|
||||
|
||||
|
||||
|
||||
# FMU content created, all files copied
|
||||
# to zip the files create a new target 'create_zip' which is build after all files have been copied
|
||||
add_custom_target(create_zip_${TARGET_NAME} ALL DEPENDS copy_framework_sdv_files_${TARGET_NAME} )
|
||||
add_custom_command(TARGET create_zip_${TARGET_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E tar "cfv" ${FMU_FULL_FILE_NAME} --format=zip ${ARCHIVE_FILES}
|
||||
WORKING_DIRECTORY ${FMU_BUILD_DIR}
|
||||
COMMENT "Creating ZIP ${FMU_FULL_FILE_NAME}"
|
||||
)
|
||||
add_dependencies(create_zip_${TARGET_NAME} copy_framework_sdv_files_${TARGET_NAME})
|
||||
|
||||
#TODO
|
||||
#add_dependencies(${TARGET_NAME} <add_cmake_target_this_depends_on>)
|
||||
endif ()
|
||||
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
*@brief Config Header template. File 'config.h'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szConfigHTemplate[] = R"code(/**
|
||||
* @file %configH_path%
|
||||
* @date %date%
|
||||
* This file defines the data link object between CAN and the V-API devices.
|
||||
* This file was generated by the DBC utility from:
|
||||
* %dbc_sources%
|
||||
* %dbc_version%
|
||||
*/
|
||||
#ifndef %safeguardconfig%
|
||||
#define %safeguardconfig%
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// define class name and unique id
|
||||
#define MODEL_IDENTIFIER %model_Identifier%
|
||||
#define INSTANTIATION_TOKEN "%model_guid%"
|
||||
#define FMI_VERSION 2
|
||||
|
||||
#define CO_SIMULATION
|
||||
|
||||
// define model size
|
||||
#define NX 0
|
||||
#define NZ 0
|
||||
|
||||
#define GET_INT32
|
||||
#define SET_INT32
|
||||
#define GET_FLAOT64
|
||||
#define SET_FLOAT64
|
||||
#define EVENT_UPDATE
|
||||
#define CLEAN_UP
|
||||
|
||||
#define FIXED_SOLVER_STEP 0.04
|
||||
#define DEFAULT_STOP_TIME 10
|
||||
|
||||
typedef enum {
|
||||
%value_reference%
|
||||
|
||||
} ValueReference;
|
||||
|
||||
typedef struct {
|
||||
%model_data%
|
||||
|
||||
} ModelData;
|
||||
|
||||
#endif // !defined %safeguardconfig%
|
||||
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
*@brief FMI2 xml template. File 'FMI2.XML'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szFMI2XMLTemplate[] = R"code(<?xml version="1.0" encoding="UTF-8"?>
|
||||
<fmiModelDescription
|
||||
fmiVersion = "2.0"
|
||||
modelName = "%model_Identifier%"
|
||||
guid = "%model_guid%"
|
||||
description = "TargetLink FMU for %model_Identifier%"
|
||||
generationTool = "TargetLink was generated by the DBC utility: %dbc_sources%"
|
||||
generationDateAndTime = "%date%"
|
||||
variableNamingConvention = "structured"
|
||||
numberOfEventIndicators = "0">
|
||||
<CoSimulation
|
||||
modelIdentifier = "%model_Identifier%"
|
||||
canHandleVariableCommunicationStepSize = "false"
|
||||
canGetAndSetFMUstate = "false"
|
||||
canSerializeFMUstate = "false"
|
||||
providesDirectionalDerivative = "false"
|
||||
canBeInstantiatedOnlyOncePerProcess = "true"
|
||||
canInterpolateInputs = "false"
|
||||
canRunAsynchronuously = "false">
|
||||
<SourceFiles>
|
||||
<File name="all.c"/>
|
||||
</SourceFiles>
|
||||
</CoSimulation>
|
||||
<DefaultExperiment startTime="0" stepSize="0.01"/>
|
||||
<ModelVariables>
|
||||
%model_variables%
|
||||
</ModelVariables>
|
||||
<ModelStructure>
|
||||
<Outputs>
|
||||
<Unknown index="%unknown_index%"/>
|
||||
</Outputs>
|
||||
</ModelStructure>
|
||||
</fmiModelDescription>
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
*@brief Model cpp template. File 'model.cpp'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szModelCPPTemplate[] = R"code(/**
|
||||
* @file %modelcpp_path%
|
||||
* @date %date%
|
||||
* This file defines the data link object between CAN and the V-API devices.
|
||||
* This file was generated by the DBC utility from:
|
||||
* %dbc_sources%
|
||||
* %dbc_version%
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <support/timer.h>
|
||||
#include "signal_identifier.h"
|
||||
#include <support/signal_support.h>
|
||||
#include <support/app_control.h>
|
||||
|
||||
%global_signals%
|
||||
// in case the simulation timer should be used
|
||||
sdv::core::ITimerSimulationStep* g_pTimerSimulationStep;
|
||||
|
||||
std::unique_ptr<sdv::app::CAppControl> g_appcontrol;
|
||||
|
||||
bool InitializeAppControl(const std::string& resource, const std::string& configFileName)
|
||||
{
|
||||
auto bResult = g_appcontrol->AddModuleSearchDir( resource );
|
||||
bResult &= g_appcontrol->Startup("");
|
||||
g_appcontrol->SetConfigMode();
|
||||
bResult &= g_appcontrol->AddConfigSearchDir( resource );
|
||||
|
||||
if (!configFileName.empty())
|
||||
{
|
||||
bResult &= g_appcontrol->LoadConfig(configFileName.c_str()) == sdv::core::EConfigProcessResult::successful;
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
sdv::core::EConfigProcessResult RegisterAllSignals()
|
||||
{
|
||||
std::string msg = "register all signals: ";
|
||||
sdv::core::CDispatchService dispatch;
|
||||
|
||||
%global_signals_register%
|
||||
%global_signals_register_check%
|
||||
|
||||
return sdv::core::EConfigProcessResult::failed;
|
||||
}
|
||||
|
||||
bool ResetAllSignals()
|
||||
{
|
||||
sdv::core::CDispatchService dispatch;
|
||||
|
||||
%global_signals_reset%
|
||||
SDV_LOG_INFO("Reset signals");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CreateCoreServiceTomlFile(const std::string& resources)
|
||||
{
|
||||
std::ofstream tomlFile("sdv_core_reloc.toml");
|
||||
if (tomlFile.is_open())
|
||||
{
|
||||
tomlFile << "# Location of the SDV binaries and configuration files\ndirectory = \"";
|
||||
tomlFile << resources;
|
||||
tomlFile << "\"\n";
|
||||
tomlFile.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool OpenAPILoad(const std::string& resources)
|
||||
{
|
||||
bool success = CreateCoreServiceTomlFile(resources);
|
||||
g_appcontrol = std::make_unique<sdv::app::CAppControl> ();
|
||||
|
||||
//
|
||||
// TODO: Dispatch service must be loaded first, adjust the correct toml file
|
||||
//
|
||||
success &= InitializeAppControl(resources, "data_dispatch_config_file.toml");
|
||||
if (!success)
|
||||
{
|
||||
std::cout << "Error: InitializeAppControl() failed" << std::endl;
|
||||
SDV_LOG_ERROR("Failed InitializeAppControl");
|
||||
return false;
|
||||
}
|
||||
success &= RegisterAllSignals() == sdv::core::EConfigProcessResult::successful;
|
||||
if (!success)
|
||||
{
|
||||
SDV_LOG_ERROR("Signals could not be registered");
|
||||
}
|
||||
%vapi_load_config_files%
|
||||
g_appcontrol->SetRunningMode();
|
||||
return success;
|
||||
}
|
||||
|
||||
void OpenAPIShutdown()
|
||||
{
|
||||
ResetAllSignals();
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <float.h> // for DBL_EPSILON
|
||||
#include <math.h> // for fabs()
|
||||
#include "config.h"
|
||||
#include "model.h"
|
||||
|
||||
Status cleanup(ModelInstance*)
|
||||
{
|
||||
SDV_LOG_INFO("Shutting down...");
|
||||
OpenAPIShutdown();
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
bool setStartValues(ModelInstance* comp)
|
||||
{
|
||||
std::string path(comp->resourceLocation);
|
||||
std::string resourcePath = path.substr(8);
|
||||
std::replace(resourcePath.begin(), resourcePath.end(), '\\', '/');
|
||||
if (!OpenAPILoad(resourcePath))
|
||||
{
|
||||
std::cout << "Error: OpenAPILoad() failed." << std::endl;
|
||||
comp->terminateSimulation = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: move this to initialize()?
|
||||
comp->nextEventTime = 0;
|
||||
comp->nextEventTimeDefined = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Status calculateValues(ModelInstance* comp)
|
||||
{
|
||||
UNUSED(comp);
|
||||
// nothing to do
|
||||
return OK;
|
||||
}
|
||||
|
||||
Status getFloat64(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] double values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
|
||||
{
|
||||
ASSERT_NVALUES(1);
|
||||
%getFloat64%
|
||||
return OK;
|
||||
}
|
||||
|
||||
Status getInt32(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] int32_t values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
|
||||
{
|
||||
ASSERT_NVALUES(1);
|
||||
%getInt32%
|
||||
return OK;
|
||||
}
|
||||
|
||||
Status setFloat64(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] const double values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
|
||||
{
|
||||
ASSERT_NVALUES(1);
|
||||
%setFloat64%
|
||||
return OK;
|
||||
}
|
||||
|
||||
Status setInt32(ModelInstance* comp, [[maybe_unused]] ValueReference vr, [[maybe_unused]] const int32_t values[], [[maybe_unused]] size_t nValues, [[maybe_unused]] size_t* index)
|
||||
{
|
||||
ASSERT_NVALUES(1);
|
||||
%setInt32%
|
||||
return OK;
|
||||
}
|
||||
|
||||
void eventUpdate(ModelInstance* comp)
|
||||
{
|
||||
%event_update%
|
||||
double epsilon = (1.0 + fabs(comp->time)) * DBL_EPSILON;
|
||||
|
||||
if (comp->nextEventTimeDefined && comp->time + epsilon >= comp->nextEventTime) {
|
||||
comp->nextEventTime += FIXED_SOLVER_STEP;
|
||||
}
|
||||
|
||||
comp->valuesOfContinuousStatesChanged = false;
|
||||
comp->nominalsOfContinuousStatesChanged = false;
|
||||
comp->terminateSimulation = false;
|
||||
comp->nextEventTimeDefined = true;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end of extern "C"
|
||||
#endif
|
||||
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
*@brief Signal name mapping template. Signal names contain the can names of the signal which must match the names of the vehicle devices.
|
||||
* File 'signal_identifier.h'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szMappingSignalIdentifierTemplate[] = R"code(/**
|
||||
@file %signalidentifierfile_path%
|
||||
@date %date%
|
||||
This file is the signal identifier header.
|
||||
This file was generated by the DBC utility from:
|
||||
%dbc_sources%
|
||||
%dbc_version%
|
||||
*/
|
||||
#ifndef %safeguardsignalidentifier%
|
||||
#define %safeguardsignalidentifier%
|
||||
|
||||
namespace %object_prefix%
|
||||
{
|
||||
// Data Dispatch Service signal names to dbc variable names C-type RX/TX vss name space
|
||||
%signals%
|
||||
} // %object_prefix%
|
||||
|
||||
#endif // %safeguardsignalidentifier%
|
||||
)code";
|
||||
|
||||
|
||||
/**
|
||||
*@brief Data dispatch service config template. File 'data_dispatch_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szDataDispatchServiceTomlFile[] = R"code([Configuration]
|
||||
Version = 100
|
||||
|
||||
[[Component]]
|
||||
Path = "data_dispatch_service.sdv"
|
||||
Class = "DataDispatchService"
|
||||
)code";
|
||||
|
||||
/**
|
||||
*@brief Simulation task timer service config template. File 'simulation_task_timer_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szSimulationTaskTimerServiceTomlFile[] = R"code([Configuration]
|
||||
Version = 100
|
||||
|
||||
[[Component]]
|
||||
Path = "simulation_task_timer.sdv"
|
||||
Class = "SimulationTaskTimerService"
|
||||
)code";
|
||||
|
||||
/**
|
||||
*@brief Task timer service config template. File 'task_timer_config_file.toml'. Code chunks are inserted at the keywords surrounded by %%.
|
||||
*/
|
||||
const char szTaskTimerhServiceTomlFile[] = R"code([Configuration]
|
||||
Version = 100
|
||||
|
||||
[[Component]]
|
||||
Path = "task_timer.sdv"
|
||||
Class = "TaskTimerService"
|
||||
)code";
|
||||
|
||||
103
sdv_executables/sdv_dbc_util/main.cpp
Normal file
103
sdv_executables/sdv_dbc_util/main.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "../../global/process_watchdog.h"
|
||||
#include <interfaces/core.h>
|
||||
#include <interfaces/mem.h>
|
||||
#include "../../global/cmdlnparser/cmdlnparser.cpp"
|
||||
#include "../../global/dbcparser/dbcparser.cpp"
|
||||
#include "../../global/localmemmgr.h"
|
||||
#include <iostream>
|
||||
#include "can_dl.h"
|
||||
#include "fmu.h"
|
||||
#include "cmake_generator.h"
|
||||
#include "../error_msg.h"
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
extern "C" int wmain(int iArgc, const wchar_t* rgszArgv[])
|
||||
#else
|
||||
extern "C" int main(int iArgc, const char* rgszArgv[])
|
||||
#endif
|
||||
{
|
||||
// Workaround for GCC to make certain that POSIX thread library is loaded before the components are loaded.
|
||||
// REASON: If the first call to a thread is done in a dynamic library, the application is already classified as single
|
||||
// threaded and a termination is initiated.
|
||||
// See: https://stackoverflow.com/questions/51209268/using-stdthread-in-a-library-loaded-with-dlopen-leads-to-a-sigsev
|
||||
// NOTE EVE 27.05.2025: This task has been taken over by the process watchdog.
|
||||
CProcessWatchdog watchdog;
|
||||
|
||||
// Suppress the warning supplied by ccpcheck about an unsused variable. The memory manager registers itself into the system and
|
||||
// needs to stay in scope.
|
||||
// cppcheck-suppress unusedVariable
|
||||
CLocalMemMgr memmgr;
|
||||
|
||||
CCommandLine cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character));
|
||||
bool bHelp = false;
|
||||
bool bError = false;
|
||||
bool bSilent = false;
|
||||
bool bVerbose = false;
|
||||
size_t nIfcIndex = 0;
|
||||
std::string ssIfcName;
|
||||
std::string ssVersion;
|
||||
std::string ssModelIdentifier;
|
||||
std::string ssDataLinkLibName = "can_dl";
|
||||
std::vector<std::filesystem::path> vecFileNames;
|
||||
std::vector<std::string> vecNodes;
|
||||
std::filesystem::path pathOutputDir;
|
||||
try
|
||||
{
|
||||
auto& rArgHelpDef = cmdln.DefineOption("?", bHelp, "Show help");
|
||||
rArgHelpDef.AddSubOptionName("help");
|
||||
auto& rArgSilentDef = cmdln.DefineOption("s", bSilent, "Do not show any information on STDOUT. Not compatible with 'verbose'.");
|
||||
rArgSilentDef.AddSubOptionName("silent");
|
||||
auto& rArgVerboseDef = cmdln.DefineOption("v", bVerbose, "Provide verbose information. Not compatible with 'silent'.");
|
||||
rArgVerboseDef.AddSubOptionName("verbose");
|
||||
cmdln.DefineSubOption("version", ssVersion, "Optional: version information of the dbc file.");
|
||||
cmdln.DefineSubOption("module", ssModelIdentifier, "Optional: module identifier for the fmu. Default 'BasicModelIdentifier'");
|
||||
cmdln.DefineSubOption("dl_lib_name", ssDataLinkLibName, "Data link library target name in the generated cmake file (default=\"can_dl\")..");
|
||||
cmdln.DefineOption("O", pathOutputDir, "Set output directory");
|
||||
cmdln.DefineSubOption("ifc_idx", nIfcIndex, "Interface index this DBC file is aiming for.");
|
||||
cmdln.DefineSubOption("ifc_name", ssIfcName, "Name of the interface this DBC file is aiming for.");
|
||||
cmdln.DefineSubOption("nodes", vecNodes, "List of nodes that will be implemented.");
|
||||
cmdln.DefineDefaultArgument(vecFileNames, "One or more DBC files");
|
||||
cmdln.Parse(static_cast<size_t>(iArgc), rgszArgv);
|
||||
} catch (const SArgumentParseException& rsExcept)
|
||||
{
|
||||
std::cout << "ERROR: " << rsExcept.what() << std::endl;
|
||||
bHelp = true;
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if (!bSilent)
|
||||
{
|
||||
std::cout << "DBC utility" << std::endl;
|
||||
std::cout << "Copyright (C): 2022-2025 ZF Friedrichshafen AG" << std::endl;
|
||||
std::cout << "Author: Erik Verhoeven" << std::endl;
|
||||
}
|
||||
if (bHelp)
|
||||
{
|
||||
if (!bSilent)
|
||||
cmdln.PrintHelp(std::cout);
|
||||
return bError ? CMDLN_ARG_ERR : NO_ERROR;
|
||||
}
|
||||
|
||||
dbc::CDbcParser parser;
|
||||
for (const std::filesystem::path& rpath : vecFileNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (bVerbose)
|
||||
std::cout << "Processing: " << rpath.generic_u8string() << std::endl;
|
||||
dbc::CDbcSource src(rpath);
|
||||
parser.Parse(src);
|
||||
CSoftcarFMUGen fmu(pathOutputDir, parser, ssModelIdentifier, ssVersion, vecNodes);
|
||||
CCanDataLinkGen dl(pathOutputDir, parser, ssVersion, ssIfcName, nIfcIndex, vecNodes);
|
||||
CDbcUtilCMakeGenerator cmakegen(pathOutputDir, ssDataLinkLibName);
|
||||
}
|
||||
catch (dbc::SDbcParserException& rsException)
|
||||
{
|
||||
if (!bSilent)
|
||||
std::cout << "ERROR " << LOAD_DBC_FILE_ERROR_MSG << " Reason: " << rsException.what() << std::endl;
|
||||
return LOAD_DBC_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
69
sdv_executables/sdv_idl_compiler/CMakeLists.txt
Normal file
69
sdv_executables/sdv_idl_compiler/CMakeLists.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
# Define project
|
||||
project (sdv_idl_compiler VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
# Get xxHash from github
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
xxhash
|
||||
GIT_REPOSITORY https://github.com/Cyan4973/xxHash.git
|
||||
GIT_TAG v0.8.3
|
||||
)
|
||||
FetchContent_MakeAvailable(xxhash)
|
||||
|
||||
# Add include directories
|
||||
include_directories(../export ${xxhash_SOURCE_DIR})
|
||||
|
||||
# Define the executable
|
||||
add_executable(sdv_idl_compiler
|
||||
main.cpp
|
||||
exception.cpp
|
||||
environment.cpp
|
||||
logger.cpp
|
||||
token.cpp
|
||||
tokenlist.cpp
|
||||
codepos.cpp
|
||||
lexer.cpp
|
||||
parser.cpp
|
||||
parsecontext.cpp
|
||||
preproc.cpp
|
||||
environment.cpp
|
||||
source.cpp
|
||||
macro.cpp
|
||||
constvariant.cpp
|
||||
entities/entity_base.cpp
|
||||
entities/root_entity.cpp
|
||||
entities/module_entity.cpp
|
||||
entities/declaration_entity.cpp
|
||||
entities/typedef_entity.cpp
|
||||
entities/variable_entity.cpp
|
||||
entities/entity_value.cpp
|
||||
entities/definition_entity.cpp
|
||||
entities/struct_entity.cpp
|
||||
entities/interface_entity.cpp
|
||||
entities/attribute_entity.cpp
|
||||
entities/operation_entity.cpp
|
||||
entities/parameter_entity.cpp
|
||||
entities/exception_entity.cpp
|
||||
entities/union_entity.cpp
|
||||
entities/enum_entity.cpp
|
||||
entities/hash_calc.cpp
|
||||
entities/meta_entity.cpp
|
||||
generator/definition_generator.cpp
|
||||
generator/proxy_generator.cpp
|
||||
generator/stub_generator.cpp
|
||||
generator/context.cpp
|
||||
"generator/ps_class_generator_base.cpp"
|
||||
"generator/serdes_generator.h"
|
||||
"generator/serdes_generator.cpp"
|
||||
"generator/cmake_generator.cpp"
|
||||
"generator/ps_cpp_generator.h"
|
||||
"generator/ps_cpp_generator.cpp" "generator/definition_generator_base.h")
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(sdv_idl_compiler ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} stdc++fs)
|
||||
else()
|
||||
target_link_libraries(sdv_idl_compiler ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
# Appending the executable to the service list
|
||||
set(SDV_Executable_List ${SDV_Executable_List} sdv_idl_compiler PARENT_SCOPE)
|
||||
314
sdv_executables/sdv_idl_compiler/codepos.cpp
Normal file
314
sdv_executables/sdv_idl_compiler/codepos.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
#include "codepos.h"
|
||||
#include "lexer.h"
|
||||
#include "exception.h"
|
||||
#include "token.h"
|
||||
|
||||
CCodePos::CCodePos()
|
||||
{}
|
||||
|
||||
CCodePos::CCodePos(const char* szCode) : m_szCode(szCode)
|
||||
{
|
||||
if (!szCode)
|
||||
throw CCompileException("No code supplied.");
|
||||
m_szCurrent = szCode;
|
||||
m_uiLine = 1;
|
||||
m_uiCol = 1;
|
||||
}
|
||||
|
||||
CCodePos::CCodePos(const CCodePos& rCode) :
|
||||
m_szCode(rCode.m_szCode), m_szCurrent(rCode.m_szCurrent), m_szPrependedPos(rCode.m_szPrependedPos),
|
||||
m_szPrependedCode(nullptr), m_szPrependedCurrent(nullptr), m_ssPrependedCode(rCode.m_ssPrependedCode),
|
||||
m_uiLine(rCode.m_uiLine), m_uiCol(rCode.m_uiCol)
|
||||
{
|
||||
if (rCode.m_szPrependedCurrent && rCode.m_szPrependedCode)
|
||||
{
|
||||
m_szPrependedCode = m_ssPrependedCode.c_str();
|
||||
m_szPrependedCurrent = m_szPrependedCode + (rCode.m_szPrependedCurrent - rCode.m_szPrependedCode);
|
||||
}
|
||||
}
|
||||
|
||||
CCodePos::CCodePos(CCodePos&& rCode) noexcept :
|
||||
m_szCode(rCode.m_szCode), m_szCurrent(rCode.m_szCurrent), m_szPrependedPos(rCode.m_szPrependedPos),
|
||||
m_szPrependedCode(rCode.m_szPrependedCode), m_szPrependedCurrent(rCode.m_szPrependedCurrent),
|
||||
m_ssPrependedCode(std::move(rCode.m_ssPrependedCode)), m_lstCodeChunks(std::move(rCode.m_lstCodeChunks)),
|
||||
m_uiLine(rCode.m_uiLine), m_uiCol(rCode.m_uiCol)
|
||||
{
|
||||
rCode.m_szCode = nullptr;
|
||||
rCode.m_szCurrent = nullptr;
|
||||
rCode.m_szPrependedPos = nullptr;
|
||||
rCode.m_szPrependedCode = nullptr;
|
||||
rCode.m_szPrependedCurrent = nullptr;
|
||||
rCode.m_uiLine = 0;
|
||||
rCode.m_uiCol = 0;
|
||||
}
|
||||
|
||||
bool CCodePos::IsValid() const
|
||||
{
|
||||
return m_szCode != nullptr &&
|
||||
m_szCurrent != nullptr &&
|
||||
m_uiLine > 0 &&
|
||||
m_uiCol > 0;
|
||||
}
|
||||
|
||||
CCodePos::operator bool() const
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
void CCodePos::Reset()
|
||||
{
|
||||
m_szCurrent = m_szCode;
|
||||
m_szPrependedPos = nullptr;
|
||||
m_szPrependedCode = nullptr;
|
||||
m_szPrependedCurrent = nullptr;
|
||||
m_uiLine = 1;
|
||||
m_uiCol = 1;
|
||||
m_ssPrependedCode.clear();
|
||||
}
|
||||
|
||||
uint32_t CCodePos::GetLine() const
|
||||
{
|
||||
return m_uiLine;
|
||||
}
|
||||
|
||||
uint32_t CCodePos::GetCol() const
|
||||
{
|
||||
return m_uiCol;
|
||||
}
|
||||
|
||||
bool CCodePos::HasEOF() const
|
||||
{
|
||||
return !m_szCurrent || ((!m_szPrependedCurrent || *m_szPrependedCurrent == '\0') && *m_szCurrent == '\0');
|
||||
}
|
||||
|
||||
bool CCodePos::HasEOL() const
|
||||
{
|
||||
if (HasEOF()) return true;
|
||||
if (m_szPrependedCurrent && *m_szPrependedCurrent != '\0')
|
||||
return *m_szPrependedCurrent == '\n' || (m_szPrependedCurrent[0] == '\r' && m_szPrependedCurrent[1] == '\n');
|
||||
return *m_szCurrent == '\n' || (m_szCurrent[0] == '\r' && m_szCurrent[1] == '\n');
|
||||
}
|
||||
|
||||
CToken CCodePos::GetLocation(ETokenType eTokenType /*= ETokenType::token_none*/) const
|
||||
{
|
||||
CToken token;
|
||||
token.m_szCode = (m_szPrependedCurrent && *m_szPrependedCurrent) ? m_szPrependedCurrent : m_szCurrent;
|
||||
token.m_uiLine = m_uiLine;
|
||||
token.m_uiCol = m_uiCol;
|
||||
token.m_eType = eTokenType;
|
||||
return token;
|
||||
}
|
||||
|
||||
void CCodePos::UpdateLocation(CToken& rtoken) const
|
||||
{
|
||||
// Check for a valid token.
|
||||
if (!rtoken) return;
|
||||
|
||||
// If the token start position is within the prepended start code and the prepended current code, update the location by
|
||||
// creating a code chunk.
|
||||
if (m_szPrependedCode && rtoken.m_szCode >= m_szPrependedCode && rtoken.m_szCode <= m_szPrependedCurrent)
|
||||
{
|
||||
// Create a chunk based on the prepended code
|
||||
std::string ssChunk = std::string(rtoken.m_szCode, m_szPrependedCurrent - rtoken.m_szCode);
|
||||
|
||||
// If the current position of the prepended code is at the end, add a part of the code.
|
||||
if (!*m_szPrependedCurrent)
|
||||
ssChunk += std::string(m_szPrependedPos, m_szCurrent - m_szPrependedPos);
|
||||
|
||||
// Add the chunk to the list
|
||||
m_lstCodeChunks.emplace_back(std::move(ssChunk));
|
||||
|
||||
// Assign the new start and length infos
|
||||
rtoken.m_szCode = m_lstCodeChunks.back().c_str();
|
||||
rtoken.m_uiLen = static_cast<uint32_t>(m_lstCodeChunks.back().size());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the token start position is within the code, update the length
|
||||
if (rtoken.m_szCode >= m_szCode && rtoken.m_szCode <= m_szCurrent)
|
||||
{
|
||||
rtoken.m_uiLen = static_cast<uint32_t>(m_szCurrent - rtoken.m_szCode);
|
||||
return;
|
||||
}
|
||||
|
||||
// The token start position is invalid. Set the code to nullptr and the length to 0.
|
||||
rtoken.m_szCode = nullptr;
|
||||
rtoken.m_uiLen = 0;
|
||||
}
|
||||
|
||||
void CCodePos::UpdateLocation(CToken& rtoken, ETokenLiteralType eLiteralType) const
|
||||
{
|
||||
UpdateLocation(rtoken);
|
||||
switch (rtoken.GetType())
|
||||
{
|
||||
case ETokenType::token_literal:
|
||||
case ETokenType::token_none:
|
||||
rtoken.m_eType = ETokenType::token_literal;
|
||||
rtoken.m_eLiteralType = eLiteralType;
|
||||
break;
|
||||
default:
|
||||
throw CCompileException("Internal error: invalid token type during literal type assignment.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCodePos::UpdateLocation(CToken& rtoken, ETokenMetaType eMetaType) const
|
||||
{
|
||||
UpdateLocation(rtoken);
|
||||
switch (rtoken.GetType())
|
||||
{
|
||||
case ETokenType::token_meta:
|
||||
case ETokenType::token_none:
|
||||
rtoken.m_eType = ETokenType::token_meta;
|
||||
rtoken.m_eMetaType = eMetaType;
|
||||
break;
|
||||
default:
|
||||
throw CCompileException("Internal error: invalid token type during meta type assignment.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCodePos::PrependCode(const std::string& rssCode)
|
||||
{
|
||||
if (rssCode.empty()) return;
|
||||
std::string ssPrependedCode = rssCode;
|
||||
if (m_szPrependedCurrent)
|
||||
ssPrependedCode += m_szPrependedCurrent;
|
||||
m_ssPrependedCode = std::move(ssPrependedCode);
|
||||
m_szPrependedCode = m_ssPrependedCode.c_str();
|
||||
m_szPrependedCurrent = m_ssPrependedCode.c_str();
|
||||
m_szPrependedPos = m_szCurrent;
|
||||
}
|
||||
|
||||
bool CCodePos::CurrentPositionInMacroExpansion() const
|
||||
{
|
||||
return m_szPrependedCurrent && *m_szPrependedCurrent;
|
||||
}
|
||||
|
||||
CCodePos& CCodePos::operator=(const CCodePos& rCode)
|
||||
{
|
||||
m_szCode = rCode.m_szCode;
|
||||
m_szCurrent = rCode.m_szCurrent;
|
||||
m_szPrependedPos = rCode.m_szPrependedPos;
|
||||
m_ssPrependedCode = rCode.m_ssPrependedCode;
|
||||
if (rCode.m_szPrependedCurrent && rCode.m_szPrependedCode)
|
||||
{
|
||||
m_szPrependedCode = m_ssPrependedCode.c_str();
|
||||
m_szPrependedCurrent = m_szPrependedCode + (rCode.m_szPrependedCurrent - rCode.m_szPrependedCode);
|
||||
} else
|
||||
{
|
||||
m_szPrependedCode = nullptr;
|
||||
m_szPrependedCurrent = nullptr;
|
||||
}
|
||||
m_uiLine = rCode.m_uiLine;
|
||||
m_uiCol = rCode.m_uiCol;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CCodePos& CCodePos::operator=(CCodePos&& rCode) noexcept
|
||||
{
|
||||
m_szCode = rCode.m_szCode;
|
||||
m_szCurrent = rCode.m_szCurrent;
|
||||
m_szPrependedPos = rCode.m_szPrependedPos;
|
||||
m_szPrependedCode = rCode.m_szPrependedCode;
|
||||
m_szPrependedCurrent = rCode.m_szPrependedCurrent;
|
||||
m_ssPrependedCode = std::move(rCode.m_ssPrependedCode);
|
||||
m_lstCodeChunks = std::move(rCode.m_lstCodeChunks);
|
||||
m_uiLine = rCode.m_uiLine;
|
||||
m_uiCol = rCode.m_uiCol;
|
||||
rCode.m_szCode = nullptr;
|
||||
rCode.m_szCurrent = nullptr;
|
||||
rCode.m_szPrependedPos = nullptr;
|
||||
rCode.m_szPrependedCode = nullptr;
|
||||
rCode.m_szPrependedCurrent = nullptr;
|
||||
rCode.m_uiLine = 0;
|
||||
rCode.m_uiCol = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
char CCodePos::operator[](uint32_t uiOffset /*= 0*/) const
|
||||
{
|
||||
// Handle an offset past the prepended string.
|
||||
for (uint32_t uiIndex = 0; uiIndex <= uiOffset; uiIndex++)
|
||||
{
|
||||
if (!m_szPrependedCurrent || m_szPrependedCurrent[uiIndex] == '\0')
|
||||
return m_szCurrent ? m_szCurrent[uiOffset - uiIndex] : '\0';
|
||||
}
|
||||
|
||||
// Return a character from the prepended string.
|
||||
return m_szPrependedCurrent[uiOffset];
|
||||
}
|
||||
|
||||
char CCodePos::operator*() const
|
||||
{
|
||||
if (m_szPrependedCurrent && m_szPrependedCurrent[0]) return m_szPrependedCurrent[0];
|
||||
return m_szCurrent ? *m_szCurrent : '\0';
|
||||
}
|
||||
|
||||
CCodePos::operator const char*() const
|
||||
{
|
||||
if (m_szPrependedCurrent) return m_szPrependedCurrent;
|
||||
return m_szCurrent;
|
||||
}
|
||||
|
||||
CCodePos CCodePos::operator++(int)
|
||||
{
|
||||
CCodePos posCopy(*this);
|
||||
operator++();
|
||||
return posCopy;
|
||||
}
|
||||
|
||||
CCodePos& CCodePos::operator++()
|
||||
{
|
||||
// Check for a valid prepended character.
|
||||
if (m_szPrependedCurrent && *m_szPrependedCurrent)
|
||||
{
|
||||
// Increase current position
|
||||
m_szPrependedCurrent++;
|
||||
|
||||
// End of prepended code?
|
||||
if (!m_szPrependedCurrent)
|
||||
{
|
||||
m_szPrependedCurrent = nullptr;
|
||||
m_ssPrependedCode.clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Check for a valid character
|
||||
if (m_szCurrent && *m_szCurrent != '\0')
|
||||
{
|
||||
// Currently a newline?
|
||||
if (*m_szCurrent == '\n')
|
||||
{
|
||||
// Set new position at beginning of ext line
|
||||
m_uiCol = 1;
|
||||
m_uiLine++;
|
||||
}
|
||||
else if (*m_szCurrent == '\t')
|
||||
{
|
||||
// Increase the column
|
||||
m_uiCol++;
|
||||
|
||||
// Align with a tab of 4 characters
|
||||
while ((m_uiCol - 1) % 4) m_uiCol++;
|
||||
}
|
||||
else
|
||||
m_uiCol++; // Increase the column
|
||||
|
||||
// Next character
|
||||
m_szCurrent++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CCodePos& CCodePos::operator+=(uint32_t uiOffset)
|
||||
{
|
||||
for (uint32_t uiIndex = 0; uiIndex != uiOffset; uiIndex++)
|
||||
operator++(0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
200
sdv_executables/sdv_idl_compiler/codepos.h
Normal file
200
sdv_executables/sdv_idl_compiler/codepos.h
Normal file
@@ -0,0 +1,200 @@
|
||||
#ifndef CODEPOS_H
|
||||
#define CODEPOS_H
|
||||
|
||||
#include "lexerbase.h"
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
// Forward declaration
|
||||
class CToken;
|
||||
|
||||
/**
|
||||
* @brief Code string with position information.
|
||||
*/
|
||||
class CCodePos
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @remarks Use the assignment operator to set the code to be covered by the code position class.
|
||||
*/
|
||||
CCodePos();
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] szCode Pointer to zero terminated string containing the IDL code. Must not be NULL.
|
||||
*/
|
||||
CCodePos(const char* szCode);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
* @param[in] rCode Reference to the code to copy.
|
||||
*/
|
||||
CCodePos(const CCodePos& rCode);
|
||||
|
||||
/**
|
||||
* @brief Move constructor
|
||||
* @param[in] rCode Reference to the code to move.
|
||||
*/
|
||||
CCodePos(CCodePos&& rCode) noexcept;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Is the code position class initialized correctly?
|
||||
* @return Returns whether the class is initialized.
|
||||
*/
|
||||
bool IsValid() const;
|
||||
operator bool() const;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reset the current navigation.
|
||||
* @attention Any prepended code will be removed.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* @brief Return the current line.
|
||||
* @return The current line.
|
||||
*/
|
||||
uint32_t GetLine() const;
|
||||
|
||||
/**
|
||||
* @brief Return the current column.
|
||||
* @return The current column.
|
||||
*/
|
||||
uint32_t GetCol() const;
|
||||
|
||||
/**
|
||||
* @brief Check for EOF.
|
||||
* @return Returns 'true' when EOF has been reached. Otherwise returns 'false'.
|
||||
*/
|
||||
bool HasEOF() const;
|
||||
|
||||
/**
|
||||
* @brief Check for EOL.
|
||||
* @return Returns 'true' when EOL has been reached. Otherwise returns 'false'.
|
||||
*/
|
||||
bool HasEOL() const;
|
||||
|
||||
/**
|
||||
* @brief Get the token at the current location.
|
||||
* @attention The returned position is volatile and might be invalid as soon as code is prepended. Once the UpdateLocation
|
||||
* has been called, the code is persistent.
|
||||
* @param[in] eTokenType The type of token this token is referring to.
|
||||
* @return The token at the current location.
|
||||
*/
|
||||
CToken GetLocation(ETokenType eTokenType = ETokenType::token_none) const;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Update the length of the token with current position. Persists the code if composed from (part of) prepended code.
|
||||
* @param[in, out] rtoken Reference to the token to be updated.
|
||||
*/
|
||||
void UpdateLocation(CToken& rtoken) const;
|
||||
|
||||
/**
|
||||
* @brief Update the length of the token with current position. Persists the code if composed from (part of) prepended code.
|
||||
* @param[in, out] rtoken Reference to the token to be updated.
|
||||
* @param[in] eLiteralType The literal type to be assigned to the token (if any).
|
||||
*/
|
||||
void UpdateLocation(CToken& rtoken, ETokenLiteralType eLiteralType) const;
|
||||
|
||||
/**
|
||||
* @brief Update the length of the token with current position. Persists the code if composed from (part of) prepended code.
|
||||
* @param[in, out] rtoken Reference to the token to be updated.
|
||||
* @param[in] eMetaType The meta type to be assigned to the token (if any).
|
||||
*/
|
||||
void UpdateLocation(CToken& rtoken, ETokenMetaType eMetaType) const;
|
||||
|
||||
/**
|
||||
* @brief Insert code at the current position allowing to parse the prepended code.
|
||||
* @details This function prepends code at the current position. The code could be a macro expansion or precedence parsing.
|
||||
* @attention This function might invalidate tokens that have a start location, but no fixed location.
|
||||
* @param[in] rssCode Reference to a string object representing the code to prepend
|
||||
*/
|
||||
void PrependCode(const std::string& rssCode);
|
||||
|
||||
/**
|
||||
* @brief Return whether the current position is part of the prepended code.
|
||||
* @return Returns 'true' when the current position is within the prepended code; otherwise returns 'false'.
|
||||
*/
|
||||
bool CurrentPositionInMacroExpansion() const;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param[in] rCode Reference to the code to copy.
|
||||
* @return Returns reference to this class.
|
||||
*/
|
||||
CCodePos& operator=(const CCodePos& rCode);
|
||||
|
||||
/**
|
||||
* @brief Move operator.
|
||||
* @param[in] rCode Reference to the code to move.
|
||||
* @return Returns reference to this class.
|
||||
*/
|
||||
CCodePos& operator=(CCodePos&& rCode) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get current character (with offset)
|
||||
* @param[in] uiOffset The offset of the character to read relative to the current character.
|
||||
* @attention The caller must make certain, that a valid character is available at the provided offset by interpreting the
|
||||
* characters before.
|
||||
* @return The current character or '\0' when there is no current character.
|
||||
*/
|
||||
char operator[](uint32_t uiOffset /*= 0*/) const;
|
||||
|
||||
/**
|
||||
* @brief Get current character
|
||||
* @attention The caller must make certain, that a valid character is available at the provided offset by interpreting the
|
||||
* characters before.
|
||||
* @return The current character or '\0' when there is no current character.
|
||||
*/
|
||||
char operator*() const;
|
||||
|
||||
/**
|
||||
* @brief Get the code at the current position.
|
||||
* @attention The caller must make certain, that a valid character is available at the provided offset by interpreting the
|
||||
* characters before.
|
||||
* @return Pointer to the code at the current location or nullptr when there is no code.
|
||||
*/
|
||||
operator const char*() const;
|
||||
|
||||
/**
|
||||
* @brief Increment the current position
|
||||
* @return Copy of the code position before incrementation.
|
||||
*/
|
||||
CCodePos operator++(int);
|
||||
|
||||
/**
|
||||
* @brief Increment the current position
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CCodePos& operator++();
|
||||
|
||||
/**
|
||||
* @brief Increment the current position
|
||||
* @param[in] uiOffset The offset of the character to increment to.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CCodePos& operator+=(uint32_t uiOffset);
|
||||
|
||||
private:
|
||||
const char* m_szCode = nullptr; ///< The code
|
||||
const char* m_szCurrent = nullptr; ///< The current position in the code
|
||||
const char* m_szPrependedPos = nullptr; ///< The position in the code where the prepended code is
|
||||
///< inserted into.
|
||||
const char* m_szPrependedCode = nullptr; ///< The start position of the prepended code.
|
||||
const char* m_szPrependedCurrent = nullptr; ///< The current position in the prepended code;
|
||||
std::string m_ssPrependedCode; ///< The prepended code being returned before parsing of the
|
||||
///< original code continues.
|
||||
mutable std::list<std::string> m_lstCodeChunks; ///< List of code chunks existing of part or complete
|
||||
///< prepended code.
|
||||
uint32_t m_uiLine = 0; ///< The current line
|
||||
uint32_t m_uiCol = 0; ///< The current column
|
||||
};
|
||||
|
||||
#endif // !defined CODEPOS_H
|
||||
439
sdv_executables/sdv_idl_compiler/constvariant.cpp
Normal file
439
sdv_executables/sdv_idl_compiler/constvariant.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
#include "constvariant.h"
|
||||
#include "constvariant.inl"
|
||||
|
||||
CConstVariant::CConstVariant(const CConstVariant& rvar) : m_varValue(rvar.m_varValue)
|
||||
{}
|
||||
|
||||
CConstVariant::CConstVariant(CConstVariant&& rvar) noexcept : m_varValue(std::move(rvar.m_varValue))
|
||||
{}
|
||||
|
||||
CConstVariant::CConstVariant(bool bValue) : m_varValue(bValue) {}
|
||||
CConstVariant::CConstVariant(int8_t iValue) : m_varValue(iValue) {}
|
||||
CConstVariant::CConstVariant(uint8_t uiValue) : m_varValue(uiValue) {}
|
||||
CConstVariant::CConstVariant(int16_t iValue) : m_varValue(iValue) {}
|
||||
CConstVariant::CConstVariant(uint16_t uiValue) : m_varValue(uiValue) {}
|
||||
#ifdef _WIN32
|
||||
CConstVariant::CConstVariant(long int iValue) : m_varValue(static_cast<int32_t>(iValue)) {}
|
||||
CConstVariant::CConstVariant(unsigned long int uiValue) : m_varValue(static_cast<uint32_t>(uiValue)) {}
|
||||
#endif
|
||||
CConstVariant::CConstVariant(int32_t iValue) : m_varValue(iValue) {}
|
||||
CConstVariant::CConstVariant(uint32_t uiValue) : m_varValue(uiValue) {}
|
||||
CConstVariant::CConstVariant(int64_t iValue) : m_varValue(iValue) {}
|
||||
CConstVariant::CConstVariant(uint64_t uiValue) : m_varValue(uiValue) {}
|
||||
#if defined(__GNUC__) && !defined(_WIN32)
|
||||
CConstVariant::CConstVariant(long long int iValue) : CConstVariant(static_cast<int64_t>(iValue)) {}
|
||||
CConstVariant::CConstVariant(unsigned long long int uiValue) : CConstVariant(static_cast<uint64_t>(uiValue)) {}
|
||||
#endif
|
||||
CConstVariant::CConstVariant(fixed fixValue) : m_varValue(fixValue) {}
|
||||
CConstVariant::CConstVariant(float fValue) : m_varValue(fValue) {}
|
||||
CConstVariant::CConstVariant(double dValue) : m_varValue(dValue) {}
|
||||
CConstVariant::CConstVariant(long double ldValue) : m_varValue(ldValue) {}
|
||||
CConstVariant::CConstVariant(const std::string& rssValue) : m_varValue(rssValue) {}
|
||||
CConstVariant::CConstVariant(const std::u16string& rssValue) : m_varValue(rssValue) {}
|
||||
CConstVariant::CConstVariant(const std::u32string& rssValue) : m_varValue(rssValue) {}
|
||||
CConstVariant::CConstVariant(const std::wstring& rssValue) : m_varValue(rssValue) {}
|
||||
|
||||
CConstVariant& CConstVariant::operator=(const CConstVariant& rvar)
|
||||
{
|
||||
m_varValue = rvar.m_varValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CConstVariant& CConstVariant::operator=(CConstVariant&& rvar) noexcept
|
||||
{
|
||||
m_varValue = std::move(rvar.m_varValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CConstVariant::IsArithmetic() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::is_arithmetic_v<bool>;
|
||||
case ETypeMapping::type_uint8_t: return std::is_arithmetic_v<uint8_t>;
|
||||
case ETypeMapping::type_uint16_t: return std::is_arithmetic_v<uint16_t>;
|
||||
case ETypeMapping::type_uint32_t: return std::is_arithmetic_v<uint32_t>;
|
||||
case ETypeMapping::type_uint64_t: return std::is_arithmetic_v<uint64_t>;
|
||||
case ETypeMapping::type_int8_t: return std::is_arithmetic_v<int8_t>;
|
||||
case ETypeMapping::type_int16_t: return std::is_arithmetic_v<int16_t>;
|
||||
case ETypeMapping::type_int32_t: return std::is_arithmetic_v<int32_t>;
|
||||
case ETypeMapping::type_int64_t: return std::is_arithmetic_v<int64_t>;
|
||||
case ETypeMapping::type_fixed: return std::is_arithmetic_v<fixed>;
|
||||
case ETypeMapping::type_float: return std::is_arithmetic_v<float>;
|
||||
case ETypeMapping::type_double: return std::is_arithmetic_v<double>;
|
||||
case ETypeMapping::type_long_double: return std::is_arithmetic_v<long double>;
|
||||
case ETypeMapping::type_string: return std::is_arithmetic_v<std::string>;
|
||||
case ETypeMapping::type_u16string: return std::is_arithmetic_v<std::u16string>;
|
||||
case ETypeMapping::type_u32string: return std::is_arithmetic_v<std::u32string>;
|
||||
case ETypeMapping::type_wstring: return std::is_arithmetic_v<std::wstring>;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool CConstVariant::IsIntegral() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::is_integral_v<bool>;
|
||||
case ETypeMapping::type_uint8_t: return std::is_integral_v<uint8_t>;
|
||||
case ETypeMapping::type_uint16_t: return std::is_integral_v<uint16_t>;
|
||||
case ETypeMapping::type_uint32_t: return std::is_integral_v<uint32_t>;
|
||||
case ETypeMapping::type_uint64_t: return std::is_integral_v<uint64_t>;
|
||||
case ETypeMapping::type_int8_t: return std::is_integral_v<int8_t>;
|
||||
case ETypeMapping::type_int16_t: return std::is_integral_v<int16_t>;
|
||||
case ETypeMapping::type_int32_t: return std::is_integral_v<int32_t>;
|
||||
case ETypeMapping::type_int64_t: return std::is_integral_v<int64_t>;
|
||||
case ETypeMapping::type_fixed: return std::is_integral_v<fixed>;
|
||||
case ETypeMapping::type_float: return std::is_integral_v<float>;
|
||||
case ETypeMapping::type_double: return std::is_integral_v<double>;
|
||||
case ETypeMapping::type_long_double: return std::is_integral_v<long double>;
|
||||
case ETypeMapping::type_string: return std::is_integral_v<std::string>;
|
||||
case ETypeMapping::type_u16string: return std::is_integral_v<std::u16string>;
|
||||
case ETypeMapping::type_u32string: return std::is_integral_v<std::u32string>;
|
||||
case ETypeMapping::type_wstring: return std::is_integral_v<std::wstring>;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool CConstVariant::IsFloatingPoint() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::is_floating_point_v<bool>;
|
||||
case ETypeMapping::type_uint8_t: return std::is_floating_point_v<uint8_t>;
|
||||
case ETypeMapping::type_uint16_t: return std::is_floating_point_v<uint16_t>;
|
||||
case ETypeMapping::type_uint32_t: return std::is_floating_point_v<uint32_t>;
|
||||
case ETypeMapping::type_uint64_t: return std::is_floating_point_v<uint64_t>;
|
||||
case ETypeMapping::type_int8_t: return std::is_floating_point_v<int8_t>;
|
||||
case ETypeMapping::type_int16_t: return std::is_floating_point_v<int16_t>;
|
||||
case ETypeMapping::type_int32_t: return std::is_floating_point_v<int32_t>;
|
||||
case ETypeMapping::type_int64_t: return std::is_floating_point_v<int64_t>;
|
||||
case ETypeMapping::type_fixed: return std::is_floating_point_v<fixed>;
|
||||
case ETypeMapping::type_float: return std::is_floating_point_v<float>;
|
||||
case ETypeMapping::type_double: return std::is_floating_point_v<double>;
|
||||
case ETypeMapping::type_long_double: return std::is_floating_point_v<long double>;
|
||||
case ETypeMapping::type_string: return std::is_floating_point_v<std::string>;
|
||||
case ETypeMapping::type_u16string: return std::is_floating_point_v<std::u16string>;
|
||||
case ETypeMapping::type_u32string: return std::is_floating_point_v<std::u32string>;
|
||||
case ETypeMapping::type_wstring: return std::is_floating_point_v<std::wstring>;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool CConstVariant::IsBoolean() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return true;
|
||||
case ETypeMapping::type_uint8_t: return false;
|
||||
case ETypeMapping::type_uint16_t: return false;
|
||||
case ETypeMapping::type_uint32_t: return false;
|
||||
case ETypeMapping::type_uint64_t: return false;
|
||||
case ETypeMapping::type_int8_t: return false;
|
||||
case ETypeMapping::type_int16_t: return false;
|
||||
case ETypeMapping::type_int32_t: return false;
|
||||
case ETypeMapping::type_int64_t: return false;
|
||||
case ETypeMapping::type_fixed: return false;
|
||||
case ETypeMapping::type_float: return false;
|
||||
case ETypeMapping::type_double: return false;
|
||||
case ETypeMapping::type_long_double: return false;
|
||||
case ETypeMapping::type_string: return false;
|
||||
case ETypeMapping::type_u16string: return false;
|
||||
case ETypeMapping::type_u32string: return false;
|
||||
case ETypeMapping::type_wstring: return false;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool CConstVariant::IsSigned() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::is_signed_v<bool>;
|
||||
case ETypeMapping::type_uint8_t: return std::is_signed_v<uint8_t>;
|
||||
case ETypeMapping::type_uint16_t: return std::is_signed_v<uint16_t>;
|
||||
case ETypeMapping::type_uint32_t: return std::is_signed_v<uint32_t>;
|
||||
case ETypeMapping::type_uint64_t: return std::is_signed_v<uint64_t>;
|
||||
case ETypeMapping::type_int8_t: return std::is_signed_v<int8_t>;
|
||||
case ETypeMapping::type_int16_t: return std::is_signed_v<int16_t>;
|
||||
case ETypeMapping::type_int32_t: return std::is_signed_v<int32_t>;
|
||||
case ETypeMapping::type_int64_t: return std::is_signed_v<int64_t>;
|
||||
case ETypeMapping::type_fixed: return std::is_signed_v<fixed>;
|
||||
case ETypeMapping::type_float: return std::is_signed_v<float>;
|
||||
case ETypeMapping::type_double: return std::is_signed_v<double>;
|
||||
case ETypeMapping::type_long_double: return std::is_signed_v<long double>;
|
||||
case ETypeMapping::type_string: return std::is_signed_v<std::string>;
|
||||
case ETypeMapping::type_u16string: return std::is_signed_v<std::u16string>;
|
||||
case ETypeMapping::type_u32string: return std::is_signed_v<std::u32string>;
|
||||
case ETypeMapping::type_wstring: return std::is_signed_v<std::wstring>;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
bool CConstVariant::IsUnsigned() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::is_unsigned_v<bool>;
|
||||
case ETypeMapping::type_uint8_t: return std::is_unsigned_v<uint8_t>;
|
||||
case ETypeMapping::type_uint16_t: return std::is_unsigned_v<uint16_t>;
|
||||
case ETypeMapping::type_uint32_t: return std::is_unsigned_v<uint32_t>;
|
||||
case ETypeMapping::type_uint64_t: return std::is_unsigned_v<uint64_t>;
|
||||
case ETypeMapping::type_int8_t: return std::is_unsigned_v<int8_t>;
|
||||
case ETypeMapping::type_int16_t: return std::is_unsigned_v<int16_t>;
|
||||
case ETypeMapping::type_int32_t: return std::is_unsigned_v<int32_t>;
|
||||
case ETypeMapping::type_int64_t: return std::is_unsigned_v<int64_t>;
|
||||
case ETypeMapping::type_fixed: return std::is_unsigned_v<fixed>;
|
||||
case ETypeMapping::type_float: return std::is_unsigned_v<float>;
|
||||
case ETypeMapping::type_double: return std::is_unsigned_v<double>;
|
||||
case ETypeMapping::type_long_double: return std::is_unsigned_v<long double>;
|
||||
case ETypeMapping::type_string: return std::is_unsigned_v<std::string>;
|
||||
case ETypeMapping::type_u16string: return std::is_unsigned_v<std::u16string>;
|
||||
case ETypeMapping::type_u32string: return std::is_unsigned_v<std::u32string>;
|
||||
case ETypeMapping::type_wstring: return std::is_unsigned_v<std::wstring>;
|
||||
default:
|
||||
throw CCompileException("Internal error: the variant doesn't contain any valid data type.");
|
||||
}
|
||||
}
|
||||
|
||||
size_t CConstVariant::Ranking() const
|
||||
{
|
||||
// The ranking is provided through the index.
|
||||
return m_varValue.index();
|
||||
}
|
||||
|
||||
void CConstVariant::Convert(size_t nRank)
|
||||
{
|
||||
if (nRank == Ranking()) return;
|
||||
|
||||
switch (static_cast<ETypeMapping>(nRank))
|
||||
{
|
||||
case ETypeMapping::type_bool: m_varValue = Get<bool>(); break;
|
||||
case ETypeMapping::type_uint8_t: m_varValue = Get<uint8_t>(); break;
|
||||
case ETypeMapping::type_uint16_t: m_varValue = Get<uint16_t>(); break;
|
||||
case ETypeMapping::type_uint32_t: m_varValue = Get<uint32_t>(); break;
|
||||
case ETypeMapping::type_uint64_t: m_varValue = Get<uint64_t>(); break;
|
||||
case ETypeMapping::type_int8_t: m_varValue = Get<int8_t>(); break;
|
||||
case ETypeMapping::type_int16_t: m_varValue = Get<int16_t>(); break;
|
||||
case ETypeMapping::type_int32_t: m_varValue = Get<int32_t>(); break;
|
||||
case ETypeMapping::type_int64_t: m_varValue = Get<int64_t>(); break;
|
||||
case ETypeMapping::type_fixed: m_varValue = Get<fixed>(); break;
|
||||
case ETypeMapping::type_float: m_varValue = Get<float>(); break;
|
||||
case ETypeMapping::type_double: m_varValue = Get<double>(); break;
|
||||
case ETypeMapping::type_long_double: m_varValue = Get<long double>(); break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
CConstVariant CConstVariant::operator!() const
|
||||
{
|
||||
return UnaryOperationIntegral(*this, [](auto tOperand) {return !tOperand;});
|
||||
}
|
||||
|
||||
CConstVariant CConstVariant::operator~() const
|
||||
{
|
||||
return UnaryOperationIntegral(*this, [](auto tOperand) -> CConstVariant {
|
||||
if constexpr (!std::is_same_v<decltype(tOperand), bool>)
|
||||
return ~tOperand;
|
||||
else
|
||||
throw CCompileException("Cannot execute bitwise operations on a boolean."); });
|
||||
}
|
||||
|
||||
CConstVariant CConstVariant::operator+() const
|
||||
{
|
||||
return UnaryOperation(*this, [](auto tOperand) {return tOperand;});
|
||||
}
|
||||
|
||||
CConstVariant CConstVariant::operator-() const
|
||||
{
|
||||
return CConstVariant::UnaryOperation(*this, [](auto tOperand) -> CConstVariant {
|
||||
if constexpr (!std::is_same_v<decltype(tOperand), bool>)
|
||||
{
|
||||
if constexpr (std::is_signed_v<decltype(tOperand)>)
|
||||
return -tOperand;
|
||||
else if constexpr (std::is_integral_v<decltype(tOperand)>)
|
||||
{
|
||||
// Two's complement plus 1.
|
||||
return ~tOperand + 1;
|
||||
} else
|
||||
throw CCompileException("Internal error: cannot execute unary arithmic operation on the type.");
|
||||
}
|
||||
else
|
||||
throw CCompileException("Cannot execute unary arithmic operations on a boolean."); });
|
||||
}
|
||||
|
||||
void Equalize(CConstVariant& rvar1, CConstVariant& rvar2)
|
||||
{
|
||||
// Are the types of both variant the same?
|
||||
if (rvar1.Ranking() == rvar2.Ranking()) return;
|
||||
|
||||
// Equalization only works if both types are arithmetic.
|
||||
if (!rvar1.IsArithmetic() || !rvar2.IsArithmetic())
|
||||
throw CCompileException("The types of both operands are not compatible.");
|
||||
|
||||
// Check for highest ranking and adapt the lowest.
|
||||
if (rvar1.Ranking() > rvar2.Ranking())
|
||||
rvar2.Convert(rvar1.Ranking());
|
||||
else
|
||||
rvar1.Convert(rvar2.Ranking());
|
||||
}
|
||||
|
||||
CConstVariant operator*(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 * tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator/(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
|
||||
#endif
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) -> CConstVariant
|
||||
{
|
||||
if constexpr (!std::is_same_v<decltype(tOperand1), bool>)
|
||||
{
|
||||
if (!tOperand2) throw CCompileException("Division by zero.");
|
||||
return tOperand1 / tOperand2;
|
||||
}
|
||||
else
|
||||
throw CCompileException("Cannot divide a boolean.");
|
||||
});
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
CConstVariant operator+(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 + tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator-(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 - tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 < tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator<=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 <= tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 > tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator>=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 >= tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator==(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 == tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator!=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 != tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator%(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
|
||||
#endif
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) -> CConstVariant
|
||||
{
|
||||
if constexpr (std::is_integral_v<decltype(tOperand1)> && !std::is_same_v<decltype(tOperand1), bool>)
|
||||
{
|
||||
if (!tOperand2) throw CCompileException("Division by zero.");
|
||||
return tOperand1 % tOperand2;
|
||||
}
|
||||
else
|
||||
throw CCompileException("Cannot divide a boolean.");
|
||||
});
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
CConstVariant operator<<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 << tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator>>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 >> tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 & tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator^(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 ^ tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator|(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2) {return tOperand1 | tOperand2;});
|
||||
}
|
||||
|
||||
CConstVariant operator&&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2)
|
||||
{
|
||||
if constexpr (std::is_integral_v<decltype(tOperand1)> &&
|
||||
std::is_integral_v<decltype(tOperand2)>)
|
||||
return tOperand1 && tOperand2;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
CConstVariant operator||(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2)
|
||||
{
|
||||
return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2,
|
||||
[](auto tOperand1, auto tOperand2)
|
||||
{
|
||||
if constexpr (std::is_integral_v<decltype(tOperand1)> &&
|
||||
std::is_integral_v<decltype(tOperand2)>)
|
||||
return tOperand1 || tOperand2;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
}
|
||||
550
sdv_executables/sdv_idl_compiler/constvariant.h
Normal file
550
sdv_executables/sdv_idl_compiler/constvariant.h
Normal file
@@ -0,0 +1,550 @@
|
||||
#ifndef VARIANT_H
|
||||
#define VARIANT_H
|
||||
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief Fixed data type is based on the double data type. Highest value is 31 digits positive and lowest 31 digits negative. The
|
||||
* best precision is 1/31.
|
||||
*/
|
||||
struct fixed
|
||||
{
|
||||
double dValue; ///< The value
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @tparam TType Type of the value to create a fixed type of
|
||||
* @param[in] tValue The value to assign
|
||||
*/
|
||||
template <typename TType>
|
||||
constexpr fixed(TType tValue) : dValue(static_cast<double>(tValue)) {}
|
||||
/**
|
||||
* @brief Assignment operator
|
||||
* @tparam TType Type of the value to assign
|
||||
* @param[in] tValue The value to assign
|
||||
* @return Reference to this class
|
||||
*/
|
||||
template <typename TType>
|
||||
constexpr fixed& operator=(TType tValue) { dValue = tValue; return *this; }
|
||||
/**
|
||||
* @{
|
||||
* @brief Contained value as double
|
||||
* @return The value
|
||||
*/
|
||||
constexpr operator double() const {return dValue;}
|
||||
constexpr operator const double&() const {return dValue;}
|
||||
constexpr operator double&() {return dValue;}
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
* @brief Unary operator to return a fixed type.
|
||||
* @return the fixed type as a copy from this class.
|
||||
*/
|
||||
fixed constexpr operator+() const {return *this;}
|
||||
/**
|
||||
* @brief Unary operator to return a negative fixed type.
|
||||
* @return the fixed type as a copy from this class.
|
||||
*/
|
||||
fixed constexpr operator-() const {return fixed(-dValue);}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Add two fixed types
|
||||
* @param[in] val1 Value 1
|
||||
* @param[in] val2 Value 2
|
||||
* @return The result
|
||||
*/
|
||||
inline fixed operator+(fixed val1, fixed val2) { return val1.dValue + val2.dValue; }
|
||||
/**
|
||||
* @brief Subtract two fixed types
|
||||
* @param[in] val1 Value 1
|
||||
* @param[in] val2 Value 2
|
||||
* @return The result
|
||||
*/
|
||||
inline fixed operator-(fixed val1, fixed val2) { return val1.dValue - val2.dValue; }
|
||||
/**
|
||||
* @brief Multiply two fixed types
|
||||
* @param[in] val1 Value 1
|
||||
* @param[in] val2 Value 2
|
||||
* @return The result
|
||||
*/
|
||||
inline fixed operator*(fixed val1, fixed val2) { return val1.dValue * val2.dValue; }
|
||||
/**
|
||||
* @brief Divide two fixed types
|
||||
* @param[in] val1 Value 1
|
||||
* @param[in] val2 Value 2
|
||||
* @return The result
|
||||
*/
|
||||
inline fixed operator/(fixed val1, fixed val2) { return val1.dValue / val2.dValue; }
|
||||
/**
|
||||
* @{
|
||||
* @brief Compare two types
|
||||
* @param[in] val1 Value 1
|
||||
* @param[in] val2 Value 2
|
||||
* @return The result
|
||||
*/
|
||||
inline bool operator<(fixed val1, fixed val2) { return val1.dValue < val2.dValue; }
|
||||
inline bool operator<(fixed val1, double val2) { return val1.dValue < val2; }
|
||||
inline bool operator<(double val1, fixed val2) { return val1 < val2.dValue; }
|
||||
inline bool operator<=(fixed val1, fixed val2) { return val1.dValue <= val2.dValue; }
|
||||
inline bool operator<=(fixed val1, double val2) { return val1.dValue <= val2; }
|
||||
inline bool operator<=(double val1, fixed val2) { return val1 <= val2.dValue; }
|
||||
inline bool operator>(fixed val1, fixed val2) { return val1.dValue > val2.dValue; }
|
||||
inline bool operator>(fixed val1, double val2) { return val1.dValue > val2; }
|
||||
inline bool operator>(double val1, fixed val2) { return val1 > val2.dValue; }
|
||||
inline bool operator>=(fixed val1, fixed val2) { return val1.dValue >= val2.dValue; }
|
||||
inline bool operator>=(fixed val1, double val2) { return val1.dValue >= val2; }
|
||||
inline bool operator>=(double val1, fixed val2) { return val1 >= val2.dValue; }
|
||||
inline bool operator==(fixed val1, fixed val2) { return val1.dValue == val2.dValue; }
|
||||
inline bool operator==(fixed val1, double val2) { return val1.dValue == val2; }
|
||||
inline bool operator==(double val1, fixed val2) { return val1 == val2.dValue; }
|
||||
inline bool operator!=(fixed val1, fixed val2) { return val1.dValue != val2.dValue; }
|
||||
inline bool operator!=(fixed val1, double val2) { return val1.dValue != val2; }
|
||||
inline bool operator!=(double val1, fixed val2) { return val1 != val2.dValue; }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
namespace std
|
||||
{
|
||||
#ifndef DOXYGEN_IGNORE
|
||||
/**
|
||||
* @brief Specialization of floating point variable for fixed data type.
|
||||
*/
|
||||
template <>
|
||||
inline constexpr bool is_floating_point_v<::fixed> = true;
|
||||
|
||||
/**
|
||||
* @brief Specialization of signed number variable for fixed data type.
|
||||
*/
|
||||
template <>
|
||||
inline constexpr bool is_signed_v<::fixed> = true;
|
||||
|
||||
/**
|
||||
* @brief Specialization of arithmic data type variable for fixed data type.
|
||||
*/
|
||||
template <>
|
||||
inline constexpr bool is_arithmetic_v<::fixed> = true;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Specialization of numeric limits class for fixed data type.
|
||||
*/
|
||||
template <>
|
||||
struct numeric_limits<::fixed> : numeric_limits<double>
|
||||
{
|
||||
/**
|
||||
* @brief Returns the smallest finite value representable by fixed.
|
||||
* @return The smallest finite type.
|
||||
*/
|
||||
[[nodiscard]] static constexpr ::fixed(min)() noexcept
|
||||
{
|
||||
return 1.0 / static_cast<double>(max());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the minimum largest value representable by fixed.
|
||||
* @return The largest finite type.
|
||||
*/
|
||||
[[nodiscard]] static constexpr ::fixed(max)() noexcept
|
||||
{
|
||||
// 31 bits available
|
||||
return 1ll << 31ll;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the lowest finite value representable by fixed.
|
||||
* @return The lowest finite type.
|
||||
*/
|
||||
[[nodiscard]] static constexpr ::fixed lowest() noexcept
|
||||
{
|
||||
return -(max)();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Variant class to store const values.
|
||||
* @details This class is used for the storage of all possible data types as well as solving the expressions in const assignments.
|
||||
* Only 32-bit, 64-bit integers, largest floating point and several string data type variations are used. The conversion rules for
|
||||
* data types follow the C++11 conversion rules:
|
||||
* - Assignment of data type:
|
||||
* - Signed integers are assigned to int32_t when smaller than 64-bit; otherwise are assigned to int64_t.
|
||||
* - Unsigned integers are assigned to uint32_t when smaller than 64-bit; otherwise are assigned to uint64_t.
|
||||
* - Integral signed data types are: char, short, long, long long, int8_t, int16_t, int32_t int64_t.
|
||||
* - Integral unsigned data types are: bool, unsigned short, unsigned long, unsigned long long, uint8_t, uint16_t, uint32_t
|
||||
* uint64_t, wchar_t, char16_t, char32_t.
|
||||
* - String objects and string pointers are assigned to their corresponding counterparts.
|
||||
* - Arithmic operations with two operands:
|
||||
* - If either operand is long double, the other operand is converted to long double.
|
||||
* - If both integral operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the
|
||||
* - operand with the greater conversion rank.
|
||||
* - Otherwise, if the unsigned integral operand's conversion rank is greater or equal to the conversion rank of the signed
|
||||
* operand, the signed operand is converted to the unsigned operand's type.
|
||||
* - Otherwise, if the signed integral operand's type can represent all values of the unsigned operand, the unsigned operand
|
||||
* is converted to the signed operand's type.
|
||||
* - Otherwise, both integral operands are converted to the unsigned counterpart of the signed operand's type.
|
||||
* - Conversions with and between string based operands are not supported.
|
||||
* - Cast to data type:
|
||||
* - If the stored data type and target data type are both signed or both unsigned, the target data type boundaries are
|
||||
* checked with the value before assignment takes place.
|
||||
* - If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo
|
||||
* 2^n where n is the number of bits used to represent the destination type.
|
||||
* - If the destination type is signed, the value does not change if the source integer can be represented in the destination
|
||||
* type.
|
||||
*/
|
||||
class CConstVariant
|
||||
{
|
||||
/**
|
||||
* The variant type containing the value in one of the data types supplied. The data type order provides the ranking of the
|
||||
* types.
|
||||
*/
|
||||
using TVariant = std::variant<bool, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, fixed, float,
|
||||
double, long double, std::string, std::u16string, std::u32string, std::wstring>;
|
||||
public:
|
||||
/**
|
||||
* @brief Type to index mapping.
|
||||
* @remarks 'char' is represented by 'int8_t'. 'char16_t' is represented by 'uint16_t'. 'char32_t' is represented by
|
||||
* 'int32_t'. 'wchar_t' is either represented by 'uint16_t' or by 'uint32_t'. ASCII and UTF-8 strings are represented by
|
||||
* 'std::string'.
|
||||
*/
|
||||
enum ETypeMapping
|
||||
{
|
||||
type_bool = 0, type_int8_t, type_uint8_t, type_int16_t, type_uint16_t, type_int32_t, type_uint32_t, type_int64_t,
|
||||
type_uint64_t, type_fixed, type_float, type_double, type_long_double, type_string, type_u16string, type_u32string,
|
||||
type_wstring,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
CConstVariant() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param[in] rvar Reference to the const variant to copy from.
|
||||
*/
|
||||
CConstVariant(const CConstVariant& rvar);
|
||||
|
||||
/**
|
||||
* @brief Move constructor is not available.
|
||||
* @param[in] rvar Reference to the const variant to move from.
|
||||
*/
|
||||
CConstVariant(CConstVariant&& rvar) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] bValue Value to assign.
|
||||
*/
|
||||
CConstVariant(bool bValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(int8_t iValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(uint8_t uiValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(int16_t iValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(uint16_t uiValue);
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(long int iValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(unsigned long int uiValue);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(int32_t iValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(uint32_t uiValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(int64_t iValue);
|
||||
|
||||
#if defined(__GNUC__) && !defined(_WIN32)
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] iValue Value to assign.
|
||||
*/
|
||||
CConstVariant(long long int iValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(unsigned long long int uiValue);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] uiValue Value to assign.
|
||||
*/
|
||||
CConstVariant(uint64_t uiValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] fixValue Value to assign.
|
||||
*/
|
||||
CConstVariant(fixed fixValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] fValue Value to assign.
|
||||
*/
|
||||
CConstVariant(float fValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] dValue Value to assign.
|
||||
*/
|
||||
CConstVariant(double dValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] ldValue Value to assign.
|
||||
*/
|
||||
CConstVariant(long double ldValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] rssValue Reference to the string value to assign.
|
||||
*/
|
||||
CConstVariant(const std::string& rssValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] rssValue Reference to the string value to assign.
|
||||
*/
|
||||
CConstVariant(const std::u16string& rssValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] rssValue Reference to the string value to assign.
|
||||
*/
|
||||
CConstVariant(const std::u32string& rssValue);
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor.
|
||||
* @param[in] rssValue Reference to the string value to assign.
|
||||
*/
|
||||
CConstVariant(const std::wstring& rssValue);
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator
|
||||
* @param[in] rvar Reference to the const variant to copy from.
|
||||
* @return Reference to the const variant instance.
|
||||
*/
|
||||
CConstVariant& operator=(const CConstVariant& rvar);
|
||||
|
||||
/**
|
||||
* @brief Move operator is not available.
|
||||
* @param[in] rvar Reference to the const variant to move from.
|
||||
* @return Reference to the const variant instance.
|
||||
*/
|
||||
CConstVariant& operator=(CConstVariant&& rvar) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @tparam TType Type of the value to assign.
|
||||
* @param[in] rtValue Reference to the value to assign.
|
||||
* @return Reference to the const variant instance.
|
||||
*/
|
||||
template <typename TType>
|
||||
CConstVariant& operator=(const TType& rtValue);
|
||||
|
||||
/**
|
||||
* @brief Get the value of the variant casted to the provided target type.
|
||||
* @throw Throws exception when the value exceeds the boundaries of the target value or the types are incompatible.
|
||||
* @tparam TTargetType The target type.
|
||||
* @return The value casted to the target type.
|
||||
*/
|
||||
template <typename TTargetType>
|
||||
TTargetType Get() const;
|
||||
|
||||
/**
|
||||
* @brief Get the value as string.
|
||||
* @return Get the value as a string.
|
||||
*/
|
||||
std::string GetAsString() const;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Meta information
|
||||
* @remarks The ranking function provides a number indicating the ranking of the type.
|
||||
* @return Returns 'true' when the type stored in the variant has the specific attribute; 'false' otherwise.
|
||||
*/
|
||||
bool IsArithmetic() const;
|
||||
bool IsIntegral() const;
|
||||
bool IsFloatingPoint() const;
|
||||
bool IsBoolean() const;
|
||||
bool IsSigned() const;
|
||||
bool IsUnsigned() const;
|
||||
size_t Ranking() const;
|
||||
template <typename TType> bool IsSame() const;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Convert the variant to the type supplied.
|
||||
* @throw Throws exception when the value exceeds the boundaries of the target value or the types are incompatible.
|
||||
* @param[in] nRank The rank of the type to convert to.
|
||||
*/
|
||||
void Convert(size_t nRank);
|
||||
|
||||
/**
|
||||
* @brief Convert the variant to the type supplied.
|
||||
* @throw Throws exception when the value exceeds the boundaries of the target value or the types are incompatible.
|
||||
* @tparam TType The type to convert to.
|
||||
*/
|
||||
template <typename TType>
|
||||
void Convert();
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Unary arithmetic operators.
|
||||
* @remarks The bit operator '~' and the logical operator '!' work with integral operands only.
|
||||
* @result The result of the operation.
|
||||
*/
|
||||
CConstVariant operator!() const;
|
||||
CConstVariant operator~() const;
|
||||
CConstVariant operator+() const;
|
||||
CConstVariant operator-() const;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Do unary operation. The first version allows the operation on any arithmetic type. The second version works for
|
||||
* integral operation only.
|
||||
* @tparam TFunction The function type that should do the operation. The function uses the prototype:
|
||||
* @code CConstVariant(auto tOperand); @endcode
|
||||
* @param[in] rvarOperand The operand.
|
||||
* @param[in] tOperation The function that is used for the operation.
|
||||
* @return The const variant with the result.
|
||||
*/
|
||||
template <typename TFunction>
|
||||
static CConstVariant UnaryOperation(const CConstVariant& rvarOperand, TFunction tOperation);
|
||||
template <typename TFunction>
|
||||
static CConstVariant UnaryOperationIntegral(const CConstVariant& rvarOperand, TFunction tOperation);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Do binary operation. The first version allows the operation on any arithmetic type. The second version works for
|
||||
* integral operation only.
|
||||
* @tparam TFunction The function type that should do the operation. The function uses the prototype:
|
||||
* @code CConstVariant(auto tOperand1, auto tOperand2); @endcode
|
||||
* @param[in] rvarOperand1 The first operand.
|
||||
* @param[in] rvarOperand2 The second operand.
|
||||
* @param[in] tOperation The function that is used for the operation.
|
||||
* @return The const variant with the result.
|
||||
*/
|
||||
template <typename TFunction>
|
||||
static CConstVariant BinaryOperation(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2,
|
||||
TFunction tOperation);
|
||||
template <typename TFunction>
|
||||
static CConstVariant BinaryOperationIntegral(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2,
|
||||
TFunction tOperation);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Get the value of the variant.
|
||||
* @details Get the value of the variant by providing the variant type as well as the target type. Do conversion if necessary.
|
||||
* Follow the casting rules as defined at the class description.
|
||||
* @throw Throws exception when the value exceeds the boundaries of the target value or the types are incompatible.
|
||||
* @tparam TTargetType The target type.
|
||||
* @tparam TVariantType The variant type
|
||||
* @return The value casted to the target type.
|
||||
*/
|
||||
template <typename TTargetType, typename TVariantType>
|
||||
TTargetType InternalGet() const;
|
||||
|
||||
TVariant m_varValue; ///< The variant that stores the value.
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Equalize variants.
|
||||
* @details Convert the variant of lesser ranking to a higher ranking. This function is used for binary arithmetic operations. The
|
||||
* function implements the rules as described at the CConstVariant class description.
|
||||
* @param[in] rvar1 The first variant.
|
||||
* @param[in] rvar2 The second variant.
|
||||
*/
|
||||
void Equalize(CConstVariant& rvar1, CConstVariant& rvar2);
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Arithmetic operators.
|
||||
* @remarks The bit operators (~ & | ^ << >>) as well as the remainder (%) operator work with integral operands only.
|
||||
* @param[in] rvarOperand1 The first operand of a binary operation.
|
||||
* @param[in] rvarOperand2 The second operand of a binary operation.
|
||||
* @result The result of the operation.
|
||||
*/
|
||||
CConstVariant operator*(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator/(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator+(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator-(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator<=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator>=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator+(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator==(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator!=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator%(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator<<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator>>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator^(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator|(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator&&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
CConstVariant operator||(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // !defined(VARIANT_H)
|
||||
343
sdv_executables/sdv_idl_compiler/constvariant.inl
Normal file
343
sdv_executables/sdv_idl_compiler/constvariant.inl
Normal file
@@ -0,0 +1,343 @@
|
||||
#ifndef CONSTVARIANT_INL
|
||||
#define CONSTVARIANT_INL
|
||||
|
||||
#include "exception.h"
|
||||
#include "constvariant.h"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
template <typename TType>
|
||||
inline CConstVariant& CConstVariant::operator=(const TType& rtValue)
|
||||
{
|
||||
m_varValue = rtValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
template <>
|
||||
inline CConstVariant& CConstVariant::operator=(const long int& rtValue)
|
||||
{
|
||||
m_varValue = static_cast<int32_t>(rtValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline CConstVariant& CConstVariant::operator=(const unsigned long int& rtValue)
|
||||
{
|
||||
m_varValue = static_cast<uint32_t>(rtValue);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( __GNUC__) && !defined(_WIN32)
|
||||
|
||||
template <>
|
||||
inline CConstVariant& CConstVariant::operator=(const long long int& rtValue)
|
||||
{
|
||||
m_varValue = static_cast<int64_t>(rtValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline CConstVariant& CConstVariant::operator=(const unsigned long long int& rtValue)
|
||||
{
|
||||
m_varValue = static_cast<uint64_t>(rtValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename TTargetType>
|
||||
inline TTargetType CConstVariant::Get() const
|
||||
{
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return InternalGet<TTargetType, bool>();
|
||||
case ETypeMapping::type_uint8_t: return InternalGet<TTargetType, uint8_t>();
|
||||
case ETypeMapping::type_uint16_t: return InternalGet<TTargetType, uint16_t>();
|
||||
case ETypeMapping::type_uint32_t: return InternalGet<TTargetType, uint32_t>();
|
||||
case ETypeMapping::type_uint64_t: return InternalGet<TTargetType, uint64_t>();
|
||||
case ETypeMapping::type_int8_t: return InternalGet<TTargetType, int8_t>();
|
||||
case ETypeMapping::type_int16_t: return InternalGet<TTargetType, int16_t>();
|
||||
case ETypeMapping::type_int32_t: return InternalGet<TTargetType, int32_t>();
|
||||
case ETypeMapping::type_int64_t: return InternalGet<TTargetType, int64_t>();
|
||||
case ETypeMapping::type_fixed: return InternalGet<TTargetType, fixed>();
|
||||
case ETypeMapping::type_float: return InternalGet<TTargetType, float>();
|
||||
case ETypeMapping::type_double: return InternalGet<TTargetType, double>();
|
||||
case ETypeMapping::type_long_double: return InternalGet<TTargetType, long double>();
|
||||
case ETypeMapping::type_string: return InternalGet<TTargetType, std::string>();
|
||||
case ETypeMapping::type_u16string: return InternalGet<TTargetType, std::u16string>();
|
||||
case ETypeMapping::type_u32string: return InternalGet<TTargetType, std::u32string>();
|
||||
case ETypeMapping::type_wstring: return InternalGet<TTargetType, std::wstring>();
|
||||
default:
|
||||
throw CCompileException("Conversion to target data type is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string CConstVariant::GetAsString() const
|
||||
{
|
||||
// TODO: Add conversion for the missing types
|
||||
switch (static_cast<ETypeMapping>(m_varValue.index()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return std::to_string(std::get<bool>(m_varValue));
|
||||
case ETypeMapping::type_uint8_t: return std::to_string(std::get<uint8_t>(m_varValue));
|
||||
case ETypeMapping::type_uint16_t: return std::to_string(std::get<uint16_t>(m_varValue));
|
||||
case ETypeMapping::type_uint32_t: return std::to_string(std::get<uint32_t>(m_varValue));
|
||||
case ETypeMapping::type_uint64_t: return std::to_string(std::get<uint64_t>(m_varValue));
|
||||
case ETypeMapping::type_int8_t: return std::to_string(std::get<int8_t>(m_varValue));
|
||||
case ETypeMapping::type_int16_t: return std::to_string(std::get<int16_t>(m_varValue));
|
||||
case ETypeMapping::type_int32_t: return std::to_string(std::get<int32_t>(m_varValue));
|
||||
case ETypeMapping::type_int64_t: return std::to_string(std::get<int64_t>(m_varValue));
|
||||
case ETypeMapping::type_fixed: return "fixed";
|
||||
case ETypeMapping::type_float: return std::to_string(std::get<float>(m_varValue));
|
||||
case ETypeMapping::type_double: return std::to_string(std::get<double>(m_varValue));
|
||||
case ETypeMapping::type_long_double: return std::to_string(std::get<long double>(m_varValue));
|
||||
case ETypeMapping::type_string: return std::get<std::string>(m_varValue);
|
||||
case ETypeMapping::type_u16string: return "UTF-16 string";
|
||||
case ETypeMapping::type_u32string: return "UTF-32string";
|
||||
case ETypeMapping::type_wstring: return "wstring";
|
||||
default:
|
||||
throw CCompileException("Creating a string from value is not possible.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TType>
|
||||
inline bool CConstVariant::IsSame() const
|
||||
{
|
||||
return std::holds_alternative<TType>(m_varValue);
|
||||
}
|
||||
|
||||
template <typename TType>
|
||||
inline void CConstVariant::Convert()
|
||||
{
|
||||
// Conversion needed?
|
||||
if (IsSame<TType>()) return;
|
||||
|
||||
if constexpr (std::is_integral_v<TType>)
|
||||
{
|
||||
if constexpr (std::is_signed_v<TType>)
|
||||
{
|
||||
// Singed integer
|
||||
// NOTE: 'if' is used instead of switch to allow the use of constexpr.
|
||||
if constexpr (sizeof(TType) == sizeof(int8_t))
|
||||
Convert(ETypeMapping::type_int8_t);
|
||||
else if constexpr (sizeof(TType) == sizeof(int16_t))
|
||||
Convert(ETypeMapping::type_int16_t);
|
||||
else if constexpr (sizeof(TType) == sizeof(int32_t))
|
||||
Convert(ETypeMapping::type_int32_t);
|
||||
else
|
||||
Convert(ETypeMapping::type_int64_t);
|
||||
} else
|
||||
{
|
||||
// Unsigned integer
|
||||
// NOTE: 'if' is used instead of switch to allow the use of constexpr.
|
||||
if constexpr (sizeof(TType) == sizeof(uint8_t))
|
||||
{
|
||||
if constexpr (std::is_same_v<bool, TType>)
|
||||
Convert(ETypeMapping::type_bool);
|
||||
else
|
||||
Convert(ETypeMapping::type_uint8_t);
|
||||
} else if constexpr (sizeof(TType) == sizeof(uint16_t))
|
||||
Convert(ETypeMapping::type_uint16_t);
|
||||
else if constexpr (sizeof(TType) == sizeof(uint32_t))
|
||||
Convert(ETypeMapping::type_uint32_t);
|
||||
else
|
||||
Convert(ETypeMapping::type_uint64_t);
|
||||
}
|
||||
|
||||
// Done!
|
||||
return;
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<TType>)
|
||||
{
|
||||
// NOTE: 'if' is used instead of switch to allow the use of constexpr.
|
||||
if constexpr (std::is_same_v<TType, fixed>)
|
||||
Convert(ETypeMapping::type_fixed);
|
||||
else if constexpr (sizeof(TType) == sizeof(float))
|
||||
Convert(ETypeMapping::type_float);
|
||||
else if constexpr (sizeof(TType) == sizeof(double))
|
||||
Convert(ETypeMapping::type_double);
|
||||
else
|
||||
Convert(ETypeMapping::type_long_double);
|
||||
|
||||
// Done!
|
||||
return;
|
||||
} else
|
||||
{
|
||||
// Conversion is only possible between arithmetic types.
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFunction>
|
||||
inline CConstVariant CConstVariant::UnaryOperation(const CConstVariant& rvarOperand, TFunction tOperation)
|
||||
{
|
||||
// Based on the operand type, execute the provided function
|
||||
switch (static_cast<ETypeMapping>(rvarOperand.Ranking()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return tOperation(rvarOperand.Get<bool>()); break;
|
||||
case ETypeMapping::type_uint8_t: return tOperation(rvarOperand.Get<uint8_t>()); break;
|
||||
case ETypeMapping::type_uint16_t: return tOperation(rvarOperand.Get<uint16_t>()); break;
|
||||
case ETypeMapping::type_uint32_t: return tOperation(rvarOperand.Get<uint32_t>()); break;
|
||||
case ETypeMapping::type_uint64_t: return tOperation(rvarOperand.Get<uint64_t>()); break;
|
||||
case ETypeMapping::type_int8_t: return tOperation(rvarOperand.Get<int8_t>()); break;
|
||||
case ETypeMapping::type_int16_t: return tOperation(rvarOperand.Get<int16_t>()); break;
|
||||
case ETypeMapping::type_int32_t: return tOperation(rvarOperand.Get<int32_t>()); break;
|
||||
case ETypeMapping::type_int64_t: return tOperation(rvarOperand.Get<int64_t>()); break;
|
||||
case ETypeMapping::type_fixed: return tOperation(rvarOperand.Get<fixed>()); break;
|
||||
case ETypeMapping::type_float: return tOperation(rvarOperand.Get<float>()); break;
|
||||
case ETypeMapping::type_double: return tOperation(rvarOperand.Get<double>()); break;
|
||||
case ETypeMapping::type_long_double: return tOperation(rvarOperand.Get<long double>()); break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFunction>
|
||||
inline CConstVariant CConstVariant::UnaryOperationIntegral(const CConstVariant& rvarOperand, TFunction tOperation)
|
||||
{
|
||||
// Based on the operand type, execute the provided function
|
||||
switch (static_cast<ETypeMapping>(rvarOperand.Ranking()))
|
||||
{
|
||||
case ETypeMapping::type_bool: return tOperation(rvarOperand.Get<bool>()); break;
|
||||
case ETypeMapping::type_uint8_t: return tOperation(rvarOperand.Get<uint8_t>()); break;
|
||||
case ETypeMapping::type_uint16_t: return tOperation(rvarOperand.Get<uint16_t>()); break;
|
||||
case ETypeMapping::type_uint32_t: return tOperation(rvarOperand.Get<uint32_t>()); break;
|
||||
case ETypeMapping::type_uint64_t: return tOperation(rvarOperand.Get<uint64_t>()); break;
|
||||
case ETypeMapping::type_int8_t: return tOperation(rvarOperand.Get<int8_t>()); break;
|
||||
case ETypeMapping::type_int16_t: return tOperation(rvarOperand.Get<int16_t>()); break;
|
||||
case ETypeMapping::type_int32_t: return tOperation(rvarOperand.Get<int32_t>()); break;
|
||||
case ETypeMapping::type_int64_t: return tOperation(rvarOperand.Get<int64_t>()); break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFunction>
|
||||
inline CConstVariant CConstVariant::BinaryOperation(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2,
|
||||
TFunction tOperation)
|
||||
{
|
||||
// Equalize the operands
|
||||
CConstVariant varOperand1 = rvarOperand1;
|
||||
CConstVariant varOperand2 = rvarOperand2;
|
||||
Equalize(varOperand1, varOperand2);
|
||||
|
||||
// Based on the operand type, execute the provided function
|
||||
switch (static_cast<ETypeMapping>(varOperand1.Ranking()))
|
||||
{
|
||||
// NOTE: Arithmetic operations on "bool" can cause warnings. Use uint8_t instead.
|
||||
case ETypeMapping::type_bool: return tOperation(varOperand1.Get<uint8_t>(), varOperand2.Get<uint8_t>()); break;
|
||||
case ETypeMapping::type_uint8_t: return tOperation(varOperand1.Get<uint8_t>(), varOperand2.Get<uint8_t>()); break;
|
||||
case ETypeMapping::type_uint16_t: return tOperation(varOperand1.Get<uint16_t>(), varOperand2.Get<uint16_t>()); break;
|
||||
case ETypeMapping::type_uint32_t: return tOperation(varOperand1.Get<uint32_t>(), varOperand2.Get<uint32_t>()); break;
|
||||
case ETypeMapping::type_uint64_t: return tOperation(varOperand1.Get<uint64_t>(), varOperand2.Get<uint64_t>()); break;
|
||||
case ETypeMapping::type_int8_t: return tOperation(varOperand1.Get<int8_t>(), varOperand2.Get<int8_t>()); break;
|
||||
case ETypeMapping::type_int16_t: return tOperation(varOperand1.Get<int16_t>(), varOperand2.Get<int16_t>()); break;
|
||||
case ETypeMapping::type_int32_t: return tOperation(varOperand1.Get<int32_t>(), varOperand2.Get<int32_t>()); break;
|
||||
case ETypeMapping::type_int64_t: return tOperation(varOperand1.Get<int64_t>(), varOperand2.Get<int64_t>()); break;
|
||||
case ETypeMapping::type_fixed: return tOperation(varOperand1.Get<fixed>(), varOperand2.Get<fixed>()); break;
|
||||
case ETypeMapping::type_float: return tOperation(varOperand1.Get<float>(), varOperand2.Get<float>()); break;
|
||||
case ETypeMapping::type_double: return tOperation(varOperand1.Get<double>(), varOperand2.Get<double>()); break;
|
||||
case ETypeMapping::type_long_double: return tOperation(varOperand1.Get<long double>(), varOperand2.Get<long double>()); break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFunction>
|
||||
inline CConstVariant CConstVariant::BinaryOperationIntegral(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2,
|
||||
TFunction tOperation)
|
||||
{
|
||||
// Equalize the operands
|
||||
CConstVariant varOperand1 = rvarOperand1;
|
||||
CConstVariant varOperand2 = rvarOperand2;
|
||||
Equalize(varOperand1, varOperand2);
|
||||
|
||||
// Based on the operand type, execute the provided function
|
||||
switch (static_cast<ETypeMapping>(varOperand1.Ranking()))
|
||||
{
|
||||
case ETypeMapping::type_uint8_t: return tOperation(varOperand1.Get<uint8_t>(), varOperand2.Get<uint8_t>()); break;
|
||||
case ETypeMapping::type_uint16_t: return tOperation(varOperand1.Get<uint16_t>(), varOperand2.Get<uint16_t>()); break;
|
||||
case ETypeMapping::type_uint32_t: return tOperation(varOperand1.Get<uint32_t>(), varOperand2.Get<uint32_t>()); break;
|
||||
case ETypeMapping::type_uint64_t: return tOperation(varOperand1.Get<uint64_t>(), varOperand2.Get<uint64_t>()); break;
|
||||
case ETypeMapping::type_int8_t: return tOperation(varOperand1.Get<int8_t>(), varOperand2.Get<int8_t>()); break;
|
||||
case ETypeMapping::type_int16_t: return tOperation(varOperand1.Get<int16_t>(), varOperand2.Get<int16_t>()); break;
|
||||
case ETypeMapping::type_int32_t: return tOperation(varOperand1.Get<int32_t>(), varOperand2.Get<int32_t>()); break;
|
||||
case ETypeMapping::type_int64_t: return tOperation(varOperand1.Get<int64_t>(), varOperand2.Get<int64_t>()); break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incompatible data type conversion.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TTargetType, typename TVariantType>
|
||||
inline TTargetType CConstVariant::InternalGet() const
|
||||
{
|
||||
if constexpr (std::is_same_v<TTargetType, TVariantType>)
|
||||
return std::get<TVariantType>(m_varValue);
|
||||
else if constexpr (std::is_floating_point_v<TTargetType> && std::is_arithmetic_v<TVariantType>)
|
||||
{
|
||||
TVariantType tValue = std::get<TVariantType>(m_varValue);
|
||||
if (static_cast<long double>(tValue) > static_cast<long double>(std::numeric_limits<TTargetType>::max()))
|
||||
throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type.");
|
||||
if (static_cast<long double>(tValue) < static_cast<long double>(std::numeric_limits<TTargetType>::lowest()))
|
||||
throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type.");
|
||||
if constexpr (std::is_floating_point_v<TVariantType>)
|
||||
{
|
||||
int iExpValue = 0, iExpMin = 0;
|
||||
long double ldDigitsValue = std::fabs(std::frexp(static_cast<long double>(tValue), &iExpValue));
|
||||
long double ldDigitsMin = std::frexp(static_cast<long double>(std::numeric_limits<TTargetType>::min()), &iExpMin);
|
||||
if ((iExpValue < iExpMin) || ((iExpValue == iExpMin) && ldDigitsValue < ldDigitsMin))
|
||||
throw CCompileException("Cannot cast to type, the value precision is below the smallest possible"
|
||||
" precision of the target type.");
|
||||
}
|
||||
return static_cast<TTargetType>(tValue);
|
||||
}
|
||||
else if constexpr (std::is_integral_v<TTargetType> && std::is_integral_v<TVariantType> && !std::is_same_v<TTargetType, bool>)
|
||||
{
|
||||
if constexpr (std::is_signed_v<TTargetType> && std::is_signed_v<TVariantType>)
|
||||
{
|
||||
TVariantType tValue = std::get<TVariantType>(m_varValue);
|
||||
if (static_cast<int64_t>(tValue) > static_cast<int64_t>(std::numeric_limits<TTargetType>::max()))
|
||||
throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type.");
|
||||
if (static_cast<int64_t>(tValue) < static_cast<int64_t>(std::numeric_limits<TTargetType>::min()))
|
||||
throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type.");
|
||||
return static_cast<TTargetType>(tValue);
|
||||
}
|
||||
if constexpr (std::is_unsigned_v<TTargetType> && std::is_unsigned_v<TVariantType>)
|
||||
{
|
||||
TVariantType tValue = std::get<TVariantType>(m_varValue);
|
||||
if (static_cast<uint64_t>(tValue) > static_cast<uint64_t>(std::numeric_limits<TTargetType>::max()))
|
||||
throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type.");
|
||||
if (static_cast<uint64_t>(tValue) < static_cast<uint64_t>(std::numeric_limits<TTargetType>::min()))
|
||||
throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type.");
|
||||
return static_cast<TTargetType>(tValue);
|
||||
}
|
||||
if constexpr (std::is_signed_v<TTargetType> && std::is_unsigned_v<TVariantType>)
|
||||
{
|
||||
TVariantType tValue = std::get<TVariantType>(m_varValue);
|
||||
if (static_cast<uint64_t>(tValue) > static_cast<uint64_t>(std::numeric_limits<TTargetType>::max()))
|
||||
throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type.");
|
||||
return static_cast<TTargetType>(tValue);
|
||||
}
|
||||
if constexpr (std::is_unsigned_v<TTargetType> && std::is_signed_v<TVariantType>)
|
||||
{
|
||||
TVariantType tValue = std::get<TVariantType>(m_varValue);
|
||||
if (tValue > 0 && static_cast<uint64_t>(tValue) > static_cast<uint64_t>(std::numeric_limits<TTargetType>::max()))
|
||||
throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type.");
|
||||
else if (tValue < 0 && static_cast<int64_t>(tValue) <
|
||||
static_cast<int64_t>(std::numeric_limits<std::make_signed_t<TTargetType>>::min()))
|
||||
throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the signed version"
|
||||
" of the target type.");
|
||||
return static_cast<TTargetType>(tValue);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<TTargetType, bool> && std::is_arithmetic_v<TVariantType>)
|
||||
return std::get<TVariantType>(m_varValue) != static_cast<TVariantType>(0) ? true : false;
|
||||
else
|
||||
{
|
||||
// Conversion not possible
|
||||
throw CCompileException("Cannot cast to target type, the types are incompatible.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined(CONSTVARIANT_INL)
|
||||
1458
sdv_executables/sdv_idl_compiler/core_idl_backup.h
Normal file
1458
sdv_executables/sdv_idl_compiler/core_idl_backup.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
#include "attribute_entity.h"
|
||||
|
||||
CAttributeEntity::CAttributeEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bReadOnly) :
|
||||
CDeclarationEntity(rptrContext, ptrParent), m_bReadOnly(bReadOnly),
|
||||
m_iteratorReadExceptions(GetReadExceptionVector()), m_iteratorWriteExceptions(GetWriteExceptionVector())
|
||||
{}
|
||||
|
||||
sdv::interface_t CAttributeEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
// Expose interfaces
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IAttributeEntity>())
|
||||
return static_cast<sdv::idl::IAttributeEntity*>(this);
|
||||
return CDeclarationEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* CAttributeEntity::GetReadExceptions()
|
||||
{
|
||||
if (!GetReadExceptionVector().empty()) return &m_iteratorReadExceptions;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* CAttributeEntity::GetWriteExceptions()
|
||||
{
|
||||
if (!GetWriteExceptionVector().empty()) return &m_iteratorWriteExceptions;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CAttributeEntity::Process()
|
||||
{
|
||||
CDeclarationEntity::Process();
|
||||
}
|
||||
|
||||
bool CAttributeEntity::SupportArrays() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAttributeEntity::IsReadOnly() const
|
||||
{
|
||||
return m_bReadOnly;
|
||||
}
|
||||
|
||||
bool CAttributeEntity::SupportMultipleDeclarations() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAttributeEntity::SupportRaiseExceptions() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAttributeEntity::SupportSeparateSetGetRaiseExceptions() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
99
sdv_executables/sdv_idl_compiler/entities/attribute_entity.h
Normal file
99
sdv_executables/sdv_idl_compiler/entities/attribute_entity.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef ATTRIBUTE_ENTITY_H
|
||||
#define ATTRIBUTE_ENTITY_H
|
||||
|
||||
#include "declaration_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The attribute definition of an IDL file.
|
||||
* @details The attribute section of the IDL file defines attribute values.
|
||||
*/
|
||||
class CAttributeEntity : public CDeclarationEntity, public sdv::idl::IAttributeEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] bReadOnly When set, the attribute is defined as readonly.
|
||||
*/
|
||||
CAttributeEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bReadOnly);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CAttributeEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the list of possible exceptions that might be fired during a read operation. Overload of
|
||||
* sdv::idl::IAttributeEntity::GetReadExceptions.
|
||||
* @return Returns a pointer to the exceptions iterator or NULL when no exceptions were defined.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetReadExceptions() override;
|
||||
|
||||
/**
|
||||
* @brief Get the list of possible exceptions that might be fired during a write operation. Overload of
|
||||
* sdv::idl::IAttributeEntity::GetWriteExceptions.
|
||||
* @return Returns a pointer to the exceptions iterator or NULL when no exceptions were defined.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetWriteExceptions() override;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the attribute entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_attribute; }
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const override;
|
||||
|
||||
/**
|
||||
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support multiple declarations on one line of code? Overload of
|
||||
* CDeclarationEntity::SupportMultipleDeclarations.
|
||||
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportMultipleDeclarations() const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support raising exceptions? Overload of CDeclarationEntity::SupportRaiseExceptions.
|
||||
* @return Returns 'true' when the entity supports exceptions; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportRaiseExceptions() const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support separate set/get raising exceptions? Overload of
|
||||
* CDeclarationEntity::SupportSeparateSetGetRaiseExceptions.
|
||||
* @return Returns 'true' when the entity supports separate set/get raise exceptions; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportSeparateSetGetRaiseExceptions() const override;
|
||||
|
||||
private:
|
||||
bool m_bReadOnly = false; ///< When set, the attribute is readonly.
|
||||
CEntityIterator m_iteratorReadExceptions; ///< Exceptions iterator for read exceptions
|
||||
CEntityIterator m_iteratorWriteExceptions; ///< Exceptions iterator for write exceptions
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // !defined(ATTRIBUTE_ENTITY_H)
|
||||
749
sdv_executables/sdv_idl_compiler/entities/declaration_entity.cpp
Normal file
749
sdv_executables/sdv_idl_compiler/entities/declaration_entity.cpp
Normal file
@@ -0,0 +1,749 @@
|
||||
#include "declaration_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "../token.h"
|
||||
#include "../tokenlist.h"
|
||||
#include "../support.h"
|
||||
#include "../lexer.h"
|
||||
#include "../constvariant.inl"
|
||||
#include "../parser.h"
|
||||
#include "struct_entity.h"
|
||||
#include "interface_entity.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include "attribute_entity.h"
|
||||
#include "operation_entity.h"
|
||||
#include "exception_entity.h"
|
||||
#include "parameter_entity.h"
|
||||
#include "enum_entity.h"
|
||||
#include "union_entity.h"
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
CDeclarationEntity::CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
CDeclarationEntity::CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
|
||||
const CTokenList& rlstTokenList) :
|
||||
CEntity(rptrContext, ptrParent, rlstTokenList)
|
||||
{}
|
||||
|
||||
sdv::interface_t CDeclarationEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IDeclarationEntity>())
|
||||
return static_cast<sdv::idl::IDeclarationEntity*>(this);
|
||||
return CEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::IInterfaceAccess* CDeclarationEntity::GetDeclarationType() const
|
||||
{
|
||||
return const_cast<CTypeDeclaration*>(&m_typedecl);
|
||||
}
|
||||
|
||||
CEntityPtr CDeclarationEntity::GetTypeEntity() const
|
||||
{
|
||||
return m_typedecl.GetTypeDefinitionEntityPtr();
|
||||
}
|
||||
|
||||
bool CDeclarationEntity::HasArray() const
|
||||
{
|
||||
return m_vecMultiArraySizeTokenList.size() ? true : false;
|
||||
}
|
||||
|
||||
sdv::sequence<sdv::idl::SArrayDimension> CDeclarationEntity::GetArrayDimensions() const
|
||||
{
|
||||
sdv::sequence<sdv::idl::SArrayDimension> seqArrayDimensions;
|
||||
if (!HasArray()) return seqArrayDimensions;
|
||||
|
||||
// Traverse through each array entry
|
||||
std::function<void(const CValueNodePtr& ptrValue)> fnCollectArrayDimensions =
|
||||
[&](const CValueNodePtr& ptrValue)
|
||||
{
|
||||
// Is the value node an array at all?
|
||||
CArrayValueNode* pArrayValue = ptrValue->Get<CArrayValueNode>();
|
||||
if (!pArrayValue) return;
|
||||
|
||||
// Fill the array dimension struct
|
||||
sdv::idl::SArrayDimension sArrayDimension{};
|
||||
sArrayDimension.eType = sdv::idl::SArrayDimension::EDimensionType::bound;
|
||||
if (pArrayValue->IsUnbound())
|
||||
sArrayDimension.eType = sdv::idl::SArrayDimension::EDimensionType::unbound;
|
||||
sArrayDimension.ssExpression = MakeFullScoped(pArrayValue->GetSizeExpression());
|
||||
|
||||
// Store in sequence
|
||||
seqArrayDimensions.push_back(sArrayDimension);
|
||||
|
||||
// Process the next array dimension
|
||||
if (pArrayValue->GetSize() != 0)
|
||||
fnCollectArrayDimensions((*pArrayValue)[0]);
|
||||
};
|
||||
|
||||
// Collect the array dimensions.
|
||||
fnCollectArrayDimensions(ValueRef());
|
||||
|
||||
return seqArrayDimensions;
|
||||
}
|
||||
|
||||
bool CDeclarationEntity::HasAssignment() const
|
||||
{
|
||||
return !m_lstAssignmentTokenList.empty();
|
||||
}
|
||||
|
||||
sdv::u8string CDeclarationEntity::GetAssignment() const
|
||||
{
|
||||
std::stringstream sstreamAssignment;
|
||||
bool bInitial = true;
|
||||
for (const CToken& rToken : m_lstAssignmentTokenList)
|
||||
{
|
||||
if (!bInitial) sstreamAssignment << " ";
|
||||
bInitial = false;
|
||||
sstreamAssignment << static_cast<std::string>(rToken);
|
||||
}
|
||||
return sstreamAssignment.str();
|
||||
}
|
||||
|
||||
void CDeclarationEntity::Process()
|
||||
{
|
||||
CLog log("Processing declaration (preparation)...");
|
||||
|
||||
// Determine whether the comments are preceding the token (either on the same line or the line before).
|
||||
CTokenList lstPreComments = GetPreCommentTokenList();
|
||||
if (!lstPreComments.empty()) SetCommentTokens(lstPreComments);
|
||||
|
||||
// Process the type
|
||||
CTypeDeclaration sTypeDecl = ProcessType();
|
||||
|
||||
// Check for the support of interface and void types
|
||||
if (sTypeDecl.GetBaseType() == sdv::idl::EDeclType::decltype_interface && !SupportInterface())
|
||||
throw CCompileException("The declaration of interfaces is not supported.");
|
||||
if (sTypeDecl.GetBaseType() == sdv::idl::EDeclType::decltype_void && !SupportVoid())
|
||||
throw CCompileException("The use of 'void' as type is not supported.");
|
||||
|
||||
// Preprocess potential array declaration (only for operations).
|
||||
if (GetType() == sdv::idl::EEntityType::type_operation)
|
||||
PreprocessArrayDeclaration();
|
||||
|
||||
// Process the declaration
|
||||
ProcessDeclaration(sTypeDecl);
|
||||
}
|
||||
|
||||
void CDeclarationEntity::ProcessDeclaration(const CTypeDeclaration& rTypeDecl)
|
||||
{
|
||||
// Store the type
|
||||
m_typedecl = rTypeDecl;
|
||||
|
||||
CLog log("Processing declaration...");
|
||||
|
||||
// Expecting an identifier.
|
||||
CToken token = GetToken();
|
||||
if (token.GetType() == ETokenType::token_keyword)
|
||||
{
|
||||
// Keywords as names are allowed if the extension is enabled.
|
||||
if (!GetParserRef().GetEnvironment().ContextDependentNamesExtension())
|
||||
throw CCompileException(token, "The identifier cannot be a reserved keyword.");
|
||||
}
|
||||
else if (token.GetType() != ETokenType::token_identifier)
|
||||
throw CCompileException(token, "Expecting an identifier.");
|
||||
SetName(token);
|
||||
log << "Declaration name '" << GetName() << "'..." << std::endl;
|
||||
|
||||
// Preprocess potential array declaration (not for operations).
|
||||
if (GetType() != sdv::idl::EEntityType::type_operation)
|
||||
PreprocessArrayDeclaration();
|
||||
|
||||
// Further processing...
|
||||
token = GetToken();
|
||||
|
||||
// Requires parameters?
|
||||
if (RequiresParameters())
|
||||
{
|
||||
// Expect a left bracket
|
||||
if (token != "(") throw CCompileException(token, "Expected left bracket '('.");
|
||||
|
||||
log << "Reading parameter list..." << std::endl;
|
||||
PreprocessTokenListVector(m_vecParametersTokenList);
|
||||
|
||||
// Expect a right bracket
|
||||
token = GetToken();
|
||||
if (token != ")")
|
||||
throw CCompileException(token, "Expected right bracket ')'.");
|
||||
|
||||
// Get the next token...
|
||||
token = GetToken();
|
||||
|
||||
// Check for the 'const' keyword. If set, the operation is defined as const-operation.
|
||||
if (token == "const")
|
||||
{
|
||||
SetOperationAsConst();
|
||||
token = GetToken();
|
||||
}
|
||||
}
|
||||
|
||||
// Supports exceptions
|
||||
if (SupportRaiseExceptions())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Check for the 'raises' keyword.
|
||||
enum class EExceptType {raises, getraises, setraises, none} eExceptType = EExceptType::none;
|
||||
if (token == "raises")
|
||||
eExceptType = EExceptType::raises;
|
||||
else if (token == "getraises")
|
||||
eExceptType = EExceptType::getraises;
|
||||
else if (token == "setraises")
|
||||
eExceptType = EExceptType::setraises;
|
||||
if (eExceptType == EExceptType::none)
|
||||
break;
|
||||
|
||||
// Check for validity
|
||||
if (!SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::getraises)
|
||||
throw CCompileException(token,
|
||||
"Cannot set a separate 'get-raises' exception list; use the 'raises' keyword instead.");
|
||||
if (!SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::setraises)
|
||||
throw CCompileException(token,
|
||||
"Cannot set a separate 'set-raises' exception list; use the 'raises' keyword instead.");
|
||||
if (SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::raises && IsReadOnly())
|
||||
eExceptType = EExceptType::getraises;
|
||||
if (eExceptType == EExceptType::setraises && IsReadOnly())
|
||||
throw CCompileException(token, "Cannot set a set-raises exception list for a readonly type.");
|
||||
if ((eExceptType == EExceptType::raises) && !m_vecRaisesExceptionsTokenList.empty())
|
||||
throw CCompileException(token, "Multiple definitions of 'raises' exceptions are not allowed.");
|
||||
if ((eExceptType == EExceptType::setraises) && !m_vecSetRaisesExceptionsTokenList.empty())
|
||||
throw CCompileException(token, "Multiple definitions of 'set-raises' exceptions are not allowed.");
|
||||
if ((eExceptType == EExceptType::getraises) && !m_vecGetRaisesExceptionsTokenList.empty())
|
||||
throw CCompileException(token, "Multiple definitions of 'get-raises' exceptions are not allowed.");
|
||||
|
||||
// Expect a left bracket
|
||||
token = GetToken();
|
||||
if (token != "(") throw CCompileException(token, "Expected left bracket '('.");
|
||||
|
||||
// Processes raises exception list.
|
||||
switch (eExceptType)
|
||||
{
|
||||
case EExceptType::raises:
|
||||
log << "Reading 'raises' exception list..." << std::endl;
|
||||
PreprocessTokenListVector(m_vecRaisesExceptionsTokenList);
|
||||
if (m_vecRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
|
||||
break;
|
||||
case EExceptType::setraises:
|
||||
log << "Reading 'setraises' exception list..." << std::endl;
|
||||
PreprocessTokenListVector(m_vecSetRaisesExceptionsTokenList);
|
||||
if (m_vecSetRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
|
||||
break;
|
||||
case EExceptType::getraises:
|
||||
log << "Reading 'getraises' exception list..." << std::endl;
|
||||
PreprocessTokenListVector(m_vecGetRaisesExceptionsTokenList);
|
||||
if (m_vecGetRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Expect a right bracket
|
||||
token = GetToken();
|
||||
if (token != ")")
|
||||
throw CCompileException(token, "Expected right bracket ')'.");
|
||||
|
||||
// Get the next token...
|
||||
token = GetToken();
|
||||
}
|
||||
}
|
||||
|
||||
// Is there an assignment?
|
||||
if (token == "=")
|
||||
{
|
||||
if (!SupportAssignments())
|
||||
throw CCompileException(token, "Assignment operator detected, but type doesn't support assignments.");
|
||||
log << "Declaration assignment detected; storing expression for later processing..." << std::endl;
|
||||
|
||||
// Read the tokens for the assignment expression. Read until ';' or ','; the latter not within an expression
|
||||
// sub-statement.
|
||||
size_t nDepth = 0;
|
||||
log << "Assignment expression:" << std::endl;
|
||||
while(true)
|
||||
{
|
||||
token = GetToken();
|
||||
if (!token)
|
||||
throw CCompileException("Unexpected end of file found; missing ';'.");
|
||||
if (token == ";" || ((token == "," || token == "}") && !nDepth))
|
||||
break;
|
||||
|
||||
log << " " << static_cast<std::string>(token);
|
||||
|
||||
if (token == "{") nDepth++;
|
||||
if (token == "}") nDepth--;
|
||||
m_lstAssignmentTokenList.push_back(token);
|
||||
}
|
||||
log << std::endl;
|
||||
} else
|
||||
{
|
||||
// Does the entity need an assignment?
|
||||
if (RequiresAssignment())
|
||||
throw CCompileException(token, "Expecting an assignment operator.");
|
||||
}
|
||||
|
||||
// Assign any succeeding comments
|
||||
ProcessPostCommentTokenList(token.GetLine());
|
||||
|
||||
// Another declaration?
|
||||
if (token == ",")
|
||||
{
|
||||
if (!SupportMultipleDeclarations())
|
||||
throw CCompileException(token, "Multiple declarations on a single line of code is not supported for this type.");
|
||||
log << "Another declaration of the same type..." << std::endl;
|
||||
|
||||
// Peek for ending the definition
|
||||
if (DoNotEnfoceNextDeclarationAfterComma() && PeekToken() == "}") return;
|
||||
|
||||
// Create another declaration
|
||||
CDeclarationEntity* pTypeEntity = nullptr;
|
||||
if (Get<CVariableEntity>()) pTypeEntity = CreateChild<CVariableEntity>(token.GetContext(), GetParentEntity().get(), IsReadOnly(), false)->Get<CDeclarationEntity>();
|
||||
else if (Get<CEnumEntry>()) pTypeEntity = CreateChild<CEnumEntry>(token.GetContext(), GetParentEntity().get())->Get<CDeclarationEntity>();
|
||||
else if (Get<CAttributeEntity>()) pTypeEntity = CreateChild<CAttributeEntity>(token.GetContext(), GetParentEntity().get(), IsReadOnly())->Get<CDeclarationEntity>();
|
||||
else
|
||||
throw CCompileException(token, "Unexpected token ','.");
|
||||
if (!pTypeEntity) throw CCompileException(token, "Internal error: failed to create another declaration entity.");
|
||||
|
||||
// Set the new begin position of the declaration
|
||||
CToken tokenTemp = PeekToken();
|
||||
pTypeEntity->SetBeginPosition(tokenTemp.GetLine(), tokenTemp.GetCol());
|
||||
|
||||
// Use the same type for the processing.
|
||||
pTypeEntity->ProcessDeclaration(m_typedecl);
|
||||
|
||||
// Done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the end position of the declaration
|
||||
SetEndPosition(token.GetLine(), token.GetCol());
|
||||
|
||||
// Reinsert the token
|
||||
PrependToken(token);
|
||||
}
|
||||
|
||||
void CDeclarationEntity::PreprocessArrayDeclaration()
|
||||
{
|
||||
CLog log("Checking for array...");
|
||||
|
||||
// For each array dimension, add a tokenlist to the m_vecMultiArraySizeTokenList variable.
|
||||
bool bIsArray = false;
|
||||
while (true)
|
||||
{
|
||||
// Check for an array
|
||||
CToken token = GetToken();
|
||||
if (token != "[")
|
||||
{
|
||||
PrependToken(token);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!SupportArrays())
|
||||
throw CCompileException(token, "Unexpected token '['.");
|
||||
|
||||
log << "Array detected; storing expression for later processing..." << std::endl;
|
||||
log << "Array expression: [";
|
||||
|
||||
// Check for multidimensional arrays
|
||||
if (bIsArray && !GetParserRef().GetEnvironment().MultiDimArrayExtension())
|
||||
throw CCompileException(token, "Multi-dimentsional arrays are not allowed. Unexpected token '['.");
|
||||
bIsArray = true;
|
||||
|
||||
// Read the tokens for the array size. Read until ']'.
|
||||
CTokenList lstArraySize;
|
||||
size_t nDepth = 1;
|
||||
while (true)
|
||||
{
|
||||
token = GetToken();
|
||||
log << " " << static_cast<std::string>(token);
|
||||
if (!token)
|
||||
throw CCompileException("Unexpected end of file found; missing ']'.");
|
||||
if (token == ";")
|
||||
throw CCompileException("Unexpected end of declaration; missing ']'.");
|
||||
if (token == "[")
|
||||
nDepth++;
|
||||
if (token == "]")
|
||||
{
|
||||
nDepth--;
|
||||
if (!nDepth)
|
||||
{
|
||||
m_vecMultiArraySizeTokenList.push_back(std::move(lstArraySize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lstArraySize.push_back(token);
|
||||
}
|
||||
log << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CDeclarationEntity::PreprocessTokenListVector(std::vector<CTokenList>& rvecTokenList)
|
||||
{
|
||||
CLog log("Checking for comma separated token lists...");
|
||||
|
||||
CTokenList lstTokens;
|
||||
bool bInitial = true;
|
||||
while (true)
|
||||
{
|
||||
// Check for array index (allowed in certain situations)
|
||||
CToken token = GetToken();
|
||||
if (token == "[")
|
||||
{
|
||||
do
|
||||
{
|
||||
lstTokens.push_back(token);
|
||||
token = GetToken();
|
||||
} while (token && token != "]");
|
||||
lstTokens.push_back(token);
|
||||
token = GetToken();
|
||||
}
|
||||
|
||||
// Check for template parameters
|
||||
if (token == "<")
|
||||
{
|
||||
size_t nDepth = 0;
|
||||
do
|
||||
{
|
||||
if (token == "<") nDepth++;
|
||||
if (token == ">>") // Special case when closing nested templates.
|
||||
{
|
||||
token = CToken(">", ETokenType::token_operator);
|
||||
PrependToken(token);
|
||||
}
|
||||
if (token == ">") nDepth--;
|
||||
lstTokens.push_back(token);
|
||||
token = GetToken();
|
||||
} while (token && static_cast<bool>(nDepth));
|
||||
lstTokens.push_back(token);
|
||||
token = GetToken();
|
||||
}
|
||||
|
||||
// Check for end of processing
|
||||
if (!token || token == "]" || token == ")" || token == ";")
|
||||
{
|
||||
if (!bInitial)
|
||||
rvecTokenList.push_back(std::move(lstTokens));
|
||||
PrependToken(token);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bInitial)
|
||||
log << "Comma separated list detected: ";
|
||||
bInitial = false;
|
||||
|
||||
log << " " << static_cast<std::string>(token);
|
||||
|
||||
// Check for comma separator
|
||||
if (token == ",")
|
||||
{
|
||||
rvecTokenList.push_back(std::move(lstTokens));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the token to the token list
|
||||
lstTokens.push_back(token);
|
||||
}
|
||||
if (rvecTokenList.empty())
|
||||
log << "No comma separated list detected..." << std::endl;
|
||||
else
|
||||
log << std::endl;
|
||||
}
|
||||
|
||||
void CDeclarationEntity::PostProcess()
|
||||
{
|
||||
CLog log("Post process declaration...");
|
||||
|
||||
// Check the assignment processing progression state...
|
||||
switch (m_eProcAssState)
|
||||
{
|
||||
case EProcessAssignmentProgression::unprocessed:
|
||||
// Not processed yet, start processing...
|
||||
m_eProcAssState = EProcessAssignmentProgression::currently_processing;
|
||||
break;
|
||||
case EProcessAssignmentProgression::currently_processing:
|
||||
log << "Post processing declaration assignment takes place already; cannot do this more than once at the same time..."
|
||||
<< std::endl;
|
||||
// Alarm, circular references... cannot continue.
|
||||
throw CCompileException("Circular referencing entity.");
|
||||
case EProcessAssignmentProgression::processed:
|
||||
default:
|
||||
// Already done...
|
||||
log << "Post processing declaration was done before; no need to repeat..." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// The parent value is the value of the parent entity, if there is any value.
|
||||
CValueNodePtr ptrValueParent = GetParentEntity() ? GetParentEntity()->ValueRef() : nullptr;
|
||||
if (ptrValueParent)
|
||||
log << "The parent entity '" << GetParentEntity()->GetName() << "' has a value node..." << std::endl;
|
||||
else
|
||||
log << "No parent entity or no value node assigned to the parent entity..." << std::endl;
|
||||
|
||||
// Create a value at each bottom leaf of a multi-dimensional array.
|
||||
std::function<void(CValueNodePtr&, const CValueNodePtr, std::function<CValueNodePtr(const CValueNodePtr)>)> fnCreateAtBottomLeaf =
|
||||
[&](CValueNodePtr& rptrValue, const CValueNodePtr& rptrValueParent, std::function<CValueNodePtr(const CValueNodePtr)> fnCreate)
|
||||
{
|
||||
// Check for an array value
|
||||
CArrayValueNode* psArrayValue = dynamic_cast<CArrayValueNode*>(rptrValue.get());
|
||||
|
||||
// If there is an array value, call the function once more for each leaf.
|
||||
if (psArrayValue)
|
||||
{
|
||||
for (size_t nIndex = 0; nIndex < psArrayValue->GetSize(); nIndex++)
|
||||
fnCreateAtBottomLeaf((*psArrayValue)[nIndex], rptrValue, fnCreate);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new element...
|
||||
rptrValue = fnCreate(rptrValueParent);
|
||||
};
|
||||
|
||||
// Process parameters - since parameters might depend on other parameters, do the processing in two steps.
|
||||
size_t nIndex = 1;
|
||||
for (const CTokenList& rlstTokenList : m_vecParametersTokenList)
|
||||
{
|
||||
log << "Processing parameter #" << nIndex++ << std::endl;
|
||||
|
||||
CEntityPtr ptrEntity = std::make_shared<CParameterEntity>(GetContext(), shared_from_this(), rlstTokenList);
|
||||
ptrEntity->Process();
|
||||
|
||||
m_vecParameters.push_back(ptrEntity);
|
||||
}
|
||||
for (CEntityPtr& rptrParameter : m_vecParameters)
|
||||
rptrParameter->Get<CParameterEntity>()->PostProcess();
|
||||
|
||||
// Build array tree
|
||||
if (m_vecMultiArraySizeTokenList.empty()) log << "No array processing needed..." << std::endl;
|
||||
else if (m_vecMultiArraySizeTokenList.size() == 1) log << "Single-dimensional array processing needed..." << std::endl;
|
||||
else log << "Multi-dimensional array processing needed..." << std::endl;
|
||||
for (const CTokenList& rlstArrayExpression : m_vecMultiArraySizeTokenList)
|
||||
{
|
||||
std::pair<CConstVariant, bool> prArraySize = {0, false};
|
||||
log << "Start processing array dimension..." << std::endl;
|
||||
|
||||
// Empty expression indicates retrieving the size from the assignment.
|
||||
if (!rlstArrayExpression.empty())
|
||||
{
|
||||
log << "Calculate the array size..." << std::endl;
|
||||
prArraySize = ProcessNumericExpression(rlstArrayExpression);
|
||||
|
||||
// Is the array size dynamic?
|
||||
if (prArraySize.second)
|
||||
throw CCompileException(*rlstArrayExpression.begin(), "Cannot use non-const variable for the array size.");
|
||||
log << "The array has " << prArraySize.first.Get<uint32_t>() << " elements..." << std::endl;
|
||||
|
||||
// Check whether the size is integral
|
||||
if (!prArraySize.first.IsIntegral())
|
||||
throw CCompileException(*rlstArrayExpression.begin(), "Only integral data types are supported for the array size.");
|
||||
if ((prArraySize.first < CConstVariant(0)).Get<bool>())
|
||||
throw CCompileException(*rlstArrayExpression.begin(), "Invalid array size.");
|
||||
} else
|
||||
{
|
||||
log << "Array is defined as unbound array retrieving the size from the variable assignment..." << std::endl;
|
||||
|
||||
// Unbound arrays are not possible for writable variables. Exception are operations, attributes and parameters of local
|
||||
// interfaces.
|
||||
bool bError = true;
|
||||
switch (GetType())
|
||||
{
|
||||
case sdv::idl::EEntityType::type_typedef:
|
||||
bError = false;
|
||||
break;
|
||||
case sdv::idl::EEntityType::type_variable:
|
||||
// When not read-only, this is an error.
|
||||
if (IsReadOnly()) bError = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bError)
|
||||
throw CCompileException("Retrieving the size of the array through its assignment is"
|
||||
" only possible with const declarations and typedefs.");
|
||||
}
|
||||
// The array creation function
|
||||
auto fnCreateArray = [&, this](const CValueNodePtr& rptrValueParent) -> CValueNodePtr
|
||||
{
|
||||
std::shared_ptr<CArrayValueNode> ptrArrayValue = std::make_shared<CArrayValueNode>(shared_from_this(), rptrValueParent);
|
||||
if (rlstArrayExpression.empty())
|
||||
ptrArrayValue->SetFixedSizeUnbound();
|
||||
else if (prArraySize.second)
|
||||
ptrArrayValue->SetDynamicSize(prArraySize.first.Get<size_t>(), rlstArrayExpression);
|
||||
else
|
||||
ptrArrayValue->SetFixedSize(prArraySize.first.Get<size_t>(), rlstArrayExpression);
|
||||
return ptrArrayValue;
|
||||
};
|
||||
|
||||
// Create the array value at the bottom leaf.
|
||||
fnCreateAtBottomLeaf(ValueRef(), ptrValueParent, fnCreateArray);
|
||||
|
||||
log << "Finalized processing array dimension..." << std::endl;
|
||||
}
|
||||
|
||||
// Add the values of the type.
|
||||
if (m_vecMultiArraySizeTokenList.size() == 0)
|
||||
log << "Copy the existing type value tree or create a declaration value node for this assignment..." << std::endl;
|
||||
else
|
||||
log << "For each array element, copy the existing type value tree or create a"
|
||||
" declaration value node for this assignment..." << std::endl;
|
||||
auto fnCreateTypeValues = [&, this](const CValueNodePtr& rptrValueParent) -> CValueNodePtr
|
||||
{
|
||||
if (m_typedecl.GetTypeDefinitionEntityPtr())
|
||||
{
|
||||
// In case the original type was not processed yet, do so now.
|
||||
CDeclarationEntity* pOriginalType = m_typedecl.GetTypeDefinitionEntityPtr()->Get<CDeclarationEntity>();
|
||||
if (pOriginalType) pOriginalType->PostProcess();
|
||||
|
||||
// Copy the existing entity of the type... this contains all the default assignments already...
|
||||
log << "Copy type value tree..." << std::endl;
|
||||
CValueNodePtr ptrValue = m_typedecl.GetTypeDefinitionEntityPtr()->ValueRef();
|
||||
if (ptrValue)
|
||||
return ptrValue->CreateCopy(shared_from_this(), rptrValueParent);
|
||||
else
|
||||
{
|
||||
if (pOriginalType)
|
||||
throw CCompileException("Internal error: value tree must be available for '", GetName(), "'.");
|
||||
log << "No value tree present; nothing to copy..." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log << "Create declaration value node..." << std::endl;
|
||||
return std::make_shared<CSimpleTypeValueNode>(shared_from_this(), ptrValueParent);
|
||||
}
|
||||
};
|
||||
fnCreateAtBottomLeaf(ValueRef(), ptrValueParent, fnCreateTypeValues);
|
||||
|
||||
// If this is a variable declaration, add the value as part of the parent tree
|
||||
if (CanSupportComplexTypeAssignments() && ptrValueParent)
|
||||
{
|
||||
log << "The entity value tree is part of the value tree of the parent node..." << std::endl;
|
||||
ptrValueParent->AddChild(ValueRef());
|
||||
}
|
||||
|
||||
// Add the assignment.
|
||||
if (!m_lstAssignmentTokenList.empty())
|
||||
{
|
||||
log << "Assignment was available, process the assignment..." << std::endl;
|
||||
if (!SupportAssignments())
|
||||
throw CCompileException(*m_lstAssignmentTokenList.begin(), "Type definitions cannot be assigned any values.");
|
||||
ValueRef()->ProcessValueAssignment(m_lstAssignmentTokenList);
|
||||
} else
|
||||
{
|
||||
// Does the entity need an assignment?
|
||||
if (RequiresAssignment())
|
||||
throw CCompileException("Expecting an assignment operator for '", GetName(), "'.");
|
||||
}
|
||||
|
||||
// Build raises exception lists
|
||||
for (const CTokenList& rlstTokenList : m_vecRaisesExceptionsTokenList)
|
||||
{
|
||||
log << "Processing raising exception..." << std::endl;
|
||||
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
|
||||
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
|
||||
throw CCompileException("Exception definition not found.");
|
||||
if (SupportSeparateSetGetRaiseExceptions())
|
||||
{
|
||||
m_vecGetRaisesExceptions.push_back(prBase.second);
|
||||
m_vecSetRaisesExceptions.push_back(prBase.second);
|
||||
} else
|
||||
m_vecRaisesExceptions.push_back(prBase.second);
|
||||
log << "Entity could raise exception on operation/attribute: " << prBase.first << std::endl;
|
||||
}
|
||||
for (const CTokenList& rlstTokenList : m_vecSetRaisesExceptionsTokenList)
|
||||
{
|
||||
log << "Processing set-raising exception..." << std::endl;
|
||||
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
|
||||
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
|
||||
throw CCompileException("Exception definition not found.");
|
||||
m_vecSetRaisesExceptions.push_back(prBase.second);
|
||||
log << "Entity could raise exception on set attribute: " << prBase.first << std::endl;
|
||||
}
|
||||
for (const CTokenList& rlstTokenList : m_vecGetRaisesExceptionsTokenList)
|
||||
{
|
||||
log << "Processing get-raising exception..." << std::endl;
|
||||
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
|
||||
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
|
||||
throw CCompileException("Exception definition not found.");
|
||||
m_vecGetRaisesExceptions.push_back(prBase.second);
|
||||
log << "Entity could raise exception on get attribute: " << prBase.first << std::endl;
|
||||
}
|
||||
|
||||
// Processing is finalized...
|
||||
m_eProcAssState = EProcessAssignmentProgression::processed;
|
||||
}
|
||||
|
||||
bool CDeclarationEntity::RequiresAssignment() const
|
||||
{
|
||||
if (!ValueRef()) return false; // No value assigned yet...
|
||||
|
||||
// If the type has an unbound array in its value, it requires assignment to determine the size of the type.
|
||||
CValueNodePtr ptrValue = ValueRef();
|
||||
while (ptrValue)
|
||||
{
|
||||
if (ptrValue->IsArray() && ptrValue->IsUnbound())
|
||||
return true;
|
||||
ptrValue = ptrValue->GetParentNode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDeclarationEntity::CalcHash(CHashObject& rHash) const
|
||||
{
|
||||
// Add the type
|
||||
if (m_typedecl.GetTypeDefinitionEntityPtr())
|
||||
m_typedecl.GetTypeDefinitionEntityPtr()->CalcHash(rHash);
|
||||
else
|
||||
rHash << m_typedecl.GetTypeString();
|
||||
|
||||
// Add base entity
|
||||
CEntity::CalcHash(rHash);
|
||||
|
||||
// Add array dimensions
|
||||
sdv::sequence<sdv::idl::SArrayDimension> seqArray = GetArrayDimensions();
|
||||
for (const sdv::idl::SArrayDimension& rsDimentation : seqArray)
|
||||
{
|
||||
rHash << "[";
|
||||
if (!rsDimentation.ssExpression.empty())
|
||||
rHash << rsDimentation.ssExpression;
|
||||
rHash << "]";
|
||||
}
|
||||
|
||||
// Get the assignment
|
||||
std::string ssAssignment = GetAssignment();
|
||||
if (!ssAssignment.empty()) rHash << ssAssignment;
|
||||
|
||||
// Add parameters
|
||||
for (const CEntityPtr& rptrEntity : m_vecParameters)
|
||||
rptrEntity->CalcHash(rHash);
|
||||
|
||||
// Add exceptions
|
||||
for (const CEntityPtr& rptrEntity : m_vecRaisesExceptions)
|
||||
{
|
||||
rHash << "raises";
|
||||
rptrEntity->CalcHash(rHash);
|
||||
}
|
||||
|
||||
// Add get-exceptions
|
||||
for (const CEntityPtr& rptrEntity : m_vecGetRaisesExceptions)
|
||||
{
|
||||
rHash << "get_raises";
|
||||
rptrEntity->CalcHash(rHash);
|
||||
}
|
||||
|
||||
// Add set-exceptions
|
||||
for (const CEntityPtr& rptrEntity : m_vecSetRaisesExceptions)
|
||||
{
|
||||
rHash << "set_raises";
|
||||
rptrEntity->CalcHash(rHash);
|
||||
}
|
||||
|
||||
// Add whether it is readonly
|
||||
if (IsReadOnly())
|
||||
rHash << "const";
|
||||
}
|
||||
|
||||
372
sdv_executables/sdv_idl_compiler/entities/declaration_entity.h
Normal file
372
sdv_executables/sdv_idl_compiler/entities/declaration_entity.h
Normal file
@@ -0,0 +1,372 @@
|
||||
#ifndef BASIC_TYPE_ENTITY_H
|
||||
#define BASIC_TYPE_ENTITY_H
|
||||
|
||||
#include "entity_base.h"
|
||||
#include "entity_value.h"
|
||||
#include "../constvariant.h"
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief The base for declaration entity definitions within an IDL file (declarations, typedefs, attributes, operations,
|
||||
* parameters, case declarations, enum entries).
|
||||
* @details The declaration entity definitions all have a similar setup with small differences in detail. Consider the following
|
||||
* structures:
|
||||
* @code
|
||||
* <type> <name> = <value>
|
||||
* const <type> <name> = <value>
|
||||
* readonly attribute <name>
|
||||
* <operation_type> <operation_name>(<parameter_type> <parameter_name>) const
|
||||
* @endcode
|
||||
* The following generalized structure applies to all declaration structures:
|
||||
* @code
|
||||
* prefix type name
|
||||
* prefix type name = value
|
||||
* prefix type name(parameters) postfix
|
||||
* @endcode
|
||||
* The first statement is a declaration. The second statement is a declaration with an assignment. The last statement represents
|
||||
* an operation.
|
||||
* The prefix is used to provide a specific interpretation to the declaration (in, out, inout, const, attribute, readonly,
|
||||
* typedef, struct, union, enum).
|
||||
* The type defines the type the declaration represents (either a system type or a typedefed type - scoped name).
|
||||
* The name is the defined name o the declaration.
|
||||
* The value is the expression used for the assignment.
|
||||
* The parameters are a list of zero or more declaration statements.
|
||||
* The postfix is used to provide a specific interpretation to the declaration (const).
|
||||
* Some declarations might start as a complex type (e.g. struct, union, enum). The might contain the type definition as well as
|
||||
* the declaration. For example:
|
||||
* @code
|
||||
* struct <def_name> { <definition> } <decl_name>
|
||||
* struct { <definition> } <decl_name>
|
||||
* @endcode
|
||||
* In the first statement, the struct is defined and declared in one statement. In the second statement, an anonymous struct is
|
||||
* defined and declared in one statement.
|
||||
* Multiple declarations are possible for many types. The declarations are separated by a comma and follow the same rules as a
|
||||
* single declaration starting at the <name>.
|
||||
* @code
|
||||
* <type> <name_1> = <value_1>, <name_2> = <value_2>, <name_3>, <name_4> = <value_4>
|
||||
* @endcode
|
||||
*/
|
||||
class CDeclarationEntity : public CEntity, public sdv::idl::IDeclarationEntity
|
||||
{
|
||||
friend CSimpleTypeValueNode;
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Constructor using the provided token-list to process the code.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
|
||||
*/
|
||||
CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CDeclarationEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get declaration type. Overload of sdv::idl::IDeclarationEntity::GetDeclarationType.
|
||||
* @return Interface to the declaration type object.
|
||||
*/
|
||||
virtual sdv::IInterfaceAccess* GetDeclarationType() const override;
|
||||
|
||||
/**
|
||||
* @brief Is array? Overload of sdv::idl::IDeclarationEntity::HasArray/HasDynamicArray.
|
||||
* @return Retrurns whether the declaration reqpresents an array.
|
||||
*/
|
||||
virtual bool HasArray() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the array dimensions (if there are any). Overload of IDeclarationEntity::GetDimensionCount.
|
||||
* @return Smart pointer to the sequence of array dimensions.
|
||||
*/
|
||||
virtual sdv::sequence<sdv::idl::SArrayDimension> GetArrayDimensions() const override;
|
||||
|
||||
/**
|
||||
* @brief Has assignment? Overload of sdv::idl::IDeclarationEntity::HasAssignment.
|
||||
* @return Returns whether the declaration has an assignment.
|
||||
*/
|
||||
virtual bool HasAssignment() const override;
|
||||
|
||||
/**
|
||||
* @brief Get assignment string. Overload of sdv::idl::IDeclarationEntity::GetAssignment.
|
||||
* @details The assignment can be an algebraic expression composed from constants and variables. If the assignment is an array,
|
||||
* the expression is composed like this: {{expr1},{expr2},{expr...}}
|
||||
* @return On success, returns the assignment string object or an empty string when no assignment is available.
|
||||
*/
|
||||
virtual sdv::u8string GetAssignment() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the base type of the entity.
|
||||
* @return Returns the base type.
|
||||
*/
|
||||
virtual sdv::idl::EDeclType GetBaseType() const { return m_typedecl.GetBaseType(); }
|
||||
|
||||
/**
|
||||
* @brief Get the type entity if the type is not a system type.
|
||||
* @details Complex types (struct, enum, union) and type definitions are based on a type entity.
|
||||
* @return Returns a pointer to the type entity if available.
|
||||
*/
|
||||
CEntityPtr GetTypeEntity() const;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Process a declaration.
|
||||
* @details The processing of a declaration is done through several steps: processing the declaration type, processing the
|
||||
* declaration identifier, processing (multi-dimensional) arrays, processing assignments, processing the next declaration
|
||||
* identifier and so on.
|
||||
* The following statement are examples:
|
||||
* @code
|
||||
* <type> <identifier>; // No assignment, one declaration
|
||||
* <type> <identifier>, <identifier>; // No assignment, multiple declarations
|
||||
* <type> <identifier>=<expression>; // One definition (declaration with assignment)
|
||||
* <type> <identifier>=<expressoin>, <identifier>=<expression>; // Multiple definitions
|
||||
* <type> <identifier>=<expression>, <identifier>; // Mixed expression, definition
|
||||
* <type> <identifier>[]={<expression>, <expression>}; // Array definition
|
||||
* <type> <identifier>[<expression>]; // Array declaration
|
||||
* <type> <identifier>[<expression>]={<expression>, <expression>}; // Array definition
|
||||
* struct <type> <identifier>; // Struct declaration with explicit struct keyword
|
||||
* struct <type> <identifier>={<expression>, <expression>}; // Struct declaration with assignment
|
||||
* union <type> <identifier>; // Union declaration with explicit union keyword
|
||||
* enum <type> <identifier>; // Enum declaration with explicit enum keyword
|
||||
* enum <type> <identifier>=<exppression>; // Enum definition with explicit enum keyword
|
||||
* @endcode
|
||||
* The 'type' can be a system type (short, int64, float) or a scoped type definition (MyType, \::MyModule\::MyType). Without
|
||||
* assignment the type can be 'struct' or 'union', with or without the 'struct' and 'union' type identification (not allowed
|
||||
* for const entities, which need an assignment).
|
||||
* The 'identifier' is the unique name for the declaration. This name must be case-insensitive unique within the current
|
||||
* scope. The identifier can be followed by square-brackets indicating an array. The size of the array can either be retrieved
|
||||
* through the assignment or through the expression. If both an assignment and an expression are available, they must match.
|
||||
* The array expression must be of an integral type and is not allowed to become negative. Furthermore, it can be created
|
||||
* through a mathematical expression existing of constants and/or when not defined to be a constant entity, through
|
||||
* declarations made before (this deviates to C/C++, where dynamic arrays are not allowed). In case of a dynamic array, an
|
||||
* assignment is not supported.
|
||||
* The assignment 'expression' defines a mathematical expression existing of constants and/or when not defined to be a
|
||||
* constant entity, through declarations made before.
|
||||
* @remarks Array size expressions and assignment expressions are stored as tokenlists to be processed by the
|
||||
* ProcessValueAssignment function.
|
||||
* @param[in] rTypeDecl Reference to the type identifier (can be a system type as well as a scoped name to a previously
|
||||
* defined type).
|
||||
*/
|
||||
void ProcessDeclaration(const CTypeDeclaration& rTypeDecl);
|
||||
|
||||
/**
|
||||
* @brief Preprocess the multi-dimensional array declaration.
|
||||
* @details Preprocess the potential multi-dimensional array declaration by detecting square brackets and storing the tokens
|
||||
* between the brackets. The tokens for each dimension are placed in the m_vecMultiArraySizeTokenList vector.
|
||||
*/
|
||||
void PreprocessArrayDeclaration();
|
||||
|
||||
/**
|
||||
* @brief Preprocess a list of comma separated declarations.
|
||||
* @details Preprocess a list of tokens separated by the comma ',' separator and place the tokens in the provided vector. The
|
||||
* processing is continued until a square bracket ']' or normal bracket ')' or no token exists any more.
|
||||
* @param[in] rvecTokenList Reference to the vector containing the token lists to be filled.
|
||||
*/
|
||||
void PreprocessTokenListVector(std::vector<CTokenList>& rvecTokenList);
|
||||
|
||||
/**
|
||||
* @brief Postprocess the token lists that where read in the preprocess functions.
|
||||
* @pre SupportAssignments returns true and at least m_vecMultiArraySizeTokenList or m_lstAssignmentTokenList is filled.
|
||||
* @details For typedef, const and declaration entities, create the value structure containing the arrays and the values of
|
||||
* the type entity. For const and declaration entities, fill the value structure using the assignment stored in the assignment
|
||||
* expression token list. For attributes and operations build the raising exception lists. For the operations process the
|
||||
* parameter list.
|
||||
*/
|
||||
void PostProcess();
|
||||
|
||||
/**
|
||||
* @brief Does the entity support assignments (const and variable declarations do, others don't)?
|
||||
* @details Determines whether the entity supports assignments. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportAssignments() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity require an assignment (const declarations do)?
|
||||
* @details Determines whether the entity requires an assignment. Default value is is based on the presence of an unbound
|
||||
* value in the type.
|
||||
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresAssignment() const;
|
||||
|
||||
/**
|
||||
* @brief Can the entity be used for assignments of complex types (variable declarations do)?
|
||||
* @details Returns whether the entity is defined to be usable for complex type assignments. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity defined as declaration; 'false' otherwise.
|
||||
*/
|
||||
virtual bool CanSupportComplexTypeAssignments() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support arrays (const and variable declarations, as well as typedefs and attributes do)?
|
||||
* @details Determines whether the entity supports arrays. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of
|
||||
* IDeclarationEntity::IsReadOnly.
|
||||
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
|
||||
* 'true'.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity transparent when used in a struct? Overload of IDeclarationEntity::IsAnonymous.
|
||||
* @details Returns whether the entity is anonymous when used in a struct/union (unnamed and not declared). This allows its
|
||||
* members to appear directly as members within the struct. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity defined as anonymous; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsAnonymous() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support multiple declarations on one line of code (const and var declarations and attributes do)?
|
||||
* @details Returns whether the entity supports multiple declarations separated by a comma ','. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportMultipleDeclarations() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Do not enforce next declaration after comma (enums do)?
|
||||
* @pre SupportMultipleDeclarations needs to be supported.
|
||||
* @details Returns whether the entity supports ending the definition after a comma ','. Default value is 'false'.
|
||||
* @return Returns 'true' when not enforcing the next declaration; 'false' otherwise.
|
||||
*/
|
||||
virtual bool DoNotEnfoceNextDeclarationAfterComma() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support raising exceptions (attributes and operations do)?
|
||||
* @details Returns whether the entity supports exceptions (defined through the keywords: raises, getraises and setraises).
|
||||
* Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports exceptions; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportRaiseExceptions() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support separate set/get raising exceptions (only attributes do)?
|
||||
* @details Returns whether the entity supports exceptions (defined through the keywords: getraises and setraises).
|
||||
* Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports separate set/get raise exceptions; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportSeparateSetGetRaiseExceptions() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support an interface as base type (non-const variables, operations and parameters do)?
|
||||
* @details Returns whether the entity supports the an interface as base type base type. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportInterface() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support 'void' as base type (operations do)?
|
||||
* @details Returns whether the entity supports the 'void' base type. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports void as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportVoid() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity require parameters (operations do)?
|
||||
* @details Returns whether the entity requires parameters. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity requires parameters; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresParameters() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Set operation as const (operations only).
|
||||
* @details If the declaration requires parameters, the declaration is checked for being defined as const operation. If so,
|
||||
* this function is called. Default implementation doesn't do anything.
|
||||
* @pre Only called when RequiresParameters is true and the declaration is defined as const.
|
||||
*/
|
||||
virtual void SetOperationAsConst() {}
|
||||
|
||||
/**
|
||||
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
|
||||
* @param[in, out] rHash Hash object to be filled with data.
|
||||
*/
|
||||
virtual void CalcHash(CHashObject& rHash) const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Get parameter vector.
|
||||
* @return Returns the vector with the parameter entities.
|
||||
*/
|
||||
CEntityVector& GetParamVector() { return m_vecParameters; }
|
||||
|
||||
/**
|
||||
* @brief Get parameter vector.
|
||||
* @return Returns the vector with the parameter entities.
|
||||
*/
|
||||
const CEntityVector& GetParamVector() const { return m_vecParameters; }
|
||||
|
||||
/**
|
||||
* @brief Get "raises" exceptions vector.
|
||||
* @return Returns the vector with the exception entities.
|
||||
*/
|
||||
CEntityVector& GetExceptionVector() { return m_vecRaisesExceptions; }
|
||||
|
||||
/**
|
||||
* @brief Get "get_raises" exceptions vector.
|
||||
* @return Returns the vector with the exception entities.
|
||||
*/
|
||||
CEntityVector& GetReadExceptionVector() { return m_vecGetRaisesExceptions; }
|
||||
|
||||
/**
|
||||
* @brief Get "set_raises" exceptions vector.
|
||||
* @return Returns the vector with the exception entities.
|
||||
*/
|
||||
CEntityVector& GetWriteExceptionVector() { return m_vecSetRaisesExceptions; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Process assignment state.
|
||||
* @details The assignment processing progression state which is used to control the processing of assignments as well as to
|
||||
* prevent circular use of assignments.
|
||||
*/
|
||||
enum class EProcessAssignmentProgression
|
||||
{
|
||||
unprocessed, ///< Assignment hasn't been processed yet
|
||||
currently_processing, ///< Processing currently takes place
|
||||
processed, ///< Processing has been done
|
||||
};
|
||||
|
||||
CTypeDeclaration m_typedecl; ///< The type definition of this declaration.
|
||||
std::vector<CTokenList> m_vecMultiArraySizeTokenList; ///< The list of tokens for each array dimension to be
|
||||
///< calculated during the post processing phase.
|
||||
CTokenList m_lstAssignmentTokenList; ///< The list of tokens forming the assignment.
|
||||
std::vector<CTokenList> m_vecRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
|
||||
///< during the post processing phase.
|
||||
std::vector<CTokenList> m_vecSetRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
|
||||
///< during the post processing phase.
|
||||
std::vector<CTokenList> m_vecGetRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
|
||||
///< during the post processing phase.
|
||||
std::vector<CTokenList> m_vecParametersTokenList; ///< The list of tokens for each parameter to be parsed
|
||||
///< during the post processing phase.
|
||||
EProcessAssignmentProgression m_eProcAssState = EProcessAssignmentProgression::unprocessed; ///< Processing assignment
|
||||
///< progression state.
|
||||
CEntityVector m_vecRaisesExceptions; ///< Can raise the exceptions while reading/writing.
|
||||
CEntityVector m_vecGetRaisesExceptions; ///< Can raise the exceptions while reading.
|
||||
CEntityVector m_vecSetRaisesExceptions; ///< Can raise the exceptions while writing.
|
||||
CEntityVector m_vecParameters; ///< Vector of parameters.
|
||||
};
|
||||
|
||||
#endif // !defined(BASIC_TYPE_ENTITY_H)
|
||||
765
sdv_executables/sdv_idl_compiler/entities/definition_entity.cpp
Normal file
765
sdv_executables/sdv_idl_compiler/entities/definition_entity.cpp
Normal file
@@ -0,0 +1,765 @@
|
||||
#include "definition_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "../parser.h"
|
||||
#include "struct_entity.h"
|
||||
#include "union_entity.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include "attribute_entity.h"
|
||||
#include "operation_entity.h"
|
||||
#include "enum_entity.h"
|
||||
#include "exception_entity.h"
|
||||
#include "interface_entity.h"
|
||||
#include "meta_entity.h"
|
||||
#include <iostream>
|
||||
|
||||
CDefinitionEntity::CDefinitionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CEntity(rptrContext, ptrParent), m_iteratorChildren(GetChildrenVector()), m_iteratorInheritance(m_vecInheritance)
|
||||
{}
|
||||
|
||||
CDefinitionEntity::CDefinitionEntity(CParser& rParser, const CContextPtr& rptrContext) :
|
||||
CEntity(rParser, rptrContext), m_iteratorChildren(GetChildrenVector()), m_iteratorInheritance(m_vecInheritance)
|
||||
{}
|
||||
|
||||
sdv::interface_t CDefinitionEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IDefinitionEntity>())
|
||||
return static_cast<sdv::idl::IDefinitionEntity*>(this);
|
||||
return CEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
void CDefinitionEntity::ProcessContent()
|
||||
{
|
||||
CLog log("Processing definition content...");
|
||||
|
||||
// Get tokens until no token is returned any more.
|
||||
while (true)
|
||||
{
|
||||
// Prepare proocessing the next token
|
||||
CToken token = PeekToken();
|
||||
|
||||
// Add any meta entity
|
||||
std::list<CParser::SMetaToken> lstMeta = GetParserRef().GetAndRemoveMeta();
|
||||
for (const CParser::SMetaToken& rsMeta : lstMeta)
|
||||
AddChild(std::make_shared<CMetaEntity>(rsMeta.tokenMeta.GetContext(), shared_from_this(), rsMeta.tokenMeta,
|
||||
rsMeta.lstComments));
|
||||
|
||||
// Process the acquired token
|
||||
if (!token) break;
|
||||
if (!IsRootEntity() && token == "}")
|
||||
break;
|
||||
|
||||
// Determine whether the comments are preceding the token (either on the same line or the line before).
|
||||
CTokenList lstPreComments = GetPreCommentTokenList();
|
||||
|
||||
// Check for prefixes
|
||||
bool bPrefixConst = false;
|
||||
bool bPrefixReadOnly = false;
|
||||
bool bPrefixTypedef = false;
|
||||
bool bPrefixLocal = false;
|
||||
token = GetToken();
|
||||
uint32_t uiLineBegin = token.GetLine();
|
||||
uint32_t uiColBegin = token.GetCol();
|
||||
if (token == "const") // This must be a const declaration
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_const_variable))
|
||||
throw CCompileException(token, "Unexpected keyword 'const'.");
|
||||
bPrefixConst = true;
|
||||
token = GetToken();
|
||||
}
|
||||
else if (token == "readonly") // This must be a readonly attribute
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_attribute))
|
||||
throw CCompileException(token, "Unexpected keyword 'readonly'.");
|
||||
bPrefixReadOnly = true;
|
||||
token = GetToken();
|
||||
} else if (token == "typedef") // This must be a typedef declaration
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_typedef))
|
||||
throw CCompileException(token, "Unexpected keyword 'typedef'.");
|
||||
bPrefixTypedef = true;
|
||||
token = GetToken();
|
||||
} else if (token == "local") // This must be a const declaration
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_interface))
|
||||
throw CCompileException(token, "Unexpected keyword 'local'.");
|
||||
bPrefixLocal = true;
|
||||
token = GetToken();
|
||||
// The next token must be interface
|
||||
if (token != "interface")
|
||||
throw CCompileException(token, "Unexpected token. Only interfaces can be local.");
|
||||
}
|
||||
|
||||
// For keywords that could be a definition as well as a declaration, find out whether the statement here is a
|
||||
// - forward declaration
|
||||
// - a definition
|
||||
// - a definition as well as a declaration
|
||||
// - a declaration
|
||||
// Check for a definition (first three points).
|
||||
auto fnIsDefinition = [&]() -> bool
|
||||
{
|
||||
// A declaration without definition has the construction
|
||||
// <def type> <def identifier> <decl identifier>;
|
||||
// e.g.
|
||||
// struct STest sTest;
|
||||
// The <def type> was retrieved already. The next token would be the identifier.
|
||||
if (PeekToken(0).GetType() == ETokenType::token_identifier &&
|
||||
PeekToken(1).GetType() == ETokenType::token_identifier) return false;
|
||||
|
||||
// All other situations indicate a definition (possibly followed by a declaration).
|
||||
return true;
|
||||
};
|
||||
|
||||
CEntityPtr ptrDefinitionEntity;
|
||||
CToken tokenDefinitionType = token;
|
||||
if (token == "module" && fnIsDefinition())
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_module))
|
||||
throw CCompileException(token, "Unexpected keyword 'module'.");
|
||||
ptrDefinitionEntity = CreateChild<CModuleEntity>(token.GetContext(), this);
|
||||
}
|
||||
else if (token == "enum" && fnIsDefinition())
|
||||
{
|
||||
if (fnIsDefinition() && !Supports(EDefinitionSupport::support_enum))
|
||||
throw CCompileException(token, "Unexpected keyword 'enum'.");
|
||||
ptrDefinitionEntity = CreateChild<CEnumEntity>(token.GetContext(), this);
|
||||
}
|
||||
else if (token == "exception" && fnIsDefinition())
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_exception))
|
||||
throw CCompileException(token, "Unexpected keyword 'exception'.");
|
||||
ptrDefinitionEntity = CreateChild<CExceptionEntity>(token.GetContext(), this);
|
||||
}
|
||||
else if (token == "struct" && fnIsDefinition())
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_struct))
|
||||
throw CCompileException(token, "Unexpected keyword 'struct'.");
|
||||
ptrDefinitionEntity = CreateChild<CStructEntity>(token.GetContext(), this);
|
||||
}
|
||||
else if (token == "union" && fnIsDefinition())
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_union))
|
||||
throw CCompileException(token, "Unexpected keyword 'union'.");
|
||||
ptrDefinitionEntity = CreateChild<CUnionEntity>(token.GetContext(), this);
|
||||
}
|
||||
else if (token == "interface" && fnIsDefinition())
|
||||
{
|
||||
if (!Supports(EDefinitionSupport::support_interface))
|
||||
throw CCompileException(token, "Unexpected keyword 'interface'.");
|
||||
ptrDefinitionEntity = CreateChild<CInterfaceEntity>(token.GetContext(), this, bPrefixLocal);
|
||||
}
|
||||
|
||||
// Definition available?
|
||||
if (ptrDefinitionEntity)
|
||||
{
|
||||
// Assign the preceding comments (only if not prefixed)
|
||||
if (!bPrefixConst && !bPrefixReadOnly && !bPrefixTypedef && !lstPreComments.empty())
|
||||
{
|
||||
ptrDefinitionEntity->SetCommentTokens(lstPreComments);
|
||||
lstPreComments.clear();
|
||||
}
|
||||
|
||||
// Set the location in the source file
|
||||
ptrDefinitionEntity->SetBeginPosition(uiLineBegin, uiColBegin);
|
||||
|
||||
// Process the definition
|
||||
log << "Detected " << static_cast<std::string>(token) << " definition..." << std::endl;
|
||||
ptrDefinitionEntity->Process();
|
||||
token = GetToken();
|
||||
|
||||
// Assign any succeeding comments
|
||||
ptrDefinitionEntity->ProcessPostCommentTokenList(token.GetLine());
|
||||
}
|
||||
|
||||
// A struct allows the definition of types that require a declaration within the struct, but the declaration is anonymous
|
||||
// (unnamed and not declared) so the members of the definition appear as if they are part of the struct.
|
||||
bool bAnonymousDecl = false;
|
||||
if (token == ";" && GetType() == sdv::idl::EEntityType::type_struct && ptrDefinitionEntity &&
|
||||
ptrDefinitionEntity->Get<CDefinitionEntity>()->RequireDeclaration())
|
||||
{
|
||||
if (ptrDefinitionEntity->Get<CDefinitionEntity>()->AllowAutoTransparentDeclaration())
|
||||
{
|
||||
// Allow processing still
|
||||
PrependToken(token);
|
||||
|
||||
// Create a dummy name
|
||||
token = CToken(GetParserRef().GenerateAnonymousEntityName("var"));
|
||||
|
||||
bAnonymousDecl = true;
|
||||
} else
|
||||
throw CCompileException(token,
|
||||
"The definition requires a declaration following the definition content or cannot find a variable within "
|
||||
"current scope - unexpected token ';'.");
|
||||
}
|
||||
|
||||
// Statement finished?
|
||||
if (token == ";")
|
||||
{
|
||||
if (bPrefixConst || bPrefixReadOnly || bPrefixTypedef)
|
||||
throw CCompileException(token, "Unexpected token ';'.");
|
||||
|
||||
if (ptrDefinitionEntity)
|
||||
{
|
||||
// Assign any succeeding comments
|
||||
ptrDefinitionEntity->ProcessPostCommentTokenList(token.GetLine());
|
||||
|
||||
// Set the end position in the source file.
|
||||
ptrDefinitionEntity->SetEndPosition(token.GetLine(), token.GetCol());
|
||||
|
||||
// Declaration needed?
|
||||
if (ptrDefinitionEntity->Get<CDefinitionEntity>()->RequireDeclaration())
|
||||
throw CCompileException(token,
|
||||
"The definition requires a declaration following the definition content - unexpected token ';'.");
|
||||
}
|
||||
|
||||
continue;
|
||||
};
|
||||
|
||||
if (!token && !bPrefixConst && !bPrefixReadOnly && !bPrefixTypedef)
|
||||
throw CCompileException(GetLastValidToken(), "Missing ';' following the token.");
|
||||
|
||||
// The declarative part can consist of the following types of declaration
|
||||
// - an attribute - read-only prefix possible
|
||||
// - a typedef
|
||||
// - an operation
|
||||
// - a variable - const prefix possible
|
||||
CEntityPtr ptrDeclarationEntity;
|
||||
if (bPrefixReadOnly && token != "attribute")
|
||||
throw CCompileException(token, "Expecting 'attribute' keyword following 'readonly'.");
|
||||
if (token == "attribute")
|
||||
{
|
||||
if (bPrefixConst || bPrefixTypedef || ptrDefinitionEntity || !Supports(EDefinitionSupport::support_attribute))
|
||||
throw CCompileException(token, "Unexpected keyword 'attribute'.");
|
||||
ptrDeclarationEntity = CreateChild<CAttributeEntity>(token.GetContext(), this, bPrefixReadOnly);
|
||||
if (bPrefixReadOnly)
|
||||
log << "Detected read-only attribute declaration..." << std::endl;
|
||||
else
|
||||
log << "Detected attribute declaration..." << std::endl;
|
||||
}
|
||||
else if (token == "case" || token == "default")
|
||||
{
|
||||
if (bPrefixReadOnly || bPrefixConst || bPrefixTypedef || ptrDefinitionEntity || !Supports(EDefinitionSupport::support_case_declaration))
|
||||
throw CCompileException(token, "Unexpected keyword 'case'.");
|
||||
ptrDeclarationEntity = CreateChild<CCaseEntry>(token.GetContext(), this, token == "default");
|
||||
log << "Detected case entry declaration..." << std::endl;
|
||||
} else
|
||||
{
|
||||
// Reinsert the token into the tokenlist
|
||||
PrependToken(token);
|
||||
|
||||
// Check whether the declaration is a variable declaration or an operation.
|
||||
// An operation can have the following structure:
|
||||
// <keyword> <identifier>(); e.g. int32 Func()
|
||||
// <keyword> <keyword> <identifier>(); e.g. long long Func()
|
||||
// <keyword> <keyword> <keyword> <identifier>(); e.g. unsigned long long Func()
|
||||
// <identifier> <identifier>() e.g. mytype Func()
|
||||
// A variable declaration can have the following structure:
|
||||
// <keyword> <identifier>; e.g. int32 iVar;
|
||||
// <keyword> <keyword> <identifier>; e.g. long long llVar;
|
||||
// <keyword> <keyword> <keyword> <identifier>; e.g. unsigned long long ullVar;
|
||||
// <keyword> <identifier> = <expression>; e.g. int32 iVar = 10;
|
||||
// <keyword> <keyword> <identifier> = <expression>; e.g. long long llVar = 10;
|
||||
// <keyword> <keyword> <keyword> <identifier> = <expression>; e.g. unsigned long long ullVar = 10;
|
||||
// Only variables can be declared with const prefix.
|
||||
// A variable declaration without assignment can also be a typedef when declared with typedef prefix.
|
||||
// Operations cannot be declared follwoing a definition.
|
||||
|
||||
// As type expecting up to three keywords or one scoped identifier (composition of identifier and scope operator).
|
||||
// If there is a definition, then the declaration and definition are combined. The type is there then already.
|
||||
size_t nIndex = 0;
|
||||
bool bTypeFound = ptrDefinitionEntity ? true : false;
|
||||
CToken tokenLocal;
|
||||
bool bLongType = false;
|
||||
bool bUnsignedType = false;
|
||||
while ((tokenLocal = PeekToken(nIndex)).GetType() == ETokenType::token_keyword)
|
||||
{
|
||||
// Unsigned is allowed only as first keyword
|
||||
if (tokenLocal == "unsigned")
|
||||
{
|
||||
if (nIndex) break;
|
||||
bUnsignedType = true;
|
||||
}
|
||||
|
||||
// Long should be followed by long or double.
|
||||
if (bLongType && tokenLocal != "long" && tokenLocal != "double") break;
|
||||
|
||||
// Increase the token index...
|
||||
nIndex++;
|
||||
|
||||
// Type found...
|
||||
bTypeFound = true;
|
||||
|
||||
// After unsigned, at least one more keyword needs to follow
|
||||
if (bUnsignedType && nIndex == 1) continue;
|
||||
|
||||
// After long, another type can follow, but only when this long didn't follow a previous long already.
|
||||
if (tokenLocal == "long")
|
||||
{
|
||||
if (bLongType) break; // type was long long.
|
||||
bLongType = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The type can be a templated type (or even nested templated types are possible).
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
CToken tokenLocalTemplate;
|
||||
if (tokenLocal == "<")
|
||||
{
|
||||
size_t nDepth = 0;
|
||||
tokenLocalTemplate = tokenLocal;
|
||||
do
|
||||
{
|
||||
if (tokenLocal == "<") nDepth++;
|
||||
if (tokenLocal == ">") nDepth--;
|
||||
if (tokenLocal == ">>") nDepth-=2; // This actually is an operator
|
||||
nIndex++;
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
} while (tokenLocal && static_cast<bool>(nDepth));
|
||||
}
|
||||
|
||||
// No more types are expected to follow
|
||||
break;
|
||||
}
|
||||
while (!bTypeFound)
|
||||
{
|
||||
// Check for the scope parameter
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
if (tokenLocal == "::")
|
||||
{
|
||||
nIndex++;
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
}
|
||||
|
||||
// Check for the identifier
|
||||
if (tokenLocal.GetType() == ETokenType::token_identifier)
|
||||
{
|
||||
nIndex++;
|
||||
if (PeekToken(nIndex) != "::")
|
||||
bTypeFound = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Coming here means, there was no type
|
||||
throw CCompileException(tokenLocal, "Invalid token '", static_cast<std::string>(tokenLocal),
|
||||
"' found for type name.");
|
||||
}
|
||||
|
||||
// The return value can be an array - but only in case of operations.
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
CToken tokenLocalArray;
|
||||
while (tokenLocal == "[")
|
||||
{
|
||||
if (!tokenLocalArray) tokenLocalArray = tokenLocal;
|
||||
do
|
||||
{
|
||||
nIndex++;
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
} while (tokenLocal && tokenLocal != "]");
|
||||
nIndex++;
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
}
|
||||
|
||||
// Expecting identfier representing the name
|
||||
// If the extension is enabled, this could also be a keyword.
|
||||
if (tokenLocal.GetType() != ETokenType::token_identifier &&
|
||||
(!GetParserRef().GetEnvironment().ContextDependentNamesExtension() ||
|
||||
tokenLocal.GetType() != ETokenType::token_keyword))
|
||||
throw CCompileException(tokenLocal, "Invalid token '", static_cast<std::string>(tokenLocal),
|
||||
"' found for type name (or missing semi-colon ';' ?).");
|
||||
nIndex++;
|
||||
|
||||
// An operation has a left bracket
|
||||
tokenLocal = PeekToken(nIndex);
|
||||
if (tokenLocal == "(") // This indicates a operation
|
||||
{
|
||||
if (ptrDefinitionEntity || bPrefixConst || bPrefixTypedef || !Supports(EDefinitionSupport::support_operation))
|
||||
throw CCompileException(tokenLocal, "Unexpected left bracket '('.");
|
||||
ptrDeclarationEntity = CreateChild<COperationEntity>(token.GetContext(), this);
|
||||
log << "Detected operation declaration..." << std::endl;
|
||||
}
|
||||
else // This could be a variable declaration or a typedef declaration
|
||||
{
|
||||
// An array is not allowed when not using an operation
|
||||
if (tokenLocalArray)
|
||||
throw CCompileException(tokenLocalArray, "Invalid token '[' found for type name.");
|
||||
|
||||
// If there is a definition, add the name of the definition
|
||||
if (ptrDefinitionEntity)
|
||||
{
|
||||
CToken tokenName(ptrDefinitionEntity->GetName());
|
||||
PrependToken(tokenName);
|
||||
}
|
||||
|
||||
// Check for typedef declaration
|
||||
if (bPrefixTypedef)
|
||||
{
|
||||
ptrDeclarationEntity = CreateChild<CTypedefEntity>(token.GetContext(), this);
|
||||
log << "Detected typedef declaration..." << std::endl;
|
||||
}
|
||||
else // Variable declaration
|
||||
{
|
||||
if (!bPrefixConst && !Supports(EDefinitionSupport::support_variable))
|
||||
throw CCompileException(token, "Variable declaration is not supported.");
|
||||
ptrDeclarationEntity = CreateChild<CVariableEntity>(token.GetContext(), this, bPrefixConst, bAnonymousDecl);
|
||||
if (bPrefixConst)
|
||||
log << "Detected const variable declaration..." << std::endl;
|
||||
else
|
||||
log << "Detected variable declaration..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the entity declaration.
|
||||
if (!ptrDeclarationEntity) throw CCompileException("Declaration expected.");
|
||||
ptrDeclarationEntity->SetBeginPosition(uiLineBegin, uiColBegin);
|
||||
ptrDeclarationEntity->Process();
|
||||
|
||||
if (!lstPreComments.empty())
|
||||
ptrDeclarationEntity->SetCommentTokens(lstPreComments);
|
||||
|
||||
// Expect ';'
|
||||
token = GetToken();
|
||||
if (token != ";")
|
||||
throw CCompileException(token, "Missing semicolon ';' following the declaration.");
|
||||
}
|
||||
|
||||
log << "For definition '" << GetName() << "', processing value assignments within content..." << std::endl;
|
||||
|
||||
// If supported create the value node for the definition (this allows assignments of values to this entity).
|
||||
CreateValueNode();
|
||||
|
||||
// If there is a value node (assignment is supported), add the inherited value sub-trees to the type as children. If there are
|
||||
// inherited entities with value nodes of their own, of course.
|
||||
if (ValueRef())
|
||||
CreateInheritanceValueChildNodes();
|
||||
|
||||
// Go through all the type members and do post processing (building value chains, resolving arrays, etc.).
|
||||
for (CEntityPtr ptrTypeEntity : m_lstTypeMembers)
|
||||
{
|
||||
CTypedefEntity* pTypedefEntity = ptrTypeEntity->Get<CTypedefEntity>();
|
||||
if (pTypedefEntity)
|
||||
{
|
||||
log << "Post-processing typedef entity '" << pTypedefEntity->GetName() << "'..." << std::endl;
|
||||
pTypedefEntity->PostProcess();
|
||||
}
|
||||
CUnionEntity* pUnionEntity = ptrTypeEntity->Get<CUnionEntity>();
|
||||
if (pUnionEntity)
|
||||
{
|
||||
log << "Post-processing union entity '" << pUnionEntity->GetName() << "'..." << std::endl;
|
||||
pUnionEntity->PostProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all the typedef members and do post processing (building value chains, resolving arrays, variable assignment,
|
||||
// etc.).
|
||||
for (CEntityPtr ptrConstEntity : m_lstConstMembers)
|
||||
{
|
||||
CVariableEntity* pConstEntity = ptrConstEntity->Get<CVariableEntity>();
|
||||
if (!pConstEntity)
|
||||
throw CCompileException("Internal error: non-const entities in const entity list.");
|
||||
else
|
||||
{
|
||||
log << "Post-processing const variable entity '" << pConstEntity->GetName() << "'..." << std::endl;
|
||||
pConstEntity->PostProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all the definition members and do post processing (resolving arrays, creating exception and parameter lists,
|
||||
// etc.).
|
||||
for (CEntityPtr ptrDefinitionEntity : m_lstAttributesOperation)
|
||||
{
|
||||
CAttributeEntity* pAttribute = ptrDefinitionEntity->Get<CAttributeEntity>();
|
||||
COperationEntity* pOperation = ptrDefinitionEntity->Get<COperationEntity>();
|
||||
if (!pAttribute && !pOperation)
|
||||
throw CCompileException("Internal error: wrong entities in definition list.");
|
||||
|
||||
if (pAttribute)
|
||||
{
|
||||
log << "Postprocessing attribute entity '" << pAttribute->GetName() << "'..." << std::endl;
|
||||
pAttribute->PostProcess();
|
||||
}
|
||||
if (pOperation)
|
||||
{
|
||||
log << "Postprocessing operation entity '" << pOperation->GetName() << "'..." << std::endl;
|
||||
pOperation->PostProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all the variable members and create the default values for all var members if the value node is a compound type
|
||||
// value node.
|
||||
for (CEntityPtr ptrDeclEntity : m_lstDeclMembers)
|
||||
{
|
||||
CVariableEntity *pDeclEntity = ptrDeclEntity->Get<CVariableEntity>();
|
||||
if (!pDeclEntity)
|
||||
throw CCompileException("Internal error: non-declaration entity in declaration entity list.");
|
||||
else
|
||||
{
|
||||
log << "Postprocess variable entity '" << pDeclEntity->GetName() << "'..." << std::endl;
|
||||
pDeclEntity->PostProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDefinitionEntity::Process()
|
||||
{
|
||||
CLog log("Processing definition of entity...");
|
||||
|
||||
// Check for an identifier.
|
||||
// If present, this is the name of the definition.
|
||||
CToken token = GetToken();
|
||||
std::string ssName;
|
||||
m_bAnonymousDefinition = false;
|
||||
if (token.GetType() == ETokenType::token_identifier)
|
||||
{
|
||||
ssName = static_cast<std::string>(token);
|
||||
log << "Definition type name '" << ssName << "'..." << std::endl;
|
||||
} else
|
||||
if (SupportsAnonymous())
|
||||
{
|
||||
if (!GetParentEntity() || GetParentEntity()->IsRootEntity())
|
||||
throw CCompileException(token, "Unnamed definitions are not supported at root level.");
|
||||
std::string ssPrefix = "anonymous";
|
||||
switch (GetType())
|
||||
{
|
||||
case sdv::idl::EEntityType::type_enum: ssPrefix = "enum"; break;
|
||||
case sdv::idl::EEntityType::type_struct: ssPrefix = "struct"; break;
|
||||
case sdv::idl::EEntityType::type_union: ssPrefix = "union"; break;
|
||||
case sdv::idl::EEntityType::type_module: ssPrefix = "namespace"; break;
|
||||
case sdv::idl::EEntityType::type_interface: ssPrefix = "interface"; break;
|
||||
case sdv::idl::EEntityType::type_exception: ssPrefix = "except"; break;
|
||||
case sdv::idl::EEntityType::type_typedef: ssPrefix = "typedef"; break;
|
||||
default: break;
|
||||
}
|
||||
ssName = GetParserRef().GenerateAnonymousEntityName(ssPrefix);
|
||||
log << "Unnamed definition was automatically assigned name '" << ssName << "'..." << std::endl;
|
||||
m_bRequiresContent = true;
|
||||
m_bAnonymousDefinition = true;
|
||||
PrependToken(token);
|
||||
} else
|
||||
throw CCompileException(token, "Unnamed definition is not supported.");
|
||||
|
||||
// Process the definition addendum
|
||||
ProcessDefinitionAddendum();
|
||||
|
||||
// Expecting curly bracket when for a
|
||||
token = GetToken();
|
||||
if (RequireContentDefinition() && token != "{")
|
||||
throw CCompileException(token, "Expecting curly bracket '{'.");
|
||||
|
||||
// If there is no content, consider the statement as a (forward) declaration.
|
||||
SetName(ssName, token != "{");
|
||||
|
||||
// If there is no content, the processing is done.
|
||||
if (token != "{")
|
||||
{
|
||||
log << "Definition type was defined as forward declaration." << std::endl;
|
||||
log << "Finished processing definition entity..." << std::endl;
|
||||
PrependToken(token);
|
||||
return;
|
||||
}
|
||||
|
||||
// Definition content...
|
||||
ProcessContent();
|
||||
|
||||
// Close the definition
|
||||
token = GetToken();
|
||||
if (token != "}")
|
||||
throw CCompileException(token, "Expecting curly bracket '}'.");
|
||||
|
||||
log << "Finished processing definition entity..." << std::endl;
|
||||
}
|
||||
|
||||
void CDefinitionEntity::ProcessDefinitionAddendum()
|
||||
{
|
||||
// Check for inheritance
|
||||
CToken token = GetToken();
|
||||
if (token != ":")
|
||||
{
|
||||
PrependToken(token);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SupportsInheritance()) throw CCompileException(token, "Inheritance is not supported.");
|
||||
|
||||
// When an inheritance list is provided, the content should also be provided.
|
||||
m_bRequiresContent = true;
|
||||
|
||||
CLog log("Processing inheritance list...");
|
||||
|
||||
// Get the list of base entities
|
||||
while (true)
|
||||
{
|
||||
// Find the base entity.
|
||||
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName();
|
||||
if (prBase.first.empty() || !prBase.second)
|
||||
throw CCompileException("Base not found.");
|
||||
log << "Inherited from base entity: " << prBase.first << std::endl;
|
||||
|
||||
if (prBase.second->GetResolvedEntity()->GetType() != GetType())
|
||||
throw CCompileException("Cannot inherit from different types.");
|
||||
|
||||
// Check whether the base entity is more than only a declaration.
|
||||
if (prBase.second->ForwardDeclaration())
|
||||
throw CCompileException("Base type found, but only declared; definition is missing.");
|
||||
|
||||
// TODO: Check whether the entity was already previously inherited directly or indirectly. Inheriting through a base
|
||||
// prevents inheriting again.
|
||||
|
||||
// Add the base entity to the base entity list.
|
||||
m_vecInheritance.push_back(prBase.second);
|
||||
|
||||
// Get the next base entity or the beginning of the definition.
|
||||
token = GetToken();
|
||||
if (token != ",")
|
||||
{
|
||||
PrependToken(token);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDefinitionEntity::CreateInheritanceValueChildNodes()
|
||||
{
|
||||
CLog log("Creating values for inherited child nodes...");
|
||||
|
||||
if (!ValueRef()) throw CCompileException("Internal error: cannot create inheritance value child nodes.");
|
||||
|
||||
// For each base entity, copy the value tree
|
||||
for (CEntityPtr ptrInheritedEntity : m_vecInheritance)
|
||||
{
|
||||
// Check for a valid value of the base entity.
|
||||
if (!ptrInheritedEntity->GetResolvedEntity()->ValueRef())
|
||||
throw CCompileException("Internal error: base entity wasn't processed for assignment yet.");
|
||||
|
||||
log << "Assigning values from base entity '" << ptrInheritedEntity->GetName() << "'." << std::endl;
|
||||
|
||||
// Create a copy of the tree and add as child to own tree.
|
||||
ValueRef()->AddChild(ptrInheritedEntity->GetResolvedEntity()->ValueRef()->CreateCopy(shared_from_this(), ValueRef()));
|
||||
}
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* CDefinitionEntity::GetChildren()
|
||||
{
|
||||
if (SupportsChildren()) return &m_iteratorChildren;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* CDefinitionEntity::GetInheritance()
|
||||
{
|
||||
if (SupportsInheritance() && !m_vecInheritance.empty()) return &m_iteratorInheritance;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CDefinitionEntity::CalcHash(CHashObject& rHash) const
|
||||
{
|
||||
// First calc the hash of the base entity.
|
||||
CEntity::CalcHash(rHash);
|
||||
|
||||
// Add the hashes of all inherited entities
|
||||
for (const CEntityPtr& ptrEntity : m_vecInheritance)
|
||||
ptrEntity->CalcHash(rHash);
|
||||
|
||||
// Add the declarations
|
||||
for (const CEntityPtr& ptrEntity : m_lstDeclMembers)
|
||||
ptrEntity->CalcHash(rHash);
|
||||
|
||||
// Add the attributes and operations
|
||||
for (const CEntityPtr& ptrEntity : m_lstAttributesOperation)
|
||||
ptrEntity->CalcHash(rHash);
|
||||
}
|
||||
|
||||
const CEntityList CDefinitionEntity::GetDeclMembers() const
|
||||
{
|
||||
CEntityList lstMembers;
|
||||
|
||||
// Add all declarations from the inherited members
|
||||
for (const CEntityPtr& rptrInheritedEntity : m_vecInheritance)
|
||||
{
|
||||
const CDefinitionEntity* pDefinition = rptrInheritedEntity->GetResolvedEntity()->Get<CDefinitionEntity>();
|
||||
if (pDefinition)
|
||||
{
|
||||
CEntityList lstInheritedEntities = pDefinition->GetDeclMembers();
|
||||
for (const CEntityPtr& ptrInheritedMember : lstInheritedEntities)
|
||||
lstMembers.push_back(ptrInheritedMember);
|
||||
}
|
||||
}
|
||||
|
||||
// Add own declarations
|
||||
for (const CEntityPtr& rptrMember : m_lstDeclMembers)
|
||||
lstMembers.push_back(rptrMember);
|
||||
|
||||
return lstMembers;
|
||||
}
|
||||
|
||||
void CDefinitionEntity::AddChild(CEntityPtr ptrChild)
|
||||
{
|
||||
CLog log;
|
||||
|
||||
// Call base class first
|
||||
CEntity::AddChild(ptrChild);
|
||||
|
||||
// Dependable on the type of entity, add the entity to dedicated lists as well.
|
||||
if (ptrChild->Get<CTypedefEntity>())
|
||||
{
|
||||
m_lstTypeMembers.push_back(ptrChild);
|
||||
log << "Added typedef declaration to type member list..." << std::endl;
|
||||
}
|
||||
else if (ptrChild->Get<CAttributeEntity>())
|
||||
{
|
||||
m_lstAttributesOperation.push_back(ptrChild);
|
||||
log << "Added attribute to definition list..." << std::endl;
|
||||
} else if (ptrChild->Get<COperationEntity>())
|
||||
{
|
||||
m_lstAttributesOperation.push_back(ptrChild);
|
||||
log << "Added operation to definition list..." << std::endl;
|
||||
}
|
||||
else if (ptrChild->Get<CDeclarationEntity>())
|
||||
{
|
||||
if (ptrChild->Get<CDeclarationEntity>()->IsReadOnly())
|
||||
{
|
||||
m_lstConstMembers.push_back(ptrChild);
|
||||
log << "Added const declaration to const member list..." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lstDeclMembers.push_back(ptrChild);
|
||||
log << "Added declaration to variable member list..." << std::endl;
|
||||
}
|
||||
}
|
||||
else if (ptrChild->Get<CDefinitionEntity>())
|
||||
{
|
||||
m_lstTypeMembers.push_back(ptrChild);
|
||||
log << "Added definition to type member list..." << std::endl;
|
||||
}
|
||||
else if (ptrChild->Get<CMetaEntity>())
|
||||
{
|
||||
GetRootEntity()->Get<CRootEntity>()->AddMeta(ptrChild);
|
||||
log << "Added meta data to root based meta list..." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<CEntityPtr, bool> CDefinitionEntity::FindLocal(const std::string& rssName, bool bDeclaration) const
|
||||
{
|
||||
// Call base class implementation first.
|
||||
std::pair<CEntityPtr, bool> prEntity = CEntity::FindLocal(rssName, bDeclaration);
|
||||
if (prEntity.first) return prEntity;
|
||||
|
||||
// Check through all inherited entities
|
||||
for (const CEntityPtr& rptrBaseEntity : m_vecInheritance)
|
||||
{
|
||||
if (!rptrBaseEntity) continue;
|
||||
CEntityPtr ptrResolvedBaseEntity = rptrBaseEntity->GetResolvedEntity();
|
||||
if (!ptrResolvedBaseEntity->Get<CDefinitionEntity>()) continue;
|
||||
prEntity = ptrResolvedBaseEntity->Get<CDefinitionEntity>()->FindLocal(rssName, bDeclaration);
|
||||
if (prEntity.first)
|
||||
{
|
||||
// Set the inherited flag
|
||||
prEntity.second = true;
|
||||
return prEntity;
|
||||
}
|
||||
}
|
||||
|
||||
// No entity found.
|
||||
return std::make_pair(CEntityPtr(), false);
|
||||
}
|
||||
249
sdv_executables/sdv_idl_compiler/entities/definition_entity.h
Normal file
249
sdv_executables/sdv_idl_compiler/entities/definition_entity.h
Normal file
@@ -0,0 +1,249 @@
|
||||
#ifndef DEFINITION_ENTITY_H
|
||||
#define DEFINITION_ENTITY_H
|
||||
|
||||
#include "entity_base.h"
|
||||
|
||||
/**
|
||||
* @brief Support flags for the content of a definition (the part between the curly brackets '{...}').
|
||||
*/
|
||||
enum class EDefinitionSupport : uint32_t
|
||||
{
|
||||
support_variable, ///< Support variable declarations.
|
||||
support_const_variable, ///< Support const variable declarations.
|
||||
support_case_declaration, ///< Support case declarations.
|
||||
support_enum_entry, ///< Support enumerator entry.
|
||||
support_module, ///< Support module definitions.
|
||||
support_typedef, ///< Support typedef declarations.
|
||||
support_interface, ///< Support interface definitions.
|
||||
support_struct, ///< Support struct definitions.
|
||||
support_union, ///< Support union definitions.
|
||||
support_enum, ///< Support enum definitions.
|
||||
support_exception, ///< Support exception definitions.
|
||||
support_attribute, ///< Support attribute declarations.
|
||||
support_operation, ///< Support operation declarations.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The base for definition entity definitions within an IDL file (struct, union, exception, interface, enum).
|
||||
* @details The definition entity definitions all have a similar setup with small differences in detail. Consider the following
|
||||
* structures:
|
||||
* @code
|
||||
* struct <name | anonymous> : <inheritance list> { <member list> }
|
||||
* union <name | anonymous> switch(<type>) { <case member list> }
|
||||
* interface <name> : <inheritance list> { <member list> }
|
||||
* exception <name> { <member list> }
|
||||
* enum <name> : <type> { <item list> }
|
||||
* @endcode
|
||||
* The following generalized structure applies to all complex structures:
|
||||
* @code
|
||||
* keyword name
|
||||
* prefix keyword name postfix { definition }
|
||||
* @endcode
|
||||
* The first statement is a forward declaration. The second represents the type definition.
|
||||
* The prefix is used to provide a specific interpretation to the definition.
|
||||
* The keyword defines the type of definition (can be struct, union, interface, exception, enum).
|
||||
* The name is the defined name of the definition. For types that allow anonymous names, this part is optionally.
|
||||
* The postfix allows the specification of additional information needed for the definition (inheritynce list, switch list).
|
||||
* The definition defines the content of the type.
|
||||
* Some declarations might start as a type definition (e.g. struct, union, enum) followed with a declaration. For example:
|
||||
* @code
|
||||
* struct <def_name> { <definition> } <decl_name>
|
||||
* struct { <definition> } <decl_name>
|
||||
* @endcode
|
||||
* In the first statement, the struct is defined and declared in one statement. In the second statement, an anonymous struct is
|
||||
* defined and declared in one statement.
|
||||
*/
|
||||
class CDefinitionEntity : public CEntity, public sdv::idl::IDefinitionEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CDefinitionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Root entity constructor (name is 'root' and no parent).
|
||||
* @param[in] rParser Reference to the parser.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
*/
|
||||
CDefinitionEntity(CParser& rParser, const CContextPtr& rptrContext);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CDefinitionEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Process the content of the definition.
|
||||
* @details Process the content of the definition. This function parses through the content until a closing curly bracket
|
||||
* has been detected. First the function checks for prefixes. Then the function determines whether the statement is a
|
||||
* declaration or a definition. It then creates the corresponding entity and let the entity process itself.
|
||||
*/
|
||||
virtual void ProcessContent();
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Process the definition addendum.
|
||||
* @details Process the definition addendum following the definition statement before the content definition. The default
|
||||
* implementation checks for an inheritance list.
|
||||
*/
|
||||
virtual void ProcessDefinitionAddendum();
|
||||
|
||||
/**
|
||||
* @brief Create a values for inherited child nodes.
|
||||
*/
|
||||
void CreateInheritanceValueChildNodes();
|
||||
|
||||
/**
|
||||
* \brief Does the entity have an Unnamed definition. Overload of IDefinitionEntity::Unnamed.
|
||||
* @return Returns 'true' when the definition supports unnamed definition; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsUnnamed() const override { return m_bAnonymousDefinition; };
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. This function must be implemented by the derived entity.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
|
||||
* @details Complex types support children per default.
|
||||
* @return Returns whether the entity supports children (which is the case).
|
||||
*/
|
||||
virtual bool SupportsChildren() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support inheritance?
|
||||
* @details The default implementation is that inheritance is not supported.
|
||||
* @return Returns whether the entity supports inheritance (which is not the case).
|
||||
*/
|
||||
virtual bool SupportsInheritance() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support anonymous naming?
|
||||
* @details The default implementation is that anonymous naming is not supported.
|
||||
* @return Returns whether the entity supports inheritance (which is not the case).
|
||||
*/
|
||||
virtual bool SupportsAnonymous() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the complex entity support attributes in its content?
|
||||
* @details The default implementation doesn't support attributes (they are specific to interfaces).
|
||||
* @return Returns whether the entity supports attributes (which is not the case).
|
||||
*/
|
||||
virtual bool SupportContentAttributes() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the complex entity support operations in its content?
|
||||
* @details The default implementation doesn't support operations (they are specific to interfaces).
|
||||
* @return Returns whether the entity supports operations (which is not the case).
|
||||
*/
|
||||
virtual bool SupportContentOperations() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Does the definition entity require a content definition?
|
||||
* @details In certain cases, it is required that the content definition is following the definition statement. For example,
|
||||
* when an inheritance list is provided. The default implementation checks the m_bRequiresContent variable.
|
||||
* @return Returns whether the content definition should be defined following the definition statement.
|
||||
*/
|
||||
virtual bool RequireContentDefinition() const { return m_bRequiresContent; }
|
||||
|
||||
/**
|
||||
* @brief Does the definition require a declaration?
|
||||
* @details In certain cases, it is required that the definition is followed by a declaration. For example,
|
||||
* when the definition was made anonymously or when the definition is dependent on a variable within the same struct (e.g. with
|
||||
* unions).
|
||||
* @return Returns whether the definition requires a declaration.
|
||||
*/
|
||||
virtual bool RequireDeclaration() const { return IsUnnamed(); }
|
||||
|
||||
/**
|
||||
* @brief Does the definition allow automatic transparent declaration if not present?
|
||||
* @details When set an automatic transparent declaration is allowed without an explicit variable declaration. Currently this
|
||||
* is only the case with unions with a variable based switch type.
|
||||
* @return Returns whether the definition allows an automatic transparent declaration.
|
||||
*/
|
||||
virtual bool AllowAutoTransparentDeclaration() const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Get child entity iterator if children are available and supported by the definition. Overload of
|
||||
* sdv::idl::IDefinitionEntity::GetChildren.
|
||||
* @return Returns a pointer to the child entity iterator or NULL when not available.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetChildren() override;
|
||||
|
||||
/**
|
||||
* @brief Get inheritance entity iterator if the definition was inheriting from other entities. Overload of
|
||||
* sdv::idl::IDefinitionEntity::GetInheritance.
|
||||
* @return Returns a pointer to the inheritance entity iterator or NULL when not available.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetInheritance() override;
|
||||
|
||||
/**
|
||||
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
|
||||
* @param[in, out] rHash Hash object to be filled with data.
|
||||
*/
|
||||
virtual void CalcHash(CHashObject& rHash) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the declaration members.
|
||||
* @return List of declaration members.
|
||||
*/
|
||||
const CEntityList GetDeclMembers() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Add the child to the children list. Called by CreateChild function. Overload of CEntity::AddChild.
|
||||
* @param[in] ptrChild Pointer to the child entity to add.
|
||||
*/
|
||||
virtual void AddChild(CEntityPtr ptrChild) override;
|
||||
|
||||
/**
|
||||
* @brief Find the entity locally by looking in the entity children map and the entity children maps of all the chained
|
||||
* entities. The search is done case-insensitive. Overload of CEntity::FindLocal.
|
||||
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
|
||||
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
|
||||
* the reuse of names between declarations and definitions.
|
||||
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
|
||||
* boolean that indicates that the entity was from an inherited entity.
|
||||
*/
|
||||
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overridable when supporting content values.
|
||||
* @details When supporting value assignments, create the value node and assign the value node to the ValueRef() reference. For
|
||||
* definitions that do not support value assignments, do nothing (default).
|
||||
*/
|
||||
virtual void CreateValueNode() {};
|
||||
|
||||
protected:
|
||||
CEntityVector m_vecInheritance; ///< List of base entities in the order of appearance.
|
||||
CEntityList m_lstTypeMembers; ///< List of typedef member declarations and type definitions.
|
||||
CEntityList m_lstConstMembers; ///< List of const member declarations.
|
||||
CEntityList m_lstDeclMembers; ///< List of variable member declarations.
|
||||
CEntityList m_lstAttributesOperation; ///< List with attributes and operations.
|
||||
bool m_bRequiresContent = false; ///< When set, the definition statement requires content to follow.
|
||||
bool m_bAnonymousDefinition = false; ///< When set, the entity has an anonymous generated name.
|
||||
CEntityIterator m_iteratorChildren; ///< Children iterator
|
||||
CEntityIterator m_iteratorInheritance; ///< Inheritance iterator
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(DEFINITION_ENTITY_H)
|
||||
1708
sdv_executables/sdv_idl_compiler/entities/entity_base.cpp
Normal file
1708
sdv_executables/sdv_idl_compiler/entities/entity_base.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1066
sdv_executables/sdv_idl_compiler/entities/entity_base.h
Normal file
1066
sdv_executables/sdv_idl_compiler/entities/entity_base.h
Normal file
File diff suppressed because it is too large
Load Diff
803
sdv_executables/sdv_idl_compiler/entities/entity_value.cpp
Normal file
803
sdv_executables/sdv_idl_compiler/entities/entity_value.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
#include "entity_value.h"
|
||||
#include "../exception.h"
|
||||
#include "variable_entity.h"
|
||||
#include "definition_entity.h"
|
||||
#include "../constvariant.inl"
|
||||
#include "../support.h"
|
||||
#include "../parser.h"
|
||||
|
||||
CEntityValueNode::CEntityValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
m_ptrEntity(ptrEntity), m_ptrParent(ptrParent)
|
||||
{
|
||||
if (!ptrEntity) throw CCompileException("Internal error: expected a valid entity.");
|
||||
|
||||
CLog log;
|
||||
if (!ptrParent)
|
||||
log << "The value node of '" << ptrEntity->GetName() << "' has no parent node..." << std::endl;
|
||||
else
|
||||
log << "The value node of '" << ptrEntity->GetName() << "' has a parent node..." << std::endl;
|
||||
}
|
||||
|
||||
CEntityValueNode::CEntityValueNode(const CEntityValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
m_ptrEntity(ptrEntity), m_ptrParent(ptrParent), m_vecChildren(rValueNode.m_vecChildren)
|
||||
{
|
||||
if (!ptrEntity) throw CCompileException("Internal error: expected a valid entity.");
|
||||
|
||||
CLog log;
|
||||
if (!ptrParent)
|
||||
log << "The value node of '" << ptrEntity->GetName() << "' has no parent node..." << std::endl;
|
||||
else
|
||||
log << "The value node of '" << ptrEntity->GetName() << "' has a parent node..." << std::endl;
|
||||
}
|
||||
|
||||
void CEntityValueNode::ProcessChildNodes(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log;
|
||||
log << "Processing " << m_vecChildren.size() << " child nodes..." << std::endl;
|
||||
bool bInitial = true;
|
||||
for (CValueNodePtr& rptrValue : m_vecChildren)
|
||||
{
|
||||
// Check for a comma separator.
|
||||
if (!bInitial)
|
||||
{
|
||||
if (rlstExpression.Current() != ",")
|
||||
throw CCompileException(rlstExpression.LastValid(), "Missing comma ',' for value separation.");
|
||||
++rlstExpression;
|
||||
}
|
||||
bInitial = false;
|
||||
|
||||
log << "Processing child node..." << std::endl;
|
||||
rptrValue->ProcessValueAssignment(rlstExpression);
|
||||
}
|
||||
}
|
||||
|
||||
void CEntityValueNode::AddChild(CValueNodePtr ptrChild)
|
||||
{
|
||||
CLog log;
|
||||
log << "Adding child node..." << std::endl;
|
||||
if (!ptrChild)
|
||||
throw CCompileException("Internal error: cannot add an empty child node.");
|
||||
m_vecChildren.push_back(ptrChild);
|
||||
}
|
||||
|
||||
std::string CEntityValueNode::GetDeclTypeStr(bool bResolveTypedef) const
|
||||
{
|
||||
return GetDeclEntity()->GetDeclTypeStr(bResolveTypedef);
|
||||
}
|
||||
|
||||
bool CEntityValueNode::IsConst() const
|
||||
{
|
||||
// Default implementation
|
||||
// - In case the entity is a const entity, return 'true'.
|
||||
// - Otherwise check whether the parent value is available and ask the parent if the declaration entity is a const entity.
|
||||
// - If no parent is available, this entity must be a declaration entity and is therefore not a const entity.
|
||||
if (m_ptrEntity->Get<CVariableEntity>() && m_ptrEntity->Get<CVariableEntity>()->IsReadOnly()) return true;
|
||||
if (m_ptrParent) return m_ptrParent->IsConst();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CEntityValueNode::IsDeclaration() const
|
||||
{
|
||||
// Default implementation
|
||||
return m_ptrEntity->Get<CVariableEntity>();
|
||||
}
|
||||
|
||||
CSimpleTypeValueNode::CSimpleTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CSimpleTypeValueNode::CSimpleTypeValueNode(const CSimpleTypeValueNode& rValueNode, CEntityPtr ptrEntity,
|
||||
const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_varValue(rValueNode.m_varValue),
|
||||
m_lstExpression(rValueNode.m_lstExpression), m_eValueDef(rValueNode.m_eValueDef)
|
||||
{}
|
||||
|
||||
CValueNodePtr CSimpleTypeValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
|
||||
{
|
||||
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
|
||||
}
|
||||
|
||||
void CSimpleTypeValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log("Processing declaration value assignment...");
|
||||
|
||||
if (!m_ptrEntity) throw CCompileException("Internal error: no entity assigned to the value node.");
|
||||
|
||||
const CDeclarationEntity* pSystemTypeEntity = m_ptrEntity->Get<CDeclarationEntity>();
|
||||
if (!pSystemTypeEntity)
|
||||
throw CCompileException("Internal error: type mismatch between value node and entity type.");
|
||||
|
||||
// Process the assignment expression and convert the result in the target type.
|
||||
std::pair<CConstVariant, bool> prValue{0, false};
|
||||
switch (pSystemTypeEntity->GetBaseType())
|
||||
{
|
||||
case sdv::idl::EDeclType::decltype_short:
|
||||
log << "Processing system type value node of type 'int16/short'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<int16_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_long:
|
||||
log << "Processing system type value node of type 'int32/long'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<int32_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_long_long:
|
||||
log << "Processing system type value node of type 'int64/long long'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<int64_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_short:
|
||||
log << "Processing system type value node of type 'uint16/unsigned short'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint16_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long:
|
||||
log << "Processing system type value node of type 'uint32/unsigned long'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint32_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long_long:
|
||||
log << "Processing system type value node of type 'uint64/unsigned long long'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint64_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_char:
|
||||
log << "Processing system type value node of type 'int8/UTF-8 or ASCII char'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<int8_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_char16:
|
||||
log << "Processing system type value node of type 'UTF-16 char'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint16_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_char32:
|
||||
log << "Processing system type value node of type 'UTF-32 char'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint32_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_wchar:
|
||||
log << "Processing system type value node of type 'wchar'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
if (sizeof(wchar_t) == 2)
|
||||
prValue.first.Convert<uint16_t>();
|
||||
else
|
||||
prValue.first.Convert<uint32_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_float:
|
||||
log << "Processing system type value node of type 'float'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<float>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_double:
|
||||
log << "Processing system type value node of type 'double'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<double>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_long_double:
|
||||
log << "Processing system type value node of type 'long double'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<long double>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_fixed:
|
||||
log << "Processing system type value node of type 'fixed'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<fixed>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_boolean:
|
||||
log << "Processing system type value node of type 'boolean'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<bool>();
|
||||
log << "Simple type value node has calculated value " << (prValue.first.Get<bool>() ? "'true'" : "'false'") << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_native:
|
||||
log << "Processing system type value node of type 'native'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<size_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<size_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_octet:
|
||||
log << "Processing system type value node of type 'uint8/octet'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
|
||||
prValue.first.Convert<uint8_t>();
|
||||
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_string:
|
||||
log << "Processing system type value node of type 'ASCII string'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
|
||||
prValue.first.Convert<std::string>();
|
||||
log << "Simple type value node has constructed string \"" << prValue.first.Get<std::string>() << "\"..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_u8string:
|
||||
log << "Processing system type value node of type 'UTF-8 string'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
|
||||
prValue.first.Convert<std::string>();
|
||||
log << "Simple type value node has constructed string \"" << prValue.first.Get<std::string>() << "\"..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_u16string:
|
||||
log << "Processing system type value node of type 'UTF-16 string'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
|
||||
prValue.first.Convert<std::u16string>();
|
||||
log << "Simple type value node has constructed string..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_u32string:
|
||||
log << "Processing system type value node of type 'UTF-32 string'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
|
||||
prValue.first.Convert<std::u32string>();
|
||||
log << "Simple type value node has constructed string..." << std::endl;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_wstring:
|
||||
log << "Processing system type value node of type 'wstring'..." << std::endl;
|
||||
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
|
||||
prValue.first.Convert<std::wstring>();
|
||||
log << "Simple type value node has constructed string..." << std::endl;
|
||||
break;
|
||||
default:
|
||||
log << "Processing system type value node of unknown type..." << std::endl;
|
||||
throw CCompileException("Internal error: expression build error.");
|
||||
}
|
||||
|
||||
// Check for a dynamic result
|
||||
if (prValue.second)
|
||||
SetDynamicValue(rlstExpression);
|
||||
else
|
||||
SetFixedValue(prValue.first, rlstExpression);
|
||||
}
|
||||
|
||||
void CSimpleTypeValueNode::SetFixedValue(const CConstVariant& rvarValue, const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log;
|
||||
switch (m_eValueDef)
|
||||
{
|
||||
case EValueDef::dynamic:
|
||||
log << "The value was re-assigned; the previous value was a dynamic value..." << std::endl;
|
||||
break;
|
||||
case EValueDef::fixed:
|
||||
log << "The value was re-assigned; the previous value was a fixed value of " <<
|
||||
m_varValue.GetAsString() << "..." << std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_eValueDef = EValueDef::fixed;
|
||||
|
||||
log << "The system type value node was set to a fixed value of " << rvarValue.GetAsString() << "..." << std::endl;
|
||||
|
||||
m_varValue = rvarValue;
|
||||
m_lstExpression = rlstExpression;
|
||||
}
|
||||
|
||||
void CSimpleTypeValueNode::SetDynamicValue(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log;
|
||||
switch (m_eValueDef)
|
||||
{
|
||||
case EValueDef::dynamic:
|
||||
log << "The value was re-assigned; the previous value was a dynamic value..." << std::endl;
|
||||
break;
|
||||
case EValueDef::fixed:
|
||||
log << "The value was re-assigned; the previous value was a fixed value of " <<
|
||||
m_varValue.GetAsString() << "..." << std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_eValueDef = EValueDef::dynamic;
|
||||
|
||||
log << "The system type value node was set to a dynamic value..." << std::endl;
|
||||
|
||||
m_lstExpression = rlstExpression;
|
||||
}
|
||||
|
||||
CArrayValueNode::CArrayValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CArrayValueNode::CArrayValueNode(const CArrayValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_lstArraySizeExpression(rValueNode.m_lstArraySizeExpression),
|
||||
m_eSizeDef(rValueNode.m_eSizeDef)
|
||||
{
|
||||
m_vecChildren = rValueNode.m_vecChildren;
|
||||
}
|
||||
|
||||
CValueNodePtr CArrayValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
|
||||
{
|
||||
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
|
||||
}
|
||||
|
||||
void CArrayValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log("Process array value node...");
|
||||
|
||||
if (rlstExpression.End())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Expecting left curly bracket '{'");
|
||||
|
||||
// The array assignment is placed between brackets.
|
||||
// In case the type is a character, the array might also be defined as a string literal
|
||||
// Or identified as a value sequence.
|
||||
|
||||
if (rlstExpression.Current() == "{")
|
||||
{
|
||||
// Skip the bracket
|
||||
++rlstExpression;
|
||||
|
||||
// Process the child nodes
|
||||
ProcessChildNodes(rlstExpression);
|
||||
|
||||
// Expecting '}'
|
||||
if (rlstExpression.End() || rlstExpression.Current() != "}")
|
||||
throw CCompileException(rlstExpression.LastValid(), "Expecting right curly bracket '}'");
|
||||
++rlstExpression;
|
||||
}
|
||||
else if (rlstExpression.Current().GetType() == ETokenType::token_literal && rlstExpression.Current().IsString())
|
||||
{
|
||||
// Process the string node
|
||||
ProcessStringNode(rlstExpression.Current());
|
||||
++rlstExpression;
|
||||
}
|
||||
else
|
||||
throw CCompileException(rlstExpression.LastValid(), "Expecting left curly bracket '{'");
|
||||
}
|
||||
|
||||
void CArrayValueNode::ProcessChildNodes(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log;
|
||||
CValueNodePtr ptrValueTemplateUnbound;
|
||||
if (IsUnbound())
|
||||
{
|
||||
// The array should have one node. This is a template for all the nodes.
|
||||
if (m_vecChildren.size() != 1)
|
||||
throw CCompileException(rlstExpression.LastValid(), "Internal error: the size of the array value nodes is not as expected for the"
|
||||
" unbound array.");
|
||||
ptrValueTemplateUnbound = std::move(m_vecChildren[0]);
|
||||
|
||||
log << "Processing ubound element nodes..." << std::endl;
|
||||
}
|
||||
else
|
||||
log << "Processing " << m_vecChildren.size() << " element nodes..." << std::endl;
|
||||
|
||||
size_t nIndex = 0;
|
||||
while (!rlstExpression.End() && rlstExpression.Current() != "}")
|
||||
{
|
||||
// Check for a comma separator.
|
||||
if (nIndex)
|
||||
{
|
||||
if (rlstExpression.Current() != ",")
|
||||
throw CCompileException(rlstExpression.LastValid(), "Missing comma ',' for value separation.");
|
||||
++rlstExpression;
|
||||
}
|
||||
|
||||
// Extend the array for unbound
|
||||
if (IsUnbound())
|
||||
{
|
||||
m_vecChildren.resize(nIndex + 1);
|
||||
m_vecChildren[nIndex] = ptrValueTemplateUnbound->CreateCopy(m_ptrEntity, shared_from_this());
|
||||
}
|
||||
|
||||
// Does the size fit?
|
||||
if (nIndex >= m_vecChildren.size())
|
||||
throw CCompileException(rlstExpression.LastValid(), "The assignment doesn't fit the amount of elements.");
|
||||
|
||||
log << "Processing element node #" << nIndex << std::endl;
|
||||
m_vecChildren[nIndex]->ProcessValueAssignment(rlstExpression);
|
||||
|
||||
// Next node
|
||||
nIndex++;
|
||||
}
|
||||
|
||||
// Check whether the index corresponds to the size of the aray.
|
||||
if (nIndex != m_vecChildren.size())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Missing elements for array assignment.");
|
||||
}
|
||||
|
||||
void CArrayValueNode::ProcessStringNode(const CToken& rToken)
|
||||
{
|
||||
CLog log;
|
||||
|
||||
if (!rToken.IsString())
|
||||
throw CCompileException(rToken, "Internal error: token is expected to be a string literal.");
|
||||
|
||||
|
||||
// Check for unbound arrays.
|
||||
CValueNodePtr ptrValueTemplateUnbound;
|
||||
if (IsUnbound())
|
||||
{
|
||||
// The array should have one node. This is a template for all the nodes.
|
||||
if (m_vecChildren.size() != 1)
|
||||
throw CCompileException(rToken, "Internal error: the size of the array value nodes is not as expected for the"
|
||||
" unbound array.");
|
||||
ptrValueTemplateUnbound = std::move(m_vecChildren[0]);
|
||||
|
||||
log << "Processing ubound element nodes..." << std::endl;
|
||||
}
|
||||
else
|
||||
log << "Processing " << m_vecChildren.size() << " element nodes..." << std::endl;
|
||||
|
||||
// Determine the start position of the string
|
||||
const std::string ssValue = static_cast<std::string>(rToken);
|
||||
size_t nStart = ssValue.find('"');
|
||||
if (nStart == std::string::npos)
|
||||
throw CCompileException(rToken, "Internal error: invalid string token.");
|
||||
nStart++;
|
||||
|
||||
// For raw string, determine the delimiter
|
||||
std::string ssDelimiter = "\"";
|
||||
bool bRaw = false;
|
||||
if (rToken.IsRawString())
|
||||
{
|
||||
bRaw = true;
|
||||
size_t nStart2 = ssValue.find('(', nStart);
|
||||
if (nStart2 == std::string::npos)
|
||||
throw CCompileException(rToken, "Internal error: invalid raw string token.");
|
||||
ssDelimiter = ")" + ssValue.substr(nStart, nStart2 - nStart) + "\"";
|
||||
nStart = nStart2;
|
||||
}
|
||||
|
||||
// Check whether the base type corresponds to the string and count the characters.
|
||||
bool bError = true;
|
||||
uint32_t uiByteCnt = 0;
|
||||
std::vector<CConstVariant> lstValues;
|
||||
switch (GetDeclEntity()->GetBaseType())
|
||||
{
|
||||
case sdv::idl::EDeclType::decltype_char:
|
||||
{
|
||||
if (!rToken.IsAscii() && !rToken.IsUtf8()) break;
|
||||
bError = false;
|
||||
std::string ssText;
|
||||
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw, rToken.IsAscii());
|
||||
for (char c : ssText)
|
||||
lstValues.push_back(c);
|
||||
break;
|
||||
}
|
||||
case sdv::idl::EDeclType::decltype_wchar:
|
||||
{
|
||||
if (!rToken.IsWide()) break;
|
||||
bError = false;
|
||||
std::wstring ssText;
|
||||
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
|
||||
for (wchar_t c : ssText)
|
||||
lstValues.push_back(c);
|
||||
break;
|
||||
}
|
||||
case sdv::idl::EDeclType::decltype_char16:
|
||||
{
|
||||
if (!rToken.IsUtf16()) break;
|
||||
bError = false;
|
||||
std::u16string ssText;
|
||||
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
|
||||
for (char16_t c : ssText)
|
||||
lstValues.push_back(c);
|
||||
break;
|
||||
}
|
||||
case sdv::idl::EDeclType::decltype_char32:
|
||||
{
|
||||
if (!rToken.IsUtf32()) break;
|
||||
bError = false;
|
||||
std::u32string ssText;
|
||||
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
|
||||
for (char32_t c : ssText)
|
||||
lstValues.push_back(c);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw CCompileException(rToken, "Expecting left curly bracket '{'");
|
||||
break;
|
||||
}
|
||||
if (bError)
|
||||
throw CCompileException(rToken, "Invalid string type for the assignment");
|
||||
|
||||
// Add the terminateing zero
|
||||
lstValues.push_back(0);
|
||||
|
||||
// Extend the array for unbound
|
||||
if (IsUnbound())
|
||||
{
|
||||
m_vecChildren.resize(lstValues.size());
|
||||
for (size_t nIndex = 0; nIndex < lstValues.size(); nIndex++)
|
||||
m_vecChildren[nIndex] = ptrValueTemplateUnbound->CreateCopy(m_ptrEntity, shared_from_this());
|
||||
}
|
||||
|
||||
// Does the size fit?
|
||||
if (lstValues.size() != m_vecChildren.size())
|
||||
throw CCompileException(rToken, "The assignment doesn't fit the amount of elements.");
|
||||
|
||||
// Assign the values
|
||||
for (size_t nIndex = 0; nIndex < m_vecChildren.size(); nIndex++)
|
||||
{
|
||||
log << "Processing element node #" << nIndex << std::endl;
|
||||
CSimpleTypeValueNode* pValueNode = m_vecChildren[nIndex]->Get<CSimpleTypeValueNode>();
|
||||
if (!pValueNode)
|
||||
throw CCompileException(rToken, "Internal error: the array element is not of type simple value node.");
|
||||
|
||||
CTokenList lstExpression;
|
||||
lstExpression.push_back(rToken);
|
||||
pValueNode->SetFixedValue(lstValues[0], lstExpression);
|
||||
}
|
||||
}
|
||||
|
||||
void CArrayValueNode::SetFixedSize(size_t nSize, const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log;
|
||||
if constexpr (std::is_signed_v<size_t>)
|
||||
{
|
||||
if (static_cast<int64_t>(nSize) < 0)
|
||||
throw CCompileException("Internal error: array index is negative.");
|
||||
}
|
||||
|
||||
if (m_eSizeDef != ESizeDef::not_defined)
|
||||
throw CCompileException("Internal error: size of the value array was defined more than once.");
|
||||
m_eSizeDef = ESizeDef::fixed;
|
||||
|
||||
// Allocate the array with empty value pointers.
|
||||
m_vecChildren.resize(nSize);
|
||||
log << "Array set to a fixed size of " << nSize << "..." << std::endl;
|
||||
|
||||
// Copy the token list resulting in the size.
|
||||
m_lstArraySizeExpression = rlstExpression;
|
||||
}
|
||||
|
||||
void CArrayValueNode::SetDynamicSize(size_t nSize, const CTokenList& rlstExpression)
|
||||
{
|
||||
if (IsConst()) throw CCompileException("Cannot use a value of a variable declaration as size within a const declaration.");
|
||||
|
||||
CLog log;
|
||||
if (m_eSizeDef != ESizeDef::not_defined)
|
||||
throw CCompileException("Internal error: size of the value array was defined more than once.");
|
||||
m_eSizeDef = ESizeDef::dynamic;
|
||||
|
||||
// Allocate the array with one element.
|
||||
m_vecChildren.resize(nSize);
|
||||
log << "Array set to a dynamic size based on a variable of " << nSize << "..." << std::endl;
|
||||
|
||||
// Copy the token list resulting in the size.
|
||||
m_lstArraySizeExpression = rlstExpression;
|
||||
}
|
||||
|
||||
void CArrayValueNode::SetFixedSizeUnbound()
|
||||
{
|
||||
CLog log;
|
||||
if (m_eSizeDef != ESizeDef::not_defined)
|
||||
throw CCompileException("Internal error: size of the value array was defined more than once.");
|
||||
|
||||
m_eSizeDef = ESizeDef::fixed_unbound;
|
||||
|
||||
// Allocate the array with one element.
|
||||
m_vecChildren.resize(1);
|
||||
log << "Array set to be unbound..." << std::endl;
|
||||
}
|
||||
|
||||
const CValueNodePtr& CArrayValueNode::operator[](size_t nIndex) const
|
||||
{
|
||||
if (m_eSizeDef == ESizeDef::not_defined)
|
||||
throw CCompileException("Internal error: accessing the array can only take place after the size has been defined.");
|
||||
|
||||
if constexpr (std::is_signed_v<size_t>)
|
||||
{
|
||||
if (static_cast<int64_t>(nIndex) < 0)
|
||||
throw CCompileException("Internal error: array index is negative.");
|
||||
}
|
||||
|
||||
return m_vecChildren[nIndex];
|
||||
}
|
||||
|
||||
CValueNodePtr& CArrayValueNode::operator[](size_t nIndex)
|
||||
{
|
||||
if (m_eSizeDef == ESizeDef::not_defined)
|
||||
throw CCompileException("Internal error: accessing the array can only take place after the size has been defined.");
|
||||
|
||||
if constexpr (std::is_signed_v<size_t>)
|
||||
{
|
||||
if (static_cast<int64_t>(nIndex) < 0)
|
||||
throw CCompileException("Internal error: array index is negative.");
|
||||
}
|
||||
|
||||
return m_vecChildren[nIndex];
|
||||
}
|
||||
|
||||
size_t CArrayValueNode::GetSize() const
|
||||
{
|
||||
return m_vecChildren.size();
|
||||
}
|
||||
|
||||
bool CArrayValueNode::IsArray() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CArrayValueNode::IsUnbound() const
|
||||
{
|
||||
return m_eSizeDef == ESizeDef::fixed_unbound;
|
||||
}
|
||||
|
||||
std::string CArrayValueNode::GetSizeExpression() const
|
||||
{
|
||||
if (IsUnbound()) return std::string();
|
||||
std::string ss;
|
||||
for (const CToken& rtoken : m_lstArraySizeExpression)
|
||||
ss += static_cast<std::string>(rtoken);
|
||||
return ss;
|
||||
}
|
||||
|
||||
std::string CArrayValueNode::GetDeclTypeStr(bool bResolveTypedef) const
|
||||
{
|
||||
if (!GetSize()) return "[]"; // Not resolved yet...
|
||||
|
||||
CValueNodePtr ptrValue = (*this)[0];
|
||||
if (!ptrValue) return std::string("[" + std::to_string(GetSize()) + "]"); // Not resolved yet...
|
||||
return ptrValue->GetDeclTypeStr(bResolveTypedef) + "[" + std::to_string(GetSize()) + "]";
|
||||
}
|
||||
|
||||
CCompoundTypeValueNode::CCompoundTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CCompoundTypeValueNode::CCompoundTypeValueNode(const CCompoundTypeValueNode& rValueNode, CEntityPtr ptrEntity,
|
||||
const CValueNodePtr ptrParent) : CEntityValueNode(rValueNode, ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CValueNodePtr CCompoundTypeValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
|
||||
{
|
||||
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
|
||||
}
|
||||
|
||||
void CCompoundTypeValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log("Processing struct value node...");
|
||||
|
||||
if (rlstExpression.End())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Missing assignment");
|
||||
if (!m_ptrEntity)
|
||||
throw CCompileException(rlstExpression.LastValid(), "Internal error: a value node should be assigned to an entity.");
|
||||
|
||||
// There are two options: either a scoped name representing a type (or typedef) being of the same type (identical name), or a
|
||||
// compound value (between curly brackets '{...}').
|
||||
if (rlstExpression.Current() != "{") // Type value assignment
|
||||
{
|
||||
CValueNodePtr ptrValue = m_ptrEntity->FindValue(rlstExpression);
|
||||
|
||||
// Check if the original type of the assginee and the assigned are identical. For this both entities must be declarations.
|
||||
if (!GetDeclEntity()->Get<CDeclarationEntity>())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Internal error: the assignee entity must be a declaration entity.");
|
||||
|
||||
// Assignment can only work if the types are identical. This is regardless of the typedefs that have been made from the
|
||||
// type.
|
||||
if (GetDeclTypeStr(true) != ptrValue->GetDeclTypeStr(true))
|
||||
throw CCompileException(rlstExpression.LastValid(), "For '", GetDeclEntity()->GetName(), "', cannot assign '",
|
||||
ptrValue->GetDeclTypeStr(true), "' to '", ptrValue->GetDeclTypeStr(true), "'; base types are different.");
|
||||
|
||||
// Replace the value by the value chain of the assigned to the assignee.
|
||||
m_ptrEntity->ValueRef() = ptrValue->CreateCopy(m_ptrEntity, m_ptrParent);
|
||||
} else // Compound value assignment
|
||||
{
|
||||
++rlstExpression; // Skip left bracket
|
||||
|
||||
// Process the child nodes
|
||||
ProcessChildNodes(rlstExpression);
|
||||
|
||||
// Expecting '}'
|
||||
if (rlstExpression.End() || rlstExpression.Current() != "}")
|
||||
throw CCompileException(rlstExpression.LastValid(), "Expecting right curly bracket '}'");
|
||||
++rlstExpression; // Skip right bracket
|
||||
}
|
||||
}
|
||||
|
||||
CInterfaceValueNode::CInterfaceValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CInterfaceValueNode::CInterfaceValueNode(const CInterfaceValueNode& rValueNode, CEntityPtr ptrEntity,
|
||||
const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(rValueNode, ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CValueNodePtr CInterfaceValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
|
||||
{
|
||||
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
|
||||
}
|
||||
|
||||
void CInterfaceValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log("Processing declaration value assignment...");
|
||||
|
||||
if (!m_ptrEntity) throw CCompileException("Internal error: no entity assigned to the value node.");
|
||||
|
||||
const CDeclarationEntity* pSystemTypeEntity = m_ptrEntity->Get<CDeclarationEntity>();
|
||||
if (!pSystemTypeEntity)
|
||||
throw CCompileException("Internal error: type mismatch between value node and entity type.");
|
||||
|
||||
// Only "null" and "0" are allowed.
|
||||
if ((!m_ptrEntity->GetParserRef().GetEnvironment().InterfaceTypeExtension() || rlstExpression.Current() != "null") &&
|
||||
rlstExpression.Current() != "0")
|
||||
throw CCompileException(rlstExpression.Current(),
|
||||
"Error: assignment of interface values is only possible with the value \"null\".");
|
||||
|
||||
// Skip the value.
|
||||
++rlstExpression;
|
||||
}
|
||||
|
||||
|
||||
CValueNodePtr CCompoundTypeValueNode::Member(const std::string& rssName) const
|
||||
{
|
||||
// Check the entity names of the child value nodes.
|
||||
// ATTENTION: The child value nodes are copies of the original definition. They still contain the link to the declarations
|
||||
// that were part of the definition. The entity belonging to a declaration of a compound type does not have any children (the
|
||||
// entity itself is just the declaration and not the definition):
|
||||
for (const CValueNodePtr& rptrValue : m_vecChildren)
|
||||
if (rptrValue->GetDeclEntity()->GetName() == rssName) return rptrValue;
|
||||
return nullptr; // Value not found.
|
||||
}
|
||||
|
||||
CEnumValueNode::CEnumValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(ptrEntity, ptrParent)
|
||||
{}
|
||||
|
||||
CEnumValueNode::CEnumValueNode(const CEnumValueNode& rValueNode, CEntityPtr ptrEntity,
|
||||
const CValueNodePtr ptrParent) :
|
||||
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_ptrEntryVal(rValueNode.m_ptrEntryVal),
|
||||
m_lstExpression(rValueNode.m_lstExpression)
|
||||
{}
|
||||
|
||||
CValueNodePtr CEnumValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
|
||||
{
|
||||
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
|
||||
}
|
||||
|
||||
void CEnumValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
|
||||
{
|
||||
CLog log("Processing enum value assignment...");
|
||||
// The assignment is done using the enum entry type. Find the scoped name. This could be the enum value. Check the type first.
|
||||
CTokenList rlstExpressionTemp = rlstExpression;
|
||||
std::pair<std::string, CEntityPtr> prEntity = GetDeclEntity()->GetTypeEntity()->ProcessScopedName(rlstExpression, true);
|
||||
// If not an enum value from the type, use as scope the parent of the current enum to search for other declarations.
|
||||
if (!prEntity.second) prEntity = GetDeclEntity()->GetParentEntity()->ProcessScopedName(rlstExpressionTemp, true);
|
||||
if (!prEntity.second) throw CCompileException(rlstExpression.LastValid(), "Expecting an enum value.");
|
||||
|
||||
// This could either be an assignment of an enum to another enum or an enum entry to an enum.
|
||||
log << "The to be assigned type is '" << prEntity.second->GetDeclTypeStr(true) << "'..." << std::endl;
|
||||
log << "The assignee type is '" << GetDeclEntity()->GetDeclTypeStr(true) << "'..." << std::endl;
|
||||
if (prEntity.second->GetDeclTypeStr(true) == GetDeclEntity()->GetDeclTypeStr(true))
|
||||
{
|
||||
if (!prEntity.second->ValueRef())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Internal error: the enum doesn't have an assigned value.");
|
||||
if (!prEntity.second->ValueRef()->Get<CEnumValueNode>())
|
||||
throw CCompileException(rlstExpression.LastValid(), "Internal error: the enum doesn't have an assigned enum value.");
|
||||
m_ptrEntryVal = prEntity.second->ValueRef()->Get<CEnumValueNode>()->m_ptrEntryVal;
|
||||
} else if (prEntity.second->GetParentEntity()->GetDeclTypeStr(true) == GetDeclEntity()->GetDeclTypeStr(true))
|
||||
{
|
||||
log << "Assigning enum entry..." << std::endl;
|
||||
m_ptrEntryVal = prEntity.second;
|
||||
} else
|
||||
throw CCompileException(rlstExpression.LastValid(), "Invalid enum value; enum types are not identical.");
|
||||
log << "Enum entity was assigned value '" << m_ptrEntryVal->GetParentEntity()->GetName() << "::" <<
|
||||
m_ptrEntryVal->GetName() << "'..." << std::endl;
|
||||
}
|
||||
|
||||
const CConstVariant& CEnumValueNode::Variant() const
|
||||
{
|
||||
static CConstVariant temp;
|
||||
if (!m_ptrEntryVal) return temp;
|
||||
if (!m_ptrEntryVal->ValueRef()) return temp;
|
||||
const CSimpleTypeValueNode* pValueNode = m_ptrEntryVal->ValueRef()->Get<CSimpleTypeValueNode>();
|
||||
if (!pValueNode) return temp;
|
||||
return pValueNode->Variant();
|
||||
}
|
||||
|
||||
std::string CEnumValueNode::String() const
|
||||
{
|
||||
if (!m_ptrEntryVal) return std::string();
|
||||
return m_ptrEntryVal->GetParentEntity()->GetScopedName() + "::" + m_ptrEntryVal->GetName();
|
||||
}
|
||||
584
sdv_executables/sdv_idl_compiler/entities/entity_value.h
Normal file
584
sdv_executables/sdv_idl_compiler/entities/entity_value.h
Normal file
@@ -0,0 +1,584 @@
|
||||
#ifndef ENTITIY_VALUE_H
|
||||
#define ENTITIY_VALUE_H
|
||||
|
||||
#include "entity_base.h"
|
||||
#include "../constvariant.h"
|
||||
#include "../token.h"
|
||||
#include "../tokenlist.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
// Forward declarations
|
||||
class CDeclarationEntity;
|
||||
|
||||
/**
|
||||
* @brief The entity value node base class.
|
||||
* @details Entity values form a value tree made of all the values that are part of one assignment. Each value has its special
|
||||
* value grammar when used in a assignment. All entities have their own personal linked list, which can be formed from other
|
||||
* entities when they are defined as type of a declaration. Variable declarations can also be part of a larger linked list. Arrays
|
||||
* form their own links within the linked list
|
||||
* Examples:
|
||||
* @code
|
||||
* // Value tree for i: CSimpleTypeValueNode assigning the value 10.
|
||||
* int32 i = 10;
|
||||
*
|
||||
* // Value tree for S1: CCompoundTypeValueNode with child CSimpleTypeValueNode assigning the value 20.
|
||||
* struct S1
|
||||
* {
|
||||
* const int32 m_i1 = 10; // Value node for m_i1: CSimpleTypeValueNode assigning the value 10.
|
||||
* int32 m_i2 = 20; // Part of the value tree of S1.
|
||||
* };
|
||||
*
|
||||
* // Value tree for s1: sub-tree of S1 assigning the value 200 to m_i2.
|
||||
* S1 s1 = {200};
|
||||
*
|
||||
* // Value tree for S2: CCompoundTypeValueNode with children sub-tree of S1 and CSimpleTypeValueNode assigning the value 5.
|
||||
* struct S2 : S1
|
||||
* {
|
||||
* int32 m_i3 = 5; // Part of value tree of S2.
|
||||
* };
|
||||
*
|
||||
* // Value tree for s2: sub-tree of S2 assigning the value 150 to S1 and 100 to m_i3.
|
||||
* s2 = {{150}, 100};
|
||||
*
|
||||
* // Value tree for rgi: CArrayValueNode having two children assigning the value 10 and 20.
|
||||
* int32 rgi[2] = {10, 20};
|
||||
*
|
||||
* // Value tree for rgs3: CarrayValueNode having two children S1 assigning the values 1000 and 2000.
|
||||
* S1 rgs3[2] = {{1000}, {2000}};
|
||||
* @endcode
|
||||
*/
|
||||
class CEntityValueNode : public std::enable_shared_from_this<CEntityValueNode>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for const and declaration entities or when
|
||||
* creating a value node for a definition which will be copied in a larger declaration at a later stage.
|
||||
*/
|
||||
CEntityValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CEntityValueNode(const CEntityValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CEntityValueNode() = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Prototype to be implemented from derived class.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Prototype, to be implemented by derived value class.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) = 0;
|
||||
|
||||
/**
|
||||
* @brief Process the child nodes.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessChildNodes(const CTokenList& rlstExpression);
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Get the derived value class.
|
||||
* @tparam TValue The value class to request a pointer for.
|
||||
* @return Returns a pointer to the derived class or NULL when the requested class didn't derive from this value.
|
||||
*/
|
||||
template <class TValue>
|
||||
TValue* Get();
|
||||
template <class TValue>
|
||||
const TValue* Get() const;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add a child node
|
||||
* @param[in] ptrChild Pointer to the child value node.
|
||||
*/
|
||||
void AddChild(CValueNodePtr ptrChild);
|
||||
|
||||
/**
|
||||
* @brief Get the parent node.
|
||||
* @return Returns a reference to the smart pointer of the parent node (if assigned).
|
||||
*/
|
||||
const CValueNodePtr& GetParentNode() const { return m_ptrParent; }
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Get the attached declaration entity.
|
||||
* @return Returns the smart pointer to the entity.
|
||||
*/
|
||||
const CDeclarationEntity* GetDeclEntity() const { return m_ptrEntity->Get<CDeclarationEntity>(); }
|
||||
CDeclarationEntity* GetDeclEntity() { return m_ptrEntity->Get<CDeclarationEntity>(); }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type build from the value chain.
|
||||
* @details The declaration type consists of "<base type> <type identifier> <arrays>".
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with entity type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Information functions.
|
||||
* @details Each function is implemented by an entity value class. The IsConst function traverses through the parents to find
|
||||
* out whether or not a value is a const value (this is the case when the entity holding the top most value is a const
|
||||
* entity.)
|
||||
* @return Returns the information.
|
||||
*/
|
||||
virtual bool IsArray() const { return false; }
|
||||
virtual bool IsUnbound() const { return false; }
|
||||
virtual bool IsConst() const;
|
||||
virtual bool IsDeclaration() const;
|
||||
virtual bool IsDynamic() const { return false; }
|
||||
virtual bool IsLiteral() const { return false; }
|
||||
virtual bool IsComplex() const { return false; }
|
||||
virtual bool HasParent() const{ return m_ptrParent ? true : false; }
|
||||
virtual bool HasChildren() const{ return !m_vecChildren.empty(); }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
protected:
|
||||
CEntityPtr m_ptrEntity; ///< The entity implementing the value type.
|
||||
const CValueNodePtr m_ptrParent; ///< Parent value node - can be nullptr for root node.
|
||||
std::vector<CValueNodePtr> m_vecChildren; ///< Child nodes.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Entity declaration value (used as const variable assignment as well as default declaration assignment).
|
||||
*/
|
||||
class CSimpleTypeValueNode : public CEntityValueNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
|
||||
*/
|
||||
CSimpleTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CSimpleTypeValueNode(const CSimpleTypeValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CSimpleTypeValueNode() override = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Set to a fixed value.
|
||||
* @remarks In case the entity is not a const entity, the value is considered to be a default value.
|
||||
* @param[in] rvarValue Reference to the fixed value.
|
||||
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
|
||||
*/
|
||||
void SetFixedValue(const CConstVariant& rvarValue, const CTokenList& rlstExpression);
|
||||
|
||||
/**
|
||||
* @brief Set to a dynamic value
|
||||
* @remarks This function can only be called when the entity of any of the parent entities is not a const entity.
|
||||
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
|
||||
*/
|
||||
void SetDynamicValue(const CTokenList& rlstExpression);
|
||||
|
||||
/**
|
||||
* @brief Is the value defined?
|
||||
* @return Returns 'true' when the value is defined; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsDefined() const { return m_eValueDef != EValueDef::not_defined; }
|
||||
|
||||
/**
|
||||
* @brief Is this value dynamic (will it be defined through a non-const variable definition)?
|
||||
* @return Returns 'true' when the value is dynamic; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsDynamic() const override { return m_eValueDef != EValueDef::dynamic; }
|
||||
|
||||
/**
|
||||
* @brief Get access to the underlying const variant.
|
||||
* @return The const variant storing the calculated value.
|
||||
*/
|
||||
const CConstVariant &Variant() const { return m_varValue; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The definition of the size is either fixed or not fixed. When it is fixed, it could be derived from assigning its
|
||||
* values.
|
||||
*/
|
||||
enum class EValueDef
|
||||
{
|
||||
not_defined, ///< Currently not defined yet.
|
||||
fixed, ///< The value is fixed; could be used for const and declaration entities.
|
||||
dynamic, ///< The value is dependable on a variable declaration. Only to be used with a declaration entity.
|
||||
};
|
||||
|
||||
CConstVariant m_varValue; ///< The calculated value.
|
||||
CTokenList m_lstExpression; ///< List of tokens holding the value expression.
|
||||
EValueDef m_eValueDef = EValueDef::not_defined; ///< Dynamic value based on variables.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Entity array value (containing an array of value pointers).
|
||||
* @remarks When the array contains non-allocated value pointers, the array has been declared, but the values haven't been
|
||||
* assigned.
|
||||
*/
|
||||
class CArrayValueNode : public CEntityValueNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CArrayValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CArrayValueNode(const CArrayValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CArrayValueNode() override = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Process the child nodes. Overload of CEntityValueNode::ProcessChildNodes.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
void ProcessChildNodes(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Process the string nodes. This is an array processing function based on a string as character array.
|
||||
* @param[in] rToken Reference to the string literal token.
|
||||
*/
|
||||
void ProcessStringNode(const CToken& rToken);
|
||||
|
||||
/**
|
||||
* @brief Set the fixed size of the array when available during declaration.
|
||||
* @attention Must not be called after the value has been set to dynamic or set to a delayed fixed size.
|
||||
* @param[in] nSize The calculated size of the array.
|
||||
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
|
||||
*/
|
||||
void SetFixedSize(size_t nSize, const CTokenList& rlstExpression);
|
||||
|
||||
/**
|
||||
* @brief Set the array to a dynamic size based on a variable declaration. This is only allowed for entities that are not
|
||||
* declared as const entity (where all the parent values are not defined as const).
|
||||
* @attention Must not be called after the value has been set to a fixed size (delayed or not).
|
||||
* @param[in] nSize The calculated size of the array.
|
||||
* @param[in] rlstExpression Reference to the expression list used to calculate the size.
|
||||
*/
|
||||
void SetDynamicSize(size_t nSize, const CTokenList& rlstExpression);
|
||||
|
||||
/**
|
||||
* @brief Set the array to a fixed size through its value assignment. This is only allowed for entities that are declared as
|
||||
* const entity (where one of the parents was defined as const).
|
||||
* @attention Must not be called after the value has been set to a fixed size (not delayed) or a dynamic size.
|
||||
*/
|
||||
void SetFixedSizeUnbound();
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Element access of the array.
|
||||
* @param[in] nIndex The index of the element. For dynamic arrays, only an index of 0 is allowed.
|
||||
* @return Returns a reference to the element.
|
||||
*/
|
||||
const CValueNodePtr& operator[](size_t nIndex) const;
|
||||
CValueNodePtr& operator[](size_t nIndex);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the size of the array.
|
||||
* @return The size of the array.
|
||||
*/
|
||||
size_t GetSize() const;
|
||||
|
||||
/**
|
||||
* @brief This is an array entity.
|
||||
* @return Returns 'true'.
|
||||
*/
|
||||
virtual bool IsArray() const override;
|
||||
|
||||
/**
|
||||
* @brief Is the size of the array defined through the assignment?
|
||||
* @return Returns 'true' when the size of the array has to be defined through the assignment.
|
||||
*/
|
||||
virtual bool IsUnbound() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the size expression.
|
||||
* @return The size expression string.
|
||||
*/
|
||||
std::string GetSizeExpression() const;
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type build from the value chain. Overload of CEntityValueNode::GetDeclTypeStr.
|
||||
* @details The declaration type consists of "<base type> <type identifier> <arrays>".
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with entity type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The definition of the size is either fixed or not fixed. When it is fixed, it could be derived from assigning its
|
||||
* values.
|
||||
*/
|
||||
enum class ESizeDef
|
||||
{
|
||||
not_defined, ///< Currently not defined yet.
|
||||
fixed, ///< The size is fixed; could be used for const and declaration entities.
|
||||
dynamic, ///< The size is dependable on a variable declaration. Only to be used with a declaration entity.
|
||||
fixed_unbound, ///< The size is fixed, but gets defined during value assignment. Only to be used with a const
|
||||
///< entity.
|
||||
};
|
||||
|
||||
CTokenList m_lstArraySizeExpression; ///< List of tokens holding the array size expression.
|
||||
ESizeDef m_eSizeDef = ESizeDef::not_defined; ///< The size definition.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Entity struct value containing two arrays of value pointers, one array for the member const declarations and one array
|
||||
* for the member variable declarations.
|
||||
*/
|
||||
class CCompoundTypeValueNode : public CEntityValueNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr when creating a value node for a definition
|
||||
* which will be copied in a larger declaration at a later stage.
|
||||
*/
|
||||
CCompoundTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CCompoundTypeValueNode(const CCompoundTypeValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CCompoundTypeValueNode() override = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Return the value for the supplied member.
|
||||
* @param[in] rssName Name Reference to the string object containing the name of the member.
|
||||
* @return Returns the value node smart pointer of the requested member, or nullptr when member doesn't have a value or
|
||||
* doesn't exist.
|
||||
*/
|
||||
CValueNodePtr Member(const std::string& rssName) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Interface value node.
|
||||
* @note The only assignable values of an interface are "null" and "0". No variable is allowed to be assigned and an interface
|
||||
* cannot be const.
|
||||
*/
|
||||
class CInterfaceValueNode : public CEntityValueNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
|
||||
*/
|
||||
CInterfaceValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CInterfaceValueNode(const CInterfaceValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CInterfaceValueNode() override = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Is this value dynamic (will it be defined through a non-const variable definition)? This is always the case.
|
||||
* @return Returns 'true' when the value is dynamic; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsDynamic() const override { return true; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum entity declaration value.
|
||||
*/
|
||||
class CEnumValueNode : public CEntityValueNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
|
||||
*/
|
||||
CEnumValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor with new parent and entity.
|
||||
* @param[in] rValueNode Reference to the value node to copy from.
|
||||
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
*/
|
||||
CEnumValueNode(const CEnumValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Default destructor
|
||||
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
|
||||
*
|
||||
*/
|
||||
virtual ~CEnumValueNode() override = default;
|
||||
|
||||
/**
|
||||
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
|
||||
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
|
||||
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
|
||||
* @return Returns a smart pointer of the copy of the value.
|
||||
*/
|
||||
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
|
||||
* @param[in] rlstExpression Reference to the expression token list.
|
||||
*/
|
||||
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
|
||||
|
||||
/**
|
||||
* @brief Is the value defined?
|
||||
* @return Returns 'true' when the value is defined; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsDefined() const { return m_ptrEntryVal ? true : false; }
|
||||
|
||||
/**
|
||||
* @brief Get access to the assigned const variant of the enum entry.
|
||||
* @return The const variant storing the value.
|
||||
*/
|
||||
const CConstVariant& Variant() const;
|
||||
|
||||
/**
|
||||
* @brief Get access to the assigned name string of the enum entry.
|
||||
* @return The name string of the enum entry.
|
||||
*/
|
||||
std::string String() const;
|
||||
|
||||
private:
|
||||
CEntityPtr m_ptrEntryVal; ///< The enum entry value when assigned.
|
||||
CTokenList m_lstExpression; ///< List of tokens holding the value expression.
|
||||
};
|
||||
|
||||
template <class TValue>
|
||||
TValue* CEntityValueNode::Get()
|
||||
{
|
||||
return dynamic_cast<TValue*>(this);
|
||||
}
|
||||
|
||||
template <class TValue>
|
||||
const TValue* CEntityValueNode::Get() const
|
||||
{
|
||||
return dynamic_cast<const TValue*>(this);
|
||||
}
|
||||
|
||||
#endif // !define(ENTITY_VALUE_H)
|
||||
213
sdv_executables/sdv_idl_compiler/entities/enum_entity.cpp
Normal file
213
sdv_executables/sdv_idl_compiler/entities/enum_entity.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
#include "enum_entity.h"
|
||||
#include "entity_value.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "../exception.h"
|
||||
#include <set>
|
||||
|
||||
CEnumEntry::CEnumEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDeclarationEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
std::string CEnumEntry::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return GetScopedName();
|
||||
}
|
||||
|
||||
void CEnumEntry::Process()
|
||||
{
|
||||
// Get the base type of the enum entity and insert it in front of the declaration.
|
||||
const CEnumEntity* pEnumEntity = GetParentEntity()->Get<CEnumEntity>();
|
||||
if (!pEnumEntity) throw CCompileException("Internal error: expected an enum entity as parent.");
|
||||
CToken token(DeclTypeToString(pEnumEntity->GetEnumType()));
|
||||
PrependToken(token);
|
||||
|
||||
// Process as if normal declaration
|
||||
CDeclarationEntity::Process();
|
||||
}
|
||||
|
||||
CEnumEntity::CEnumEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDefinitionEntity(rptrContext, ptrParent)
|
||||
{
|
||||
m_typedecl.SetBaseType(sdv::idl::EDeclType::decltype_long);
|
||||
}
|
||||
|
||||
sdv::interface_t CEnumEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IEnumEntity>())
|
||||
return static_cast<sdv::idl::IEnumEntity*>(this);
|
||||
return CDefinitionEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
std::string CEnumEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return std::string("enum ") + GetScopedName();
|
||||
}
|
||||
|
||||
void CEnumEntity::GetBaseType(sdv::idl::EDeclType& reType, sdv::IInterfaceAccess*& rpType) const
|
||||
{
|
||||
reType = m_typedecl.GetBaseType();
|
||||
rpType = m_typedecl.GetTypeDefinition();
|
||||
}
|
||||
|
||||
void CEnumEntity::Process()
|
||||
{
|
||||
// The definition and declaration can be defined:
|
||||
// enum <enum_identifier>; --> forward declaration
|
||||
// enum <enum_identifier> {...}; --> enum definition
|
||||
// <enum_identifier> <decl_identifier>; --> enum variable declaration
|
||||
// <enum_identifier> <decl_identifier> = <enum_value>; --> enum variable declaration and assignment
|
||||
// enum <enum_identifier> <decl_identifier>; --> enum variable declaration
|
||||
// enum <enum_identifier> <decl_identifier> = <enum_value>; --> enum variable declaration and assignment
|
||||
// enum <enum_identifier> {...} <decl_identifier>; --> enum definition and variable declaration
|
||||
// enum <enum_identifier> {...} <decl_identifier> = <enum_value>; --> enum definition, variable declaration and assignment
|
||||
// enum {...} <decl_identifier>; --> anonymous enum definition and variable declaration
|
||||
// enum {...} <decl_identifier> = <enum_value>; --> anonymous enum definition, variable declaration and assignment
|
||||
// const enum <enum_identifier> <decl_identifier> = <enum_value>;
|
||||
// const <enum_identifier> <decl_identifier> = <enum_value>;
|
||||
// const enum {...} <decl_identifier> = <enum_value>;
|
||||
// typedef <enum_identifier> <type_identifier>;
|
||||
// typedef enum <enum_identifier> {...} <type_identifier>;
|
||||
// typedef <enum_identifier> <type_identifier>;
|
||||
// typedef enum <enum_identifier> {...} <type_identifier>;
|
||||
// typedef enum {...} <type_identifier>;
|
||||
|
||||
CDefinitionEntity::Process();
|
||||
|
||||
// If supported create the value node for the definition (this allows assignments of values to this entity).
|
||||
CreateValueNode();
|
||||
}
|
||||
|
||||
void CEnumEntity::ProcessDefinitionAddendum()
|
||||
{
|
||||
// Check for inheritance
|
||||
CToken token = GetToken();
|
||||
if (token != ":")
|
||||
{
|
||||
PrependToken(token);
|
||||
return;
|
||||
}
|
||||
|
||||
CLog log("Processing inheritance type...");
|
||||
|
||||
// Process the type
|
||||
m_typedecl = ProcessType();
|
||||
|
||||
// The base type must be an integral type and not an enum.
|
||||
if (!IsIntegralDeclType(m_typedecl.GetBaseType()) && m_typedecl.GetBaseType() != sdv::idl::EDeclType::decltype_enum)
|
||||
throw CCompileException("Expecting an integral type to inherit from.");
|
||||
}
|
||||
|
||||
void CEnumEntity::ProcessContent()
|
||||
{
|
||||
CLog log("Processing definition content...");
|
||||
|
||||
// An enum definition consists of one declaration statement with entries separated by a comma.
|
||||
CToken token = PeekToken();
|
||||
if (!token) return;
|
||||
if (token == "}") return;
|
||||
|
||||
// Expecting an enum entry
|
||||
CEntityPtr ptrEntry = CreateChild<CEnumEntry>(token.GetContext(), this);
|
||||
if (!ptrEntry) throw CCompileException("Internal error: could not create enum entry.");
|
||||
ptrEntry->Process();
|
||||
|
||||
// The entries should reside in the const members list
|
||||
// Check the values and create values where none is declared.
|
||||
// Separate between signed and unsigned.
|
||||
int64_t iSignedNext = 0;
|
||||
std::set<int64_t> setSigned;
|
||||
uint64_t uiUnsignedNext = 0;
|
||||
std::set<uint64_t> setUnsigned;
|
||||
for (CEntityPtr ptrMember : m_lstConstMembers)
|
||||
{
|
||||
CEnumEntry* pEntry = ptrMember->Get<CEnumEntry>();
|
||||
if (!pEntry) throw CCompileException("Internal error: expected only enum entries in an enumeration.");
|
||||
|
||||
// Do post processing
|
||||
pEntry->PostProcess();
|
||||
|
||||
// Get the value from the entity; if one was assigned.
|
||||
CSimpleTypeValueNode* pValue = pEntry->ValueRef() ? pEntry->ValueRef()->Get<CSimpleTypeValueNode>() : nullptr;
|
||||
if (!pValue)
|
||||
throw CCompileException("The value for '", ptrEntry->GetName(), "' must be a system type value.");
|
||||
|
||||
// Deal with signed and unsigned values
|
||||
if (IsSignedDeclType(m_typedecl.GetBaseType()))
|
||||
{
|
||||
// Is a value assigned?
|
||||
if (pValue->IsDefined())
|
||||
{
|
||||
// Check whether the value is already in use.
|
||||
int64_t iValue = pValue->Variant().Get<int64_t>();
|
||||
if (setSigned.find(iValue) != setSigned.end())
|
||||
throw CCompileException("The value for '", ptrEntry->GetName(), "' is already defined for another entry.");
|
||||
|
||||
// Store the value
|
||||
setSigned.insert(iValue);
|
||||
iSignedNext = iValue + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the next available value
|
||||
while (setSigned.find(iSignedNext) != setSigned.end())
|
||||
iSignedNext++;
|
||||
|
||||
// Create a value assignment
|
||||
CTokenList lstValueTokens;
|
||||
lstValueTokens.push_back(CToken(std::to_string(iSignedNext), ETokenLiteralType::token_literal_dec_integer));
|
||||
pValue->SetFixedValue(iSignedNext, lstValueTokens);
|
||||
|
||||
// Store the value
|
||||
setSigned.insert(iSignedNext);
|
||||
iSignedNext++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is a value assigned?
|
||||
if (pValue->IsDefined())
|
||||
{
|
||||
// Check whether the value is already in use.
|
||||
uint64_t uiValue = pValue->Variant().Get<uint64_t>();
|
||||
if (setUnsigned.find(uiValue) != setUnsigned.end())
|
||||
throw CCompileException("The value for '", ptrEntry->GetName(), "' is already defined for another entry.");
|
||||
|
||||
// Store the value
|
||||
setUnsigned.insert(uiValue);
|
||||
uiUnsignedNext = uiValue + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the next available value
|
||||
while (setUnsigned.find(uiUnsignedNext) != setUnsigned.end())
|
||||
uiUnsignedNext++;
|
||||
|
||||
// Create a value assignment
|
||||
CTokenList lstValueTokens;
|
||||
lstValueTokens.push_back(CToken(std::to_string(uiUnsignedNext), ETokenLiteralType::token_literal_dec_integer));
|
||||
pValue->SetFixedValue(uiUnsignedNext, lstValueTokens);
|
||||
|
||||
// Store the value
|
||||
setUnsigned.insert(uiUnsignedNext);
|
||||
iSignedNext++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CEnumEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_enum_entry: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CEnumEntity::CreateValueNode()
|
||||
{
|
||||
// Create a simple type value node for this definition.
|
||||
ValueRef() = std::make_shared<CEnumValueNode>(shared_from_this(), nullptr);
|
||||
}
|
||||
178
sdv_executables/sdv_idl_compiler/entities/enum_entity.h
Normal file
178
sdv_executables/sdv_idl_compiler/entities/enum_entity.h
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef ENUM_ENTITY_H
|
||||
#define ENUM_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
#include "declaration_entity.h"
|
||||
#include "variable_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The enum entry declaration.
|
||||
*/
|
||||
class CEnumEntry : public CDeclarationEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CEnumEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CEnumEntry() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns enum entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_enum_entry; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with enum type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support assignments? Overload of CDeclarationEntity::SupportAssignments.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportAssignments() const override { return true; }
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support multiple declarations on one line of code? Overload of
|
||||
* CDeclarationEntity::SupportMultipleDeclarations.
|
||||
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportMultipleDeclarations() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Do not enforce next declaration after comma (enums do)? Overload of
|
||||
* CDeclarationEntity::DoNotEnfoceNextDeclarationAfterComma.
|
||||
* @return Returns 'true' when not enforcing the next declaration; 'false' otherwise.
|
||||
*/
|
||||
virtual bool DoNotEnfoceNextDeclarationAfterComma() const override { return true; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The enum definition of an IDL file.
|
||||
* @details The enum section of the IDL file contains a list of enum value entries
|
||||
*/
|
||||
class CEnumEntity : public CDefinitionEntity, public sdv::idl::IEnumEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CEnumEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CEnumEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns enum entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_enum; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with enum type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the enumerator base type. Overload of sdv::idl::IEnumEntity.
|
||||
* @param[out] reType Reference to the declaration type. The type if EEntityType::type_unknown if not available.
|
||||
* @param[out] rpType Reference to the interface pointer if the type is a complex type. Otherwise is NULL.
|
||||
*/
|
||||
virtual void GetBaseType(sdv::idl::EDeclType& reType, sdv::IInterfaceAccess*& rpType) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Process the content of the definition.
|
||||
*/
|
||||
virtual void ProcessContent() override;
|
||||
|
||||
/**
|
||||
* @brief Process the definition addendum (following the definition statement before the content definition).
|
||||
*/
|
||||
virtual void ProcessDefinitionAddendum() override;
|
||||
|
||||
/**
|
||||
* @brief Get the enum type.
|
||||
* @return Returns the underlying enum type.
|
||||
*/
|
||||
sdv::idl::EDeclType GetEnumType() const { return m_typedecl.GetBaseType(); }
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
|
||||
* @details The struct supports children.
|
||||
* @return Returns whether the entity supports children (which is supported).
|
||||
*/
|
||||
virtual bool SupportsChildren() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support anonymous naming?
|
||||
* @details The default implementation is that anonymous naming is not supported.
|
||||
* @return Returns whether the entity supports inheritance (which is supported).
|
||||
*/
|
||||
virtual bool SupportsAnonymous() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support inheritance?
|
||||
* @details The default implementation is that inheritance is not supported.
|
||||
* @return Returns whether the entity supports inheritance (which is supported).
|
||||
*/
|
||||
virtual bool SupportsInheritance() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
|
||||
* @details Create the value node and assign the value node to the ValueRef() reference..
|
||||
*/
|
||||
virtual void CreateValueNode() override;
|
||||
|
||||
private:
|
||||
CTypeDeclaration m_typedecl; ///< The base type of the enum.
|
||||
};
|
||||
|
||||
#endif // !defined(ENUM_ENTITY_H)
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "exception_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include <iostream>
|
||||
|
||||
CExceptionEntity::CExceptionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CStructEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
std::string CExceptionEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return std::string("exception ") + GetScopedName();
|
||||
}
|
||||
|
||||
void CExceptionEntity::Process()
|
||||
{
|
||||
CStructEntity::Process();
|
||||
}
|
||||
|
||||
bool CExceptionEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_variable: return true;
|
||||
case EDefinitionSupport::support_const_variable: return true;
|
||||
case EDefinitionSupport::support_typedef: return true;
|
||||
case EDefinitionSupport::support_struct: return true;
|
||||
case EDefinitionSupport::support_union: return true;
|
||||
case EDefinitionSupport::support_enum: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CExceptionEntity::CreateValueNode()
|
||||
{
|
||||
// Create a compound type value node for this definition.
|
||||
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
|
||||
}
|
||||
62
sdv_executables/sdv_idl_compiler/entities/exception_entity.h
Normal file
62
sdv_executables/sdv_idl_compiler/entities/exception_entity.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef EXCEPTION_ENTITY_H
|
||||
#define EXCEPTION_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
#include "struct_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The struct definition of an IDL file.
|
||||
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
|
||||
* and unions.
|
||||
*/
|
||||
class CExceptionEntity : public CStructEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CExceptionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CExceptionEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return the exception entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_exception; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with exception type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
|
||||
* @details Create the value node and assign the value node to the ValueRef() reference..
|
||||
*/
|
||||
virtual void CreateValueNode() override;
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(EXCEPTION_ENTITY_H)
|
||||
39
sdv_executables/sdv_idl_compiler/entities/hash_calc.cpp
Normal file
39
sdv_executables/sdv_idl_compiler/entities/hash_calc.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "hash_calc.h"
|
||||
|
||||
CHashObject::CHashObject()
|
||||
{
|
||||
// Create a xxHash state
|
||||
m_state = XXH64_createState();
|
||||
|
||||
/* Initialize state with selected seed */
|
||||
XXH64_hash_t seed = 0; /* or any other value */
|
||||
if (XXH64_reset(m_state, seed) == XXH_ERROR)
|
||||
{
|
||||
XXH64_freeState(m_state);
|
||||
m_state = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CHashObject::~CHashObject()
|
||||
{
|
||||
if (m_state) XXH64_freeState(m_state);
|
||||
}
|
||||
|
||||
CHashObject& CHashObject::operator<<(const std::string& rssString)
|
||||
{
|
||||
if (!m_state) return *this;
|
||||
if (rssString.empty()) return *this;
|
||||
if (XXH64_update(m_state, rssString.c_str(), rssString.size()) == XXH_ERROR)
|
||||
{
|
||||
XXH64_freeState(m_state);
|
||||
m_state = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t CHashObject::GetHash() const
|
||||
{
|
||||
if (!m_state) return 0;
|
||||
XXH64_hash_t hash = XXH64_digest(m_state);
|
||||
return hash;
|
||||
}
|
||||
52
sdv_executables/sdv_idl_compiler/entities/hash_calc.h
Normal file
52
sdv_executables/sdv_idl_compiler/entities/hash_calc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef HASH_CALC_H
|
||||
#define HASH_CALC_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Prevent warnings for XXHash during static code analysis.
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26812 26451)
|
||||
#endif
|
||||
|
||||
#define XXH_INLINE_ALL
|
||||
#include <xxhash.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Calculate a hash value
|
||||
*/
|
||||
class CHashObject
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
CHashObject();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CHashObject();
|
||||
|
||||
/**
|
||||
* @brief Shift operator adding a string to the hash.
|
||||
* @param[in] rssString Reference to the string.
|
||||
* @return
|
||||
*/
|
||||
CHashObject& operator<<(const std::string& rssString);
|
||||
|
||||
/**
|
||||
* @brief Get the current hash value.
|
||||
* @return The hash value.
|
||||
*/
|
||||
uint64_t GetHash() const;
|
||||
|
||||
private:
|
||||
XXH64_state_t* m_state = nullptr; ///< Hash state
|
||||
};
|
||||
|
||||
#endif // !defined(HASH_CALC_H)
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "interface_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include <iostream>
|
||||
|
||||
CInterfaceEntity::CInterfaceEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bIsLocal) :
|
||||
CDefinitionEntity(rptrContext, ptrParent), m_bIsLocal(bIsLocal)
|
||||
{}
|
||||
|
||||
sdv::interface_t CInterfaceEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
// Expose interfaces
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::idl::IInterfaceEntity*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IInterfaceEntity>())
|
||||
return static_cast<sdv::idl::IInterfaceEntity*>(this);
|
||||
return CDefinitionEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
std::string CInterfaceEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return std::string("interface ") + GetScopedName();
|
||||
}
|
||||
|
||||
void CInterfaceEntity::Process()
|
||||
{
|
||||
// The definition and declaration can be defined:
|
||||
// struct <struct_identifier>; --> forward declaration
|
||||
// struct <struct_identifier> {...}; --> struct definition
|
||||
// struct <struct_identifier> : <base_struct,...> {...}; --> struct definition with inheritance
|
||||
// <struct_identifier> <decl_identifier>; --> struct variable declaration
|
||||
// <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
|
||||
// struct <struct_identifier> <decl_identifier>; --> struct variable declaration
|
||||
// struct <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
|
||||
// struct <struct_identifier> {...} <decl_identifier>; --> struct definition and variable declaration
|
||||
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier>; --> struct definition with inheritance and variable declaration
|
||||
// struct <struct_identifier> {...} <decl_identifier> = {...}; --> struct definition, variable declaration and assignment
|
||||
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier> = {...}; --> struct definition with inheritance, variable declaration and assignment
|
||||
// struct {...} <decl_identifier>; --> anonymous struct definition and variable declaration
|
||||
// struct : <base_struct,...> {...} <decl_identifier>; --> anonymous struct definition with inheritance and variable declaration
|
||||
// struct {...} <decl_identifier> = {...}; --> anonymous struct definition, variable declaration and assignment
|
||||
// struct : <base_struct,...> {...} <decl_identifier> = {...}; --> anonymous struct definition with inheritance, variable declaration and assignment
|
||||
|
||||
// typedef <struct_identifier> <type_identifier>;
|
||||
// typedef struct <struct_identifier> { ... } <type_identifier>;
|
||||
// typedef <struct_identifier> <type_identifier>;
|
||||
// typedef struct <struct_identifier> { ... } <type_identifier>;
|
||||
// typedef struct { ... } <type_identifier>;
|
||||
// const struct <struct_identifier> <decl_identifier> = {...};
|
||||
// const <struct_identifier> <decl_identifier> = {...};
|
||||
// const struct {...} <decl_identifier> = {...};
|
||||
|
||||
// The declaration is as follows:
|
||||
// <struct_identifier> <decl_identifier>;
|
||||
// struct <struct_identifier> <decl_identifier>;
|
||||
// struct <struct_identifier> { ... } <decl_identifier>;
|
||||
|
||||
|
||||
// TODO Enforce inheritance from sdv::IInterfaceAccess unless the interface is sdv::IInterfaceAccess.
|
||||
|
||||
CDefinitionEntity::Process();
|
||||
}
|
||||
|
||||
bool CInterfaceEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_const_variable: return true;
|
||||
case EDefinitionSupport::support_typedef: return true;
|
||||
case EDefinitionSupport::support_struct: return true;
|
||||
case EDefinitionSupport::support_union: return true;
|
||||
case EDefinitionSupport::support_enum: return true;
|
||||
case EDefinitionSupport::support_attribute: return true;
|
||||
case EDefinitionSupport::support_operation: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CInterfaceEntity::CreateValueNode()
|
||||
{
|
||||
// Create a compound type value node for this definition.
|
||||
ValueRef() = std::make_shared<CInterfaceValueNode>(shared_from_this(), nullptr);
|
||||
}
|
||||
96
sdv_executables/sdv_idl_compiler/entities/interface_entity.h
Normal file
96
sdv_executables/sdv_idl_compiler/entities/interface_entity.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef INTERFACE_ENTITY_H
|
||||
#define INTERFACE_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The interface definition of an IDL file.
|
||||
* @details The interface section of the IDL file contains multiple declarations of attributes and operations, as well as the
|
||||
* definitions of enums, structs and unions.
|
||||
*/
|
||||
class CInterfaceEntity : public CDefinitionEntity, public sdv::idl::IInterfaceEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] bIsLocal When set, the interface is defined as a local interface not intended to be marshalled.
|
||||
*/
|
||||
CInterfaceEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bIsLocal);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CInterfaceEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Is this interface local? Overload of sdv::idl::IInterfaceEntity::IsLocal.
|
||||
* @return Returns whether the interface is defined as local.
|
||||
*/
|
||||
virtual bool IsLocal() const override { return m_bIsLocal; }
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the interface entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_interface; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with interface type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
|
||||
* @details Create the value node and assign the value node to the ValueRef() reference..
|
||||
*/
|
||||
virtual void CreateValueNode() override;
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support inheritance? Overload of CDefinitionEntity::SupportsInheritance.
|
||||
* @details Returns whether the entity supports inheritance.
|
||||
* @return Returns whether inheritance is supported (which is the case).
|
||||
*/
|
||||
virtual bool SupportsInheritance() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the complex entity support attributes in its content? Overload of CDefinitionEntity::SupportContentAttributes.
|
||||
* @details The default implementation doesn't support attributes (they are specific to interfaces).
|
||||
* @return Returns whether the entity supports attributes (which is the case).
|
||||
*/
|
||||
virtual bool SupportContentAttributes() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the complex entity support operations in its content? Overload of CDefinitionEntity::SupportContentOperations.
|
||||
* @details The default implementation doesn't support operations (they are specific to interfaces).
|
||||
* @return Returns whether the entity supports operations (which is the case).
|
||||
*/
|
||||
virtual bool SupportContentOperations() const override { return true; }
|
||||
|
||||
private:
|
||||
bool m_bIsLocal = false; ///< Flag indicating that the interface is local and not intended to be marshalled.
|
||||
};
|
||||
|
||||
#endif // !defined(INTERFACE_ENTITY_H)
|
||||
65
sdv_executables/sdv_idl_compiler/entities/meta_entity.cpp
Normal file
65
sdv_executables/sdv_idl_compiler/entities/meta_entity.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "meta_entity.h"
|
||||
|
||||
CMetaEntity::CMetaEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CToken& rtokenMeta,
|
||||
const CTokenList lstComments) :
|
||||
CEntity(rptrContext, ptrParent)
|
||||
{
|
||||
std::string ssContent = rtokenMeta;
|
||||
|
||||
// Skip initial whitespace and store the content if not verbatim text.
|
||||
size_t nSkip = 0;
|
||||
if (rtokenMeta.GetMetaType() != ETokenMetaType::token_meta_verbatim)
|
||||
{
|
||||
while (nSkip < ssContent.size() && std::isspace(ssContent[nSkip]))
|
||||
++nSkip;
|
||||
}
|
||||
m_ssContent = ssContent.substr(nSkip);
|
||||
|
||||
// Store the type
|
||||
switch (rtokenMeta.GetMetaType())
|
||||
{
|
||||
case ETokenMetaType::token_meta_include_local:
|
||||
m_eType = sdv::idl::IMetaEntity::EType::include_local;
|
||||
break;
|
||||
case ETokenMetaType::token_meta_include_global:
|
||||
m_eType = sdv::idl::IMetaEntity::EType::include_global;
|
||||
break;
|
||||
case ETokenMetaType::token_meta_define:
|
||||
m_eType = sdv::idl::IMetaEntity::EType::define;
|
||||
break;
|
||||
case ETokenMetaType::token_meta_undef:
|
||||
m_eType = sdv::idl::IMetaEntity::EType::undef;
|
||||
break;
|
||||
case ETokenMetaType::token_meta_verbatim:
|
||||
m_eType = sdv::idl::IMetaEntity::EType::verbatim;
|
||||
break;
|
||||
default:
|
||||
throw CCompileException("Internal error: incomplete meta token received.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Store comments
|
||||
SetCommentTokens(lstComments, true);
|
||||
|
||||
// Set the position in the source file
|
||||
SetBeginPosition(rtokenMeta.GetLine(), rtokenMeta.GetCol());
|
||||
}
|
||||
|
||||
sdv::interface_t CMetaEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IMetaEntity>())
|
||||
return static_cast<sdv::idl::IMetaEntity*>(this);
|
||||
return CEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::idl::IMetaEntity::EType CMetaEntity::GetMetaType() const
|
||||
{
|
||||
return m_eType;
|
||||
}
|
||||
|
||||
sdv::u8string CMetaEntity::GetContent() const
|
||||
{
|
||||
return m_ssContent;
|
||||
}
|
||||
68
sdv_executables/sdv_idl_compiler/entities/meta_entity.h
Normal file
68
sdv_executables/sdv_idl_compiler/entities/meta_entity.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef META_ENTITY_H
|
||||
#define META_ENTITY_H
|
||||
|
||||
#include "entity_base.h"
|
||||
|
||||
/**
|
||||
* @brief The meta data inserted into the code.
|
||||
*/
|
||||
class CMetaEntity : public CEntity, public sdv::idl::IMetaEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] rtokenMeta The meta data content
|
||||
* @param[in] lstComments Any preceding comments
|
||||
*/
|
||||
CMetaEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CToken& rtokenMeta,
|
||||
const CTokenList lstComments);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CMetaEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the meta entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_meta; }
|
||||
|
||||
/**
|
||||
* @brief Get the name of the entity. Overload of CEntity::GetName.
|
||||
* @return The entity name.
|
||||
*/
|
||||
virtual sdv::u8string GetName() const override { return "meta"; }
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the meta data type.
|
||||
* @return Returns meta entity type.
|
||||
*/
|
||||
virtual sdv::idl::IMetaEntity::EType GetMetaType() const override;
|
||||
|
||||
/**
|
||||
* @brief Get the meta data content.
|
||||
* @return Returns a string object.
|
||||
*/
|
||||
virtual sdv::u8string GetContent() const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Since there is none... nothing to do. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override {};
|
||||
|
||||
private:
|
||||
sdv::idl::IMetaEntity::EType m_eType; ///< Type of meta data
|
||||
std::string m_ssContent; ///< The meta data string
|
||||
};
|
||||
|
||||
#endif ///defined(META_ENTITY_H)
|
||||
49
sdv_executables/sdv_idl_compiler/entities/module_entity.cpp
Normal file
49
sdv_executables/sdv_idl_compiler/entities/module_entity.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "module_entity.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "struct_entity.h"
|
||||
#include "union_entity.h"
|
||||
#include "interface_entity.h"
|
||||
#include "exception_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../token.h"
|
||||
|
||||
CModuleEntity::CModuleEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDefinitionEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
CModuleEntity::CModuleEntity(CParser& rParser, const CContextPtr& rptrContext) :
|
||||
CDefinitionEntity(rParser, rptrContext)
|
||||
{}
|
||||
|
||||
void CModuleEntity::Process()
|
||||
{
|
||||
CDefinitionEntity::Process();
|
||||
}
|
||||
|
||||
bool CModuleEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_module: return true;
|
||||
case EDefinitionSupport::support_const_variable: return true;
|
||||
case EDefinitionSupport::support_typedef: return true;
|
||||
case EDefinitionSupport::support_struct: return true;
|
||||
case EDefinitionSupport::support_union: return true;
|
||||
case EDefinitionSupport::support_enum: return true;
|
||||
case EDefinitionSupport::support_interface: return true;
|
||||
case EDefinitionSupport::support_exception: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CModuleEntity::IsExtendable() const
|
||||
{
|
||||
// Allow extending the module.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModuleEntity::SupportsChildren() const
|
||||
{
|
||||
// Allow the support of children.
|
||||
return true;
|
||||
}
|
||||
86
sdv_executables/sdv_idl_compiler/entities/module_entity.h
Normal file
86
sdv_executables/sdv_idl_compiler/entities/module_entity.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef MODULE_ENTITY_H
|
||||
#define MODULE_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
#include <map>
|
||||
#include "../constvariant.h"
|
||||
|
||||
/**
|
||||
* @brief The module definition of an IDL file.
|
||||
* @details The module section of the IDL file contains multiple definitions of nested modules, const definitions and type
|
||||
* definitions.
|
||||
*/
|
||||
class CModuleEntity : public CDefinitionEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CModuleEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Root entity constructor (name is 'root' and no parent).
|
||||
* @param[in] rParser Reference to the parser.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
*/
|
||||
CModuleEntity(CParser& rParser, const CContextPtr& rptrContext);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CModuleEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the module entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_module; }
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
// Suppress warning of cppcheck of a useless override. The function implementation improves readability.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Is this definition a root entity? Overload of CDefinitionEntity::IsRootEntity.
|
||||
* @details The root entity is not expecting curly brackets '{...}'.
|
||||
* @return Returns whether this is a root entity (which is not the case).
|
||||
*/
|
||||
virtual bool IsRootEntity() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity extendable? Overload of CEntity::IsExtendable.
|
||||
* @details Allow extendability of the module entity.
|
||||
* @return Returns whether the entity is extendable.
|
||||
*/
|
||||
virtual bool IsExtendable() const override;
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
|
||||
* @details The module supports children.
|
||||
* @return Return whether the entity support children.
|
||||
*/
|
||||
virtual bool SupportsChildren() const override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(MODULE_ENTITY_H)
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "operation_entity.h"
|
||||
#include "interface_entity.h"
|
||||
|
||||
COperationEntity::COperationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDeclarationEntity(rptrContext, ptrParent), m_iteratorParameters(GetParamVector()),
|
||||
m_iteratorExceptions(GetExceptionVector())
|
||||
{}
|
||||
|
||||
sdv::interface_t COperationEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
// Expose interfaces
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IOperationEntity>())
|
||||
return static_cast<sdv::idl::IOperationEntity*>(this);
|
||||
return CDeclarationEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* COperationEntity::GetParameters()
|
||||
{
|
||||
if (!GetParamVector().empty()) return &m_iteratorParameters;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sdv::idl::IEntityIterator* COperationEntity::GetExceptions()
|
||||
{
|
||||
if (!GetExceptionVector().empty()) return &m_iteratorExceptions;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::pair<CEntityPtr, bool> COperationEntity::FindLocal(const std::string& rssName, bool /*bDeclaration*/) const
|
||||
{
|
||||
const CEntityVector& rvecParams = GetParamVector();
|
||||
for (const CEntityPtr& rptrEntity : rvecParams)
|
||||
{
|
||||
if (rptrEntity->GetName() == rssName)
|
||||
return std::make_pair(rptrEntity, false);
|
||||
}
|
||||
return std::make_pair(nullptr, false);
|
||||
}
|
||||
|
||||
bool COperationEntity::RequiresAssignment() const
|
||||
{
|
||||
const CInterfaceEntity* pInterface = GetParentEntity() ? GetParentEntity()->Get<CInterfaceEntity>() : nullptr;
|
||||
if (pInterface && pInterface->IsLocal()) return false;
|
||||
return CDeclarationEntity::RequiresAssignment();
|
||||
}
|
||||
128
sdv_executables/sdv_idl_compiler/entities/operation_entity.h
Normal file
128
sdv_executables/sdv_idl_compiler/entities/operation_entity.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef OPERATION_ENTITY_H
|
||||
#define OPERATION_ENTITY_H
|
||||
|
||||
#include "declaration_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The operation definition of an IDL file.
|
||||
* @details The operation section of the IDL file defines operations.
|
||||
*/
|
||||
class COperationEntity : public CDeclarationEntity, public sdv::idl::IOperationEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
COperationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~COperationEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get parameter entity iterator if the definition has any parameters. Overload of
|
||||
* sdv::idl::IOperationEntity::GetParameters.
|
||||
* @return Returns a pointer to the parameter entity iterator or NULL when not available.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetParameters() override;
|
||||
|
||||
/**
|
||||
* @brief Get the list of possible exceptions that might be fired for this operation. Overload of
|
||||
* sdv::idl::IOperationEntity::GetExceptions.
|
||||
* @return Interface pointer to the exception iterator.
|
||||
*/
|
||||
virtual sdv::idl::IEntityIterator* GetExceptions() override;
|
||||
|
||||
/**
|
||||
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of IDeclarationEntity::IsReadOnly.
|
||||
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
|
||||
* 'true'.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override { return m_bOperationIsConst; }
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the operation type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_operation; }
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override { CDeclarationEntity::Process(); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Does the entity support raising exceptions? Overload of CDeclarationEntity::SupportRaiseExceptions.
|
||||
* @return Returns 'true' when the entity defined as attribute; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportRaiseExceptions() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support an interface as base type? Overload of CDeclarationEntity::SupportVoid.
|
||||
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportInterface() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support 'void' as base type? Overload of CDeclarationEntity::SupportVoid.
|
||||
* @details Returns whether the entity supports the 'void' base type. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports void as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportVoid() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support parameters? Overload of CDeclarationEntity::RequiresParameters.
|
||||
* @details Returns whether the entity supports parameters. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity requires parameters; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresParameters() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Set operation as const. Overload of CDeclarationEntity::SetOperationAsConst.
|
||||
*/
|
||||
virtual void SetOperationAsConst() override { m_bOperationIsConst = true; }
|
||||
|
||||
/**
|
||||
* @brief Find the entity locally by looking in the parameter list. Overload of CEntity::FindLocal.
|
||||
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
|
||||
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
|
||||
* the reuse of names between declarations and definitions.
|
||||
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
|
||||
* boolean that indicates that the entity was from an inherited entity.
|
||||
*/
|
||||
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity require an assignment (const declarations do)? Overload of CDeclarationEntity::RequiresAssignment.
|
||||
* @details Default processing is done by the declaration function (checking for unbound arrays). Exception: when the
|
||||
* parent interface is defined as local, assignment is not required.
|
||||
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresAssignment() const override;
|
||||
|
||||
private:
|
||||
bool m_bOperationIsConst = false; ///< When set, the operation is defined as 'const' operation.
|
||||
CEntityIterator m_iteratorParameters; ///< Parameters iterator
|
||||
CEntityIterator m_iteratorExceptions; ///< Exceptions iterator
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(OPERATION_ENTITY_H)
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "parameter_entity.h"
|
||||
#include "interface_entity.h"
|
||||
#include "operation_entity.h"
|
||||
#include "../exception.h"
|
||||
|
||||
CParameterEntity::CParameterEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
|
||||
const CTokenList& rlstTokenList, bool bEnforceDirection /*= true*/) :
|
||||
CDeclarationEntity(rptrContext, ptrParent, rlstTokenList), m_bEnforceDirection(bEnforceDirection)
|
||||
{}
|
||||
|
||||
sdv::interface_t CParameterEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IParameterEntity>())
|
||||
return static_cast<sdv::idl::IParameterEntity*>(this);
|
||||
return CDeclarationEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
void CParameterEntity::Process()
|
||||
{
|
||||
// Check for direction indicators.
|
||||
CToken token = GetToken();
|
||||
if (token == "in") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::input;
|
||||
else if (token == "out") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::output;
|
||||
else if (token == "inout") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::in_out;
|
||||
else
|
||||
{
|
||||
PrependToken(token);
|
||||
|
||||
// Enforce the direction?
|
||||
if (m_bEnforceDirection) throw CCompileException(token, "Missing direction indicator.");
|
||||
}
|
||||
|
||||
// Let the basic type entity process further
|
||||
CDeclarationEntity::Process();
|
||||
}
|
||||
|
||||
bool CParameterEntity::RequiresAssignment() const
|
||||
{
|
||||
COperationEntity* pOperation = GetParentEntity() ? GetParentEntity()->Get<COperationEntity>() : nullptr;
|
||||
const CInterfaceEntity* pInterface = pOperation && pOperation->GetParentEntity() ? pOperation->GetParentEntity()->Get<CInterfaceEntity>() : nullptr;
|
||||
if (pInterface && pInterface->IsLocal()) return false;
|
||||
return CDeclarationEntity::RequiresAssignment();
|
||||
}
|
||||
|
||||
void CParameterEntity::CalcHash(CHashObject& rHash) const
|
||||
{
|
||||
// Call base class
|
||||
CDeclarationEntity::CalcHash(rHash);
|
||||
|
||||
// Add the direction
|
||||
switch (m_eDirection)
|
||||
{
|
||||
case sdv::idl::IParameterEntity::EParameterDirection::input:
|
||||
rHash << "in";
|
||||
break;
|
||||
case sdv::idl::IParameterEntity::EParameterDirection::output:
|
||||
rHash << "out";
|
||||
break;
|
||||
case sdv::idl::IParameterEntity::EParameterDirection::in_out:
|
||||
rHash << "inout";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
92
sdv_executables/sdv_idl_compiler/entities/parameter_entity.h
Normal file
92
sdv_executables/sdv_idl_compiler/entities/parameter_entity.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifndef PARAMETER_ENTITY_H
|
||||
#define PARAMETER_ENTITY_H
|
||||
|
||||
#include "declaration_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The parameter definition of an operation and value type.
|
||||
* @details The parameter section contains the definition of the parameter for operations and value types.
|
||||
*/
|
||||
class CParameterEntity : public CDeclarationEntity, public sdv::idl::IParameterEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
|
||||
* @param[in] bEnforceDirection Enforce parameter direction.
|
||||
*/
|
||||
CParameterEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList,
|
||||
bool bEnforceDirection = true);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CParameterEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the parameter type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_parameter; }
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support an interface as base type? Overload of CDeclarationEntity::SupportVoid.
|
||||
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportInterface() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Get the parameter direction. Overload of sdv::idl::IParameterEntity::GetDirection.
|
||||
* @return Parameter direction.
|
||||
*/
|
||||
virtual sdv::idl::IParameterEntity::EParameterDirection GetDirection() const override { return m_eDirection; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity require an assignment (const declarations do)? Overload of CDeclarationEntity::RequiresAssignment.
|
||||
* @details Default processing is done by the declaration function (checking for unbound arrays). Exception: when the
|
||||
* parent interface is defined as local, assignment is not required.
|
||||
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresAssignment() const override;
|
||||
|
||||
/**
|
||||
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of IDeclarationEntity::IsReadOnly.
|
||||
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
|
||||
* 'true'.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
|
||||
* @param[in, out] rHash Hash object to be filled with data.
|
||||
*/
|
||||
virtual void CalcHash(CHashObject& rHash) const override;
|
||||
|
||||
private:
|
||||
bool m_bEnforceDirection; ///< When set, the parameter enforces the direction indicator when processing.
|
||||
sdv::idl::IParameterEntity::EParameterDirection m_eDirection =
|
||||
sdv::idl::IParameterEntity::EParameterDirection::unknown; ///< The direction type of the parameter.
|
||||
};
|
||||
|
||||
#endif // !defined(PARAMETER_ENTITY_H)
|
||||
30
sdv_executables/sdv_idl_compiler/entities/root_entity.cpp
Normal file
30
sdv_executables/sdv_idl_compiler/entities/root_entity.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "root_entity.h"
|
||||
#include "module_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../token.h"
|
||||
|
||||
|
||||
CRootEntity::CRootEntity(CParser& rParser, const CContextPtr& rptrContext) :
|
||||
CModuleEntity(rParser, rptrContext)
|
||||
{}
|
||||
|
||||
void CRootEntity::Process()
|
||||
{
|
||||
// Skip the definition and process the content directly.
|
||||
ProcessContent();
|
||||
}
|
||||
|
||||
bool CRootEntity::IsExtendable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CRootEntity::AddMeta(const CEntityPtr& ptrMeta)
|
||||
{
|
||||
m_lstMetaEntities.push_back(ptrMeta);
|
||||
}
|
||||
|
||||
const CEntityList& CRootEntity::GetMeta() const
|
||||
{
|
||||
return m_lstMetaEntities;
|
||||
}
|
||||
57
sdv_executables/sdv_idl_compiler/entities/root_entity.h
Normal file
57
sdv_executables/sdv_idl_compiler/entities/root_entity.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef ROOT_ENTITY_H
|
||||
#define ROOT_ENTITY_H
|
||||
|
||||
#include "module_entity.h"
|
||||
#include "meta_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The root definition of an IDL file.
|
||||
* @details The root section of the IDL file contains multiple definitions of modules, constants and types.
|
||||
*/
|
||||
class CRootEntity : public CModuleEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rParser Reference to the parser used to parse the code.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
*/
|
||||
CRootEntity(CParser& rParser, const CContextPtr& rptrContext);
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CModuleEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Is this definition a root entity? Overload of CDefinitionEntity::IsRootEntity.
|
||||
* @details The root entity is not expecting curly brackets '{...}'.
|
||||
* @return Returns whether this entity is the root entity.
|
||||
*/
|
||||
virtual bool IsRootEntity() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity extendable? Overload of CEntity::IsExtendable.
|
||||
* @details Prevents extending the root entity.
|
||||
* @return Returns whether the entity is extendable.
|
||||
*/
|
||||
virtual bool IsExtendable() const override;
|
||||
|
||||
/**
|
||||
* @brief Add meta data entity.
|
||||
* @param[in] ptrMeta Shared pointer to the meta data entity.
|
||||
*/
|
||||
void AddMeta(const CEntityPtr& ptrMeta);
|
||||
|
||||
/**
|
||||
* @brief Get the meta data entity list.
|
||||
* @return Reference to the meta data entity list.
|
||||
*/
|
||||
const CEntityList& GetMeta() const;
|
||||
|
||||
private:
|
||||
CEntityList m_lstMetaEntities; ///< List of meta entities.
|
||||
|
||||
};
|
||||
|
||||
#endif // !defined(ROOT_ENTITY_H)
|
||||
71
sdv_executables/sdv_idl_compiler/entities/struct_entity.cpp
Normal file
71
sdv_executables/sdv_idl_compiler/entities/struct_entity.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "struct_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include <iostream>
|
||||
|
||||
CStructEntity::CStructEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDefinitionEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
std::string CStructEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return std::string("struct ") + GetScopedName();
|
||||
}
|
||||
|
||||
void CStructEntity::Process()
|
||||
{
|
||||
// The definition and declaration can be defined:
|
||||
// struct <struct_identifier>; --> forward declaration
|
||||
// struct <struct_identifier> {...}; --> struct definition
|
||||
// struct <struct_identifier> : <base_struct,...> {...}; --> struct definition with inheritance
|
||||
// <struct_identifier> <decl_identifier>; --> struct variable declaration
|
||||
// <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
|
||||
// struct <struct_identifier> <decl_identifier>; --> struct variable declaration
|
||||
// struct <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
|
||||
// struct <struct_identifier> {...} <decl_identifier>; --> struct definition and variable declaration
|
||||
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier>; --> struct definition with inheritance and variable declaration
|
||||
// struct <struct_identifier> {...} <decl_identifier> = {...}; --> struct definition, variable declaration and assignment
|
||||
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier> = {...}; --> struct definition with inheritance, variable declaration and assignment
|
||||
// struct {...} <decl_identifier>; --> anonymous struct definition and variable declaration
|
||||
// struct : <base_struct,...> {...} <decl_identifier>; --> anonymous struct definition with inheritance and variable declaration
|
||||
// struct {...} <decl_identifier> = {...}; --> anonymous struct definition, variable declaration and assignment
|
||||
// struct : <base_struct,...> {...} <decl_identifier> = {...}; --> anonymous struct definition with inheritance, variable declaration and assignment
|
||||
|
||||
// typedef <struct_identifier> <type_identifier>;
|
||||
// typedef struct <struct_identifier> { ... } <type_identifier>;
|
||||
// typedef <struct_identifier> <type_identifier>;
|
||||
// typedef struct <struct_identifier> { ... } <type_identifier>;
|
||||
// typedef struct { ... } <type_identifier>;
|
||||
// const struct <struct_identifier> <decl_identifier> = {...};
|
||||
// const <struct_identifier> <decl_identifier> = {...};
|
||||
// const struct {...} <decl_identifier> = {...};
|
||||
|
||||
// The declaration is as follows:
|
||||
// <struct_identifier> <decl_identifier>;
|
||||
// struct <struct_identifier> <decl_identifier>;
|
||||
// struct <struct_identifier> { ... } <decl_identifier>;
|
||||
|
||||
CDefinitionEntity::Process();
|
||||
}
|
||||
|
||||
bool CStructEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_variable: return true;
|
||||
case EDefinitionSupport::support_const_variable: return true;
|
||||
case EDefinitionSupport::support_typedef: return true;
|
||||
case EDefinitionSupport::support_struct: return true;
|
||||
case EDefinitionSupport::support_union: return true;
|
||||
case EDefinitionSupport::support_enum: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CStructEntity::CreateValueNode()
|
||||
{
|
||||
// Create a compound type value node for this definition.
|
||||
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
|
||||
}
|
||||
75
sdv_executables/sdv_idl_compiler/entities/struct_entity.h
Normal file
75
sdv_executables/sdv_idl_compiler/entities/struct_entity.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef STRUCT_ENTITY_H
|
||||
#define STRUCT_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The struct definition of an IDL file.
|
||||
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
|
||||
* and unions.
|
||||
*/
|
||||
class CStructEntity : public CDefinitionEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CStructEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CStructEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the struct type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_struct; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with struct type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support inheritance? Overload of CDefinitionEntity::SupportsInheritance.
|
||||
* @return Returns whether the entity supports inheritance.
|
||||
*/
|
||||
virtual bool SupportsInheritance() const override { return true; }
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Does the entity declaration support anonymous naming? Overload of CDefinitionEntity::SupportsAnonymous.
|
||||
* @remarks C11 supports anonymous structs. C++ not! Therefore, IDL does not support anonymous structs.
|
||||
* @return Returns whether the entity supports inheritance.
|
||||
*/
|
||||
virtual bool SupportsAnonymous() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
|
||||
* @details Create the value node and assign the value node to the ValueRef() reference..
|
||||
*/
|
||||
virtual void CreateValueNode() override;
|
||||
};
|
||||
|
||||
#endif // !defined(STRUCT_ENTITY_H)
|
||||
44
sdv_executables/sdv_idl_compiler/entities/typedef_entity.cpp
Normal file
44
sdv_executables/sdv_idl_compiler/entities/typedef_entity.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "typedef_entity.h"
|
||||
#include "../exception.h"
|
||||
|
||||
CTypedefEntity::CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CDeclarationEntity(rptrContext, ptrParent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CTypedefEntity::CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
|
||||
const std::string& rssName) :
|
||||
CDeclarationEntity(rptrContext, ptrParent)
|
||||
{
|
||||
if (rssName.empty()) throw CCompileException("Internal error: trying to create a named type entity without valid name.");
|
||||
SetName(rssName, true, true);
|
||||
}
|
||||
|
||||
std::string CTypedefEntity::GetDeclTypeStr(bool bResolveTypedef) const
|
||||
{
|
||||
// When not resolving the typedef, return the default implementation ("typedef <name>").
|
||||
if (!bResolveTypedef) return std::string("typedef ") + GetScopedName();
|
||||
|
||||
// Otherwise resolve the typedef by taking the base type.
|
||||
if (GetTypeEntity())
|
||||
return GetTypeEntity()->GetDeclTypeStr(bResolveTypedef);
|
||||
else
|
||||
return DeclTypeToString(GetBaseType());
|
||||
}
|
||||
|
||||
void CTypedefEntity::Process()
|
||||
{
|
||||
CDeclarationEntity::Process();
|
||||
}
|
||||
|
||||
std::pair<CEntityPtr, bool> CTypedefEntity::FindLocal(const std::string& rssName, bool bDeclaration) const
|
||||
{
|
||||
// Call the find local function on the original type.
|
||||
if (!GetTypeEntity()) return std::pair<CEntityPtr, bool>();
|
||||
|
||||
return GetTypeEntity()->FindLocal(rssName, bDeclaration);
|
||||
}
|
||||
|
||||
|
||||
|
||||
79
sdv_executables/sdv_idl_compiler/entities/typedef_entity.h
Normal file
79
sdv_executables/sdv_idl_compiler/entities/typedef_entity.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef TYPEDEF_ENTITY_H
|
||||
#define TYPEDEF_ENTITY_H
|
||||
|
||||
#include "declaration_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The const definition of an IDL file.
|
||||
* @details The const section of the IDL file defines const values.
|
||||
*/
|
||||
class CTypedefEntity : public CDeclarationEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Constructor for a local named type entity without parsing.
|
||||
* @attention This type entity is not attached as a child.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] rssName Reference to the name.
|
||||
*/
|
||||
CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const std::string& rssName);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CTypedefEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return The typedef entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_typedef; }
|
||||
|
||||
/**
|
||||
* @brief Get the qualified type of the entity. Overload of CEntity::GetDeclTypeStr.
|
||||
* @attention To get the qualified type including array sizes, use the GetDeclTypeStr of the CEntityValueNode class.
|
||||
* @details The qualified type consists of "<base type> <type identifier>".
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return String with the typedef entity type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity require an assignment? Overload of CDeclarationEntity::RequiresAssignment.
|
||||
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresAssignment() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief Find the entity locally. Overload of CEntity::FindLocal.
|
||||
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
|
||||
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
|
||||
* the reuse of names between declarations and definitions.
|
||||
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
|
||||
* boolean that indicates that the entity was from an inherited entity.
|
||||
*/
|
||||
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
|
||||
};
|
||||
|
||||
#endif // !defined(TYPEDEF_ENTITY_H)
|
||||
434
sdv_executables/sdv_idl_compiler/entities/union_entity.cpp
Normal file
434
sdv_executables/sdv_idl_compiler/entities/union_entity.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
#include "union_entity.h"
|
||||
#include "../exception.h"
|
||||
#include "../logger.h"
|
||||
#include "../parser.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
CCaseEntry::CCaseEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bDefault) :
|
||||
CVariableEntity(rptrContext, ptrParent, false, false), m_bDefault(bDefault)
|
||||
{}
|
||||
|
||||
std::string CCaseEntry::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return GetScopedName();
|
||||
}
|
||||
|
||||
sdv::interface_t CCaseEntry::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::ICaseEntity>())
|
||||
return static_cast<sdv::idl::ICaseEntity*>(this);
|
||||
return CVariableEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::u8string CCaseEntry::GetLabel() const
|
||||
{
|
||||
// The default case entry doesn#t have a label.
|
||||
if (m_bDefault) return sdv::u8string();
|
||||
|
||||
// Get the label string from the value of the case label entity.
|
||||
CVariableEntity* pLabelVariableEntity = m_ptrLabel->Get<CVariableEntity>();
|
||||
if (!pLabelVariableEntity)
|
||||
throw CCompileException("Internal error: expected a variable entity as case label.");
|
||||
if (!pLabelVariableEntity->ValueRef())
|
||||
throw CCompileException("Internal error: expected a value for the variable entity case label.");
|
||||
|
||||
// Enum value node?
|
||||
const CEnumValueNode* pEnumValueNode = pLabelVariableEntity->ValueRef()->Get<CEnumValueNode>();
|
||||
if (pEnumValueNode) return pEnumValueNode->String();
|
||||
|
||||
// Simple value node?
|
||||
const CSimpleTypeValueNode* pSimpleTypeValueNode = pLabelVariableEntity->ValueRef()->Get<CSimpleTypeValueNode>();
|
||||
if (pSimpleTypeValueNode) return pSimpleTypeValueNode->Variant().GetAsString();
|
||||
|
||||
// Otherwise error...
|
||||
throw CCompileException("Internal error: expected a value for the variable entity case label.");
|
||||
}
|
||||
|
||||
const CToken& CCaseEntry::GetLabelToken() const
|
||||
{
|
||||
return m_tokenLabel;
|
||||
}
|
||||
|
||||
void CCaseEntry::Process()
|
||||
{
|
||||
CLog log("Processing case label...");
|
||||
|
||||
// Peek for the label token (used for reporting parsing errors).
|
||||
m_tokenLabel = PeekToken();
|
||||
|
||||
// Processing of the case label value is done in post processing since the switch type might not be known yet.
|
||||
CToken token;
|
||||
std::string ssCaseLabel;
|
||||
while ((token = GetToken()) != ":")
|
||||
{
|
||||
if (!ssCaseLabel.empty())
|
||||
ssCaseLabel += ' ';
|
||||
ssCaseLabel += static_cast<std::string>(token);
|
||||
m_lstCaseValue.push_back(token);
|
||||
}
|
||||
log << "Case label name '" << ssCaseLabel << "'" << std::endl;
|
||||
|
||||
// Only unnamed nested struct and union definitions are not allowed. Furthermore, anonymous structs and unions (without
|
||||
// explicit declaration cannot be supported (also not part of the C++ standard). Varable based switch type unions are
|
||||
// also not supported since the variable for the switch needs to be part of the parent switch case and thus needs a struct to
|
||||
// hold it.
|
||||
token = PeekToken();
|
||||
if ((token == "struct" && (PeekToken(1) == "{" || PeekToken(2) == "{")) ||
|
||||
(token == "union" && (PeekToken(1) == "switch" || PeekToken(2) == "switch")))
|
||||
{
|
||||
// Get the struct/union from the code
|
||||
token = GetToken();
|
||||
|
||||
throw CCompileException(token, "Cannot make a definition inside an union.");
|
||||
}
|
||||
|
||||
// Stop processing if the case doesn't have any declaration (is followed by another case or a closing curled bracket).
|
||||
if (token == "case" || token == "}")
|
||||
{
|
||||
// Determine whether the comments are preceding the token (either on the same line or the line before).
|
||||
CTokenList lstPreComments = GetPreCommentTokenList();
|
||||
if (!lstPreComments.empty()) SetCommentTokens(lstPreComments);
|
||||
|
||||
// Assign any succeeding comments
|
||||
ProcessPostCommentTokenList(token.GetLine());
|
||||
|
||||
// Insert a semi-colon to identify that the statement is finished.
|
||||
CToken tokenSep(";", ETokenType::token_separator);
|
||||
PrependToken(tokenSep);
|
||||
SetName(GetParserRef().GenerateAnonymousEntityName("case"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Now let the variable process the declaration
|
||||
CVariableEntity::Process();
|
||||
}
|
||||
|
||||
void CCaseEntry::PostProcess()
|
||||
{
|
||||
CLog log("Post processing case label...");
|
||||
|
||||
// Get the base type of the enum entity and insert it in front of the declaration.
|
||||
CUnionEntity* pUnionEntity = GetParentEntity()->Get<CUnionEntity>();
|
||||
if (!pUnionEntity) throw CCompileException("Internal error: expected an union entity as parent.");
|
||||
|
||||
// Separate between case statement and default
|
||||
if (m_bDefault)
|
||||
{
|
||||
if (!m_lstCaseValue.empty())
|
||||
throw CCompileException("Default case label cannot have a value.");
|
||||
|
||||
|
||||
log << "Default case label" << std::endl;
|
||||
|
||||
} else
|
||||
{
|
||||
// Get the switch case type
|
||||
sdv::idl::EDeclType eSwitchCaseType = sdv::idl::EDeclType::decltype_unknown;
|
||||
CEntityPtr ptrSwitchCaseType;
|
||||
CValueNodePtr ptrSwitchCaseValue;
|
||||
pUnionEntity->GetSwitchCaseType(eSwitchCaseType, ptrSwitchCaseType, ptrSwitchCaseValue);
|
||||
|
||||
// Insert the switch type specific assignment to the token list
|
||||
m_lstCaseValue.push_front(CToken("="));
|
||||
m_lstCaseValue.push_front(CToken("label"));
|
||||
if (!ptrSwitchCaseType)
|
||||
{
|
||||
switch (eSwitchCaseType)
|
||||
{
|
||||
case sdv::idl::EDeclType::decltype_short: m_lstCaseValue.push_front(CToken("short")); break;
|
||||
case sdv::idl::EDeclType::decltype_long: m_lstCaseValue.push_front(CToken("long")); break;
|
||||
case sdv::idl::EDeclType::decltype_long_long: m_lstCaseValue.push_front(CToken("long long")); break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_short: m_lstCaseValue.push_front(CToken("unsigned short")); break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long: m_lstCaseValue.push_front(CToken("unsigned long")); break;
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long_long: m_lstCaseValue.push_front(CToken("unsigned long long")); break;
|
||||
case sdv::idl::EDeclType::decltype_octet: m_lstCaseValue.push_front(CToken("octet")); break;
|
||||
case sdv::idl::EDeclType::decltype_char: m_lstCaseValue.push_front(CToken("char")); break;
|
||||
case sdv::idl::EDeclType::decltype_char16: m_lstCaseValue.push_front(CToken("char16")); break;
|
||||
case sdv::idl::EDeclType::decltype_char32: m_lstCaseValue.push_front(CToken("char32")); break;
|
||||
case sdv::idl::EDeclType::decltype_wchar: m_lstCaseValue.push_front(CToken("wchar")); break;
|
||||
case sdv::idl::EDeclType::decltype_boolean: m_lstCaseValue.push_front(CToken("boolean")); break;
|
||||
case sdv::idl::EDeclType::decltype_native: m_lstCaseValue.push_front(CToken("native")); break;
|
||||
default: throw CCompileException(m_tokenLabel, "Internal error: invalid switch case data type.");
|
||||
}
|
||||
}
|
||||
else
|
||||
m_lstCaseValue.push_front(CToken(ptrSwitchCaseType->GetScopedName()));
|
||||
m_lstCaseValue.push_back(CToken(";", ETokenType::token_separator));
|
||||
|
||||
// Create the label value.
|
||||
m_ptrLabel = std::make_shared<CVariableEntity>(GetContext(), shared_from_this(), m_lstCaseValue, true, false);
|
||||
|
||||
// Process the label variable (this will resolve any assigned value and constant).
|
||||
m_ptrLabel->Process();
|
||||
CVariableEntity* pLabelVariableEntity = m_ptrLabel->Get<CVariableEntity>();
|
||||
if (!pLabelVariableEntity)
|
||||
throw CCompileException("Internal error: expected a variable entity as case label.");
|
||||
pLabelVariableEntity->PostProcess();
|
||||
|
||||
log << "Case label is: " << GetLabel() << std::endl;
|
||||
}
|
||||
|
||||
// Post process the assignment
|
||||
CVariableEntity::PostProcess();
|
||||
}
|
||||
|
||||
CUnionEntity::CUnionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
|
||||
CStructEntity(rptrContext, ptrParent)
|
||||
{}
|
||||
|
||||
sdv::interface_t CUnionEntity::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::IUnionEntity>())
|
||||
return static_cast<sdv::idl::IUnionEntity*>(this);
|
||||
return CStructEntity::GetInterface(idInterface);
|
||||
}
|
||||
|
||||
sdv::idl::IUnionEntity::ESwitchInterpret CUnionEntity::GetSwitchInterpretation() const
|
||||
{
|
||||
return m_eSwitchInterpret;
|
||||
}
|
||||
|
||||
void CUnionEntity::GetSwitchType(/*out*/ sdv::idl::EDeclType& reType, /*out*/ sdv::IInterfaceAccess*& rpType) const
|
||||
{
|
||||
reType = m_typedeclSwitch.GetBaseType();
|
||||
rpType = m_typedeclSwitch.GetTypeDefinition();
|
||||
}
|
||||
|
||||
void CUnionEntity::GetSwitchVar(/*out*/ sdv::u8string& rssVarStr, /*out*/ sdv::IInterfaceAccess*& rpVarEntity,
|
||||
/*out*/ sdv::IInterfaceAccess*& rpVarContainer) const
|
||||
{
|
||||
rssVarStr.clear();
|
||||
rpVarEntity = nullptr;
|
||||
rpVarContainer = nullptr;
|
||||
if (m_eSwitchInterpret == sdv::idl::IUnionEntity::ESwitchInterpret::switch_type) return;
|
||||
rssVarStr = m_ssValueNode;
|
||||
rpVarEntity = m_ptrSwitchValueNode ? m_ptrSwitchValueNode->GetDeclEntity()->Get<sdv::IInterfaceAccess>() : nullptr;
|
||||
rpVarContainer = m_ptrContainer ? m_ptrContainer->Get<sdv::IInterfaceAccess>() : nullptr;
|
||||
}
|
||||
|
||||
std::string CUnionEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
|
||||
{
|
||||
return std::string("union ") + GetScopedName();
|
||||
}
|
||||
|
||||
void CUnionEntity::Process()
|
||||
{
|
||||
// The definition and declaration can be defined:
|
||||
// union <union_identifier>; --> forward declaration
|
||||
// union <union_identifier> switch(<type>) {...}; --> union definition with type
|
||||
// struct { <type> <var>; union <union_identifier> switch(<var>) {...};}; --> union definition with varaiable
|
||||
// <union_identifier> <decl_identifier>; --> union variable declaration
|
||||
// <union_identifier> <decl_identifier> = {...}; --> union variable declaration and assignment
|
||||
// union <union_identifier> <decl_identifier>; --> union variable declaration
|
||||
// union <union_identifier> <decl_identifier> = {...}; --> union variable declaration and assignment
|
||||
// union <union_identifier> {...} <decl_identifier>; --> union definition and variable declaration
|
||||
// union <union_identifier> {...} <decl_identifier> = {...}; --> union definition, variable declaration and assignment
|
||||
// union {...} <decl_identifier>; --> anonymous union definition and variable declaration
|
||||
// union {...} <decl_identifier> = {...}; --> anonymous union definition, variable declaration and assignment
|
||||
|
||||
// typedef <union_identifier> <type_identifier>;
|
||||
// typedef union <union_identifier> { ... } <type_identifier>;
|
||||
// typedef <union_identifier> <type_identifier>;
|
||||
// typedef union <union_identifier> { ... } <type_identifier>;
|
||||
// typedef union { ... } <type_identifier>;
|
||||
// const union <union_identifier> <decl_identifier> = {...};
|
||||
// const <union_identifier> <decl_identifier> = {...};
|
||||
// const union {...} <decl_identifier> = {...};
|
||||
|
||||
// The declaration is as follows:
|
||||
// <union_identifier> <decl_identifier>;
|
||||
// union <union_identifier> <decl_identifier>;
|
||||
// union <union_identifier> { ... } <decl_identifier>;
|
||||
|
||||
CStructEntity::Process();
|
||||
}
|
||||
|
||||
void CUnionEntity::ProcessDefinitionAddendum()
|
||||
{
|
||||
//unions are defined as :
|
||||
//union <union_identifier> switch (<type>)-- > type is a integral or enum type or a typedef of this
|
||||
//{
|
||||
//case <value>: <type> <var_identifier> -- > case values need to be unique
|
||||
// ...
|
||||
//};
|
||||
//struct
|
||||
//{
|
||||
// <type> <var>;
|
||||
// union <union_identifier> switch (<var>)-- > var is an integral or enum value, which is part of the struct
|
||||
// {
|
||||
// case <value>: <type> <var_identifier> -- > case values need to be unique
|
||||
// ...
|
||||
// };
|
||||
//};
|
||||
|
||||
if (PeekToken() == ";") return; // Forward declaration
|
||||
CToken token = GetToken();
|
||||
if (token != "switch") throw CCompileException(token, "Expecting a switch statement following the union identifier.");
|
||||
token = GetToken();
|
||||
if (token != "(") throw CCompileException(token, "Expecting a left bracket '('.");
|
||||
size_t nIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
token = PeekToken(nIndex++);
|
||||
if (!token || token == ")") break;
|
||||
m_ssSwitchVar += static_cast<std::string>(token);
|
||||
}
|
||||
m_typedeclSwitch = ProcessType(true);
|
||||
token = GetToken();
|
||||
while (token && token != ")")
|
||||
{
|
||||
m_ssValueNode += static_cast<std::string>(token);
|
||||
token = GetToken();
|
||||
}
|
||||
if (token != ")") throw CCompileException(token, "Expecting a right bracket ')'.");
|
||||
|
||||
// Was it possible to resolve the type for the switch case. If not, the switch case is a variable?
|
||||
if (m_typedeclSwitch.GetBaseType() == sdv::idl::EDeclType::decltype_unknown)
|
||||
m_eSwitchInterpret = sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable;
|
||||
}
|
||||
|
||||
void CUnionEntity::PostProcess()
|
||||
{
|
||||
if (ForwardDeclaration()) return;
|
||||
|
||||
// Was the switch case type/variable found before? If not, check for a variable.
|
||||
if (m_eSwitchInterpret == sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable)
|
||||
{
|
||||
// Get the switch type object
|
||||
CEntityPtr ptrSwitchVarBase = Find(m_typedeclSwitch.GetTypeString());
|
||||
if (!ptrSwitchVarBase)
|
||||
throw CCompileException(m_ssSwitchVar,
|
||||
"The switch case must be determined by a predefined type or a member variable.");
|
||||
|
||||
// Proper relative name (without global scope)
|
||||
std::string ssSwitchFullName = ptrSwitchVarBase->GetName() + m_ssValueNode;
|
||||
m_ssValueNode = ssSwitchFullName;
|
||||
|
||||
// The type must be a variable type
|
||||
CVariableEntity* pVarEntityBase = ptrSwitchVarBase->Get<CVariableEntity>();
|
||||
if (!pVarEntityBase)
|
||||
throw CCompileException(m_ssSwitchVar,
|
||||
"The switch case is not determined by a member variable nor a predefined type.");
|
||||
|
||||
// The parent of the base is the common parent of both the switch var and the union.
|
||||
m_ptrContainer = ptrSwitchVarBase->GetParentEntity();
|
||||
if (!m_ptrContainer)
|
||||
throw CCompileException(m_ssSwitchVar,
|
||||
"The switch case variable and the union do not share a common parent.");
|
||||
|
||||
// Find the value node of the switch variable (in case it is a child some layers deep).
|
||||
CValueNodePtr ptrSwitchValueNode;
|
||||
if (!m_ssValueNode.empty())
|
||||
m_ptrSwitchValueNode = pVarEntityBase->FindValue(m_ssValueNode);
|
||||
else
|
||||
m_ptrSwitchValueNode = pVarEntityBase->ValueRef();
|
||||
if (!m_ptrSwitchValueNode)
|
||||
throw CCompileException(m_ssSwitchVar, "Could not find the switch variable.");
|
||||
|
||||
// Change the variable type entity to a switch variable.
|
||||
m_ptrSwitchValueNode->GetDeclEntity()->Get<CVariableEntity>()->UseAsSwitchVariable();
|
||||
|
||||
// Assign the type of the variable.
|
||||
m_typedeclSwitch.SetTypeDefinitionEntityPtr(m_ptrSwitchValueNode->GetDeclEntity()->GetTypeEntity());
|
||||
m_typedeclSwitch.SetBaseType(m_ptrSwitchValueNode->GetDeclEntity()->GetBaseType());
|
||||
if (!IsIntegralDeclType(m_typedeclSwitch.GetBaseType()) &&
|
||||
m_typedeclSwitch.GetBaseType() != sdv::idl::EDeclType::decltype_enum)
|
||||
throw CCompileException(m_ssSwitchVar, "Expecting an integral or enum identifier type or variable.");
|
||||
|
||||
// Check whether one of the parents is a struct or a union and the variable is a struct member.
|
||||
CEntityPtr ptrParent = GetParentEntity();
|
||||
if (!ptrParent ||
|
||||
((ptrParent->GetType() != sdv::idl::EEntityType::type_struct) &&
|
||||
(ptrParent->GetType() != sdv::idl::EEntityType::type_exception)))
|
||||
throw CCompileException(m_ssSwitchVar,
|
||||
"The union needs to be part of a struct or an exception when used with a variable based switch case.");
|
||||
while (ptrSwitchVarBase)
|
||||
{
|
||||
if (!ptrParent ||
|
||||
((ptrParent->GetType() != sdv::idl::EEntityType::type_struct) &&
|
||||
(ptrParent->GetType() != sdv::idl::EEntityType::type_exception)))
|
||||
throw CCompileException(m_ssSwitchVar,
|
||||
"The variable used in the switch case must be a member of the same or parent struct or exception the union "
|
||||
"is declared in.");
|
||||
if (ptrParent->GetType() == sdv::idl::EEntityType::type_struct &&
|
||||
ptrParent == ptrSwitchVarBase->GetParentEntity())
|
||||
break;
|
||||
|
||||
ptrParent = ptrParent->GetParentEntity();
|
||||
}
|
||||
}
|
||||
|
||||
// Post process all the case statements
|
||||
std::set<std::string> setValues;
|
||||
bool bDefaultFound = false;
|
||||
for (CEntityPtr ptrEntity : m_lstDeclMembers)
|
||||
{
|
||||
CCaseEntry* pCaseEntry = ptrEntity->Get<CCaseEntry>();
|
||||
if (!pCaseEntry) throw CCompileException("Internal error: unexpected entity stored at union.");
|
||||
pCaseEntry->PostProcess();
|
||||
|
||||
// Differentiate between default and standard case label...
|
||||
if (pCaseEntry->IsDefault())
|
||||
{
|
||||
if (bDefaultFound)
|
||||
throw CCompileException(pCaseEntry->GetLabelToken(), "Duplicate default switch found.");
|
||||
bDefaultFound = true;
|
||||
} else
|
||||
{
|
||||
// Check for the existence of the label.
|
||||
std::string ssLabel = pCaseEntry->GetLabel();
|
||||
if (m_setValues.find(ssLabel) != m_setValues.end())
|
||||
throw CCompileException(pCaseEntry->GetLabelToken(), "Duplicate switch case label found.");
|
||||
m_setValues.insert(ssLabel);
|
||||
}
|
||||
}
|
||||
|
||||
// If supported create the value node for the definition (this allows assignments of values to this entity).
|
||||
CreateValueNode();
|
||||
}
|
||||
|
||||
bool CUnionEntity::Supports(EDefinitionSupport eSupport) const
|
||||
{
|
||||
switch (eSupport)
|
||||
{
|
||||
case EDefinitionSupport::support_case_declaration: return true;
|
||||
case EDefinitionSupport::support_variable: return false;
|
||||
case EDefinitionSupport::support_const_variable: return false;
|
||||
case EDefinitionSupport::support_typedef: return false;
|
||||
case EDefinitionSupport::support_struct: return false;
|
||||
case EDefinitionSupport::support_union: return false;
|
||||
case EDefinitionSupport::support_enum: return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CUnionEntity::CreateValueNode()
|
||||
{
|
||||
// Create a compound type value node for this definition.
|
||||
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
|
||||
}
|
||||
|
||||
bool CUnionEntity::RequireDeclaration() const
|
||||
{
|
||||
// Require a declaration when unnamed union.
|
||||
return !ForwardDeclaration() && IsUnnamed();
|
||||
}
|
||||
|
||||
bool CUnionEntity::AllowAutoTransparentDeclaration() const
|
||||
{
|
||||
return !ForwardDeclaration() && IsUnnamed();
|
||||
}
|
||||
|
||||
void CUnionEntity::GetSwitchCaseType(sdv::idl::EDeclType& reType, CEntityPtr& rptrType, CValueNodePtr& rptrValue)
|
||||
{
|
||||
reType = m_typedeclSwitch.GetBaseType();
|
||||
rptrType = m_typedeclSwitch.GetTypeDefinitionEntityPtr();
|
||||
if (m_ptrSwitchValueNode) rptrValue = m_ptrSwitchValueNode;
|
||||
}
|
||||
233
sdv_executables/sdv_idl_compiler/entities/union_entity.h
Normal file
233
sdv_executables/sdv_idl_compiler/entities/union_entity.h
Normal file
@@ -0,0 +1,233 @@
|
||||
#ifndef UNION_ENTITY_H
|
||||
#define UNION_ENTITY_H
|
||||
|
||||
#include "definition_entity.h"
|
||||
#include "struct_entity.h"
|
||||
#include "variable_entity.h"
|
||||
#include "entity_value.h"
|
||||
#include <set>
|
||||
|
||||
/**
|
||||
* @brief The enum entry declaration.
|
||||
*/
|
||||
class CCaseEntry : public CVariableEntity, public sdv::idl::ICaseEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] bDefault When set, the entry is the default case entry.
|
||||
*/
|
||||
CCaseEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bDefault);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CCaseEntry() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the case label string. Overload of sdv::idl::ICaseEntity::GetLabel.
|
||||
* @return The label string.
|
||||
*/
|
||||
virtual sdv::u8string GetLabel() const override;
|
||||
|
||||
/**
|
||||
* @brief Is the case a default cae entry. Overload of sdv::idl::ICaseEntity::IsDefault.
|
||||
* @return Returns whether this is the default case entry.
|
||||
*/
|
||||
virtual bool IsDefault() const override { return m_bDefault; }
|
||||
|
||||
/**
|
||||
* @brief Get the label token (used for error reporting).
|
||||
* @return Returns a reference to the variable containing the label token.
|
||||
*/
|
||||
const CToken& GetLabelToken() const;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the union entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_case_entry; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns a string with union type.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Post process the case entry.
|
||||
*/
|
||||
void PostProcess();
|
||||
|
||||
/**
|
||||
* @brief The entity doesn't support assignments. Overload of CDeclarationEntity::SupportAssignments.
|
||||
* @return Returns whether assignments are supported (which is not the case).
|
||||
*/
|
||||
virtual bool SupportAssignments() const override { return false; }
|
||||
|
||||
private:
|
||||
bool m_bDefault = false; ///< When set, the case entry is the default case entry.
|
||||
CToken m_tokenLabel; ///< Label token.
|
||||
CEntityPtr m_ptrLabel; ///< The case label entity.
|
||||
CTokenList m_lstCaseValue; ///< Case value token list parsed during post processing.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The struct definition of an IDL file.
|
||||
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
|
||||
* and unions.
|
||||
*/
|
||||
class CUnionEntity : public CStructEntity, public sdv::idl::IUnionEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
*/
|
||||
CUnionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CUnionEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Return the switch interpretation. Overload of sdv::idl::IUnionEntity::GetSwitchInterpretation.
|
||||
* @return The interpretation of the switch case of this union.
|
||||
*/
|
||||
virtual sdv::idl::IUnionEntity::ESwitchInterpret GetSwitchInterpretation() const override;
|
||||
|
||||
/**
|
||||
* @brief Return type information for the switch case. If the switch case is type base, this is the type information
|
||||
* that is used to select. If the switch case is variable based, this is the type of the variable. Overload of
|
||||
* sdv::idl::IUnionEntity::GetSwitchType.
|
||||
* @param[out] reType Reference to the declaration type (either enum or an integral type).
|
||||
* @param[out] rpType Reference to the type entity if existing.
|
||||
*/
|
||||
virtual void GetSwitchType(/*out*/ sdv::idl::EDeclType& reType, /*out*/ sdv::IInterfaceAccess*& rpType) const;
|
||||
|
||||
/**
|
||||
* @brief Get the switch variable information if the switch case is variable based. Will be empty/NULL when the switch
|
||||
* case is type based. Overload of sdv::idl::IUnionEntity::GetSwitchVar.
|
||||
* @param[out] rssVarStr Reference to the string receiving the exact scoped declaration name of the switch variable if
|
||||
* the interpretation is variable based. The variable name uses the scope separator '::' to define the common parent
|
||||
* definition and the member separator '.' to define the variable declaration as member from the common parent.
|
||||
* @param[out] rpVarEntity Reference to the variable entity if the interpretation is variable based.
|
||||
* @param[out] rpVarContainer Reference to the variable entity of the container of both the switch variable and the
|
||||
* union.
|
||||
*/
|
||||
virtual void GetSwitchVar(/*out*/ sdv::u8string& rssVarStr, /*out*/ sdv::IInterfaceAccess*& rpVarEntity,
|
||||
/*out*/ sdv::IInterfaceAccess*& rpVarContainer) const;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the union type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_union; }
|
||||
|
||||
/**
|
||||
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns the declaration type string.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Process the definition addendum.
|
||||
* @details Process the definition addendum following the definition statement before the content definition. The default
|
||||
* implementation checks for an inheritance list.
|
||||
*/
|
||||
virtual void ProcessDefinitionAddendum() override;
|
||||
|
||||
/**
|
||||
* @brief Postprocess the switch/case assignments.
|
||||
*/
|
||||
void PostProcess();
|
||||
|
||||
/**
|
||||
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
|
||||
* @param[in] eSupport The type of support that is requested.
|
||||
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
|
||||
*/
|
||||
virtual bool Supports(EDefinitionSupport eSupport) const override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support anonymous naming?
|
||||
* @details The default implementation is that anonymous naming is not supported.
|
||||
* @details Returns whether the entity supports inheritance.
|
||||
* @return Returns whether anonymous naming is supported.
|
||||
*/
|
||||
virtual bool SupportsAnonymous() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
|
||||
* @details Create the value node and assign the value node to the ValueRef() reference..
|
||||
*/
|
||||
virtual void CreateValueNode() override;
|
||||
|
||||
/**
|
||||
* @brief Does the definition require a declaration? Overload of CDefinitionEntity::RequireDeclaration.
|
||||
* @return Returns whether a declaration is required.
|
||||
*/
|
||||
virtual bool RequireDeclaration() const override;
|
||||
|
||||
/**
|
||||
* @brief Does the definition allow automatic transparent declaration if not present? Overload of
|
||||
* CDefinitionEntity::AllowAutoTransparentDeclaration.
|
||||
* @details When set an automatic transparent declaration is allowed without an explicit variable declaration. Currently this
|
||||
* is only the case with unions with a variable based switch type.
|
||||
* @return Returns whether the definition allows an automatic transparent declaration.
|
||||
*/
|
||||
virtual bool AllowAutoTransparentDeclaration() const override;
|
||||
|
||||
/**
|
||||
* @brief Get switch case type.
|
||||
* @param[out] reType Reference to the base type of the switch variable.
|
||||
* @param[out] rptrType Reference to the type definition of the switch variable. Can be null if the switch uses a basic type.
|
||||
* @param[out] rptrValue Reference to the value node of the switch variable. Can be null if the switch is determined by a type.
|
||||
*/
|
||||
void GetSwitchCaseType(sdv::idl::EDeclType& reType, CEntityPtr& rptrType, CValueNodePtr& rptrValue);
|
||||
|
||||
private:
|
||||
/// Switch case interpretation.
|
||||
sdv::idl::IUnionEntity::ESwitchInterpret m_eSwitchInterpret = sdv::idl::IUnionEntity::ESwitchInterpret::switch_type;
|
||||
std::string m_ssSwitchVar; ///< Switch name
|
||||
CTypeDeclaration m_typedeclSwitch; ///< The identifier within the switch case.
|
||||
std::string m_ssValueNode; ///< Value node of the variable. If not existing the switch could either be
|
||||
///< a type or a variable entity.
|
||||
CEntityPtr m_ptrContainer; ///< The common container of both the switch variable and the union if the
|
||||
///< switch case is variable based.
|
||||
std::set<std::string> m_setValues; ///< Case entry values.
|
||||
CValueNodePtr m_ptrSwitchValueNode; ///< Value node of the switch entity of a variable based switch.
|
||||
|
||||
};
|
||||
|
||||
#endif // !defined(UNION_ENTITY_H)
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "variable_entity.h"
|
||||
#include "typedef_entity.h"
|
||||
#include "../exception.h"
|
||||
|
||||
CVariableEntity::CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bConst, bool bAnonymous) :
|
||||
CDeclarationEntity(rptrContext, ptrParent), m_bConst(bConst), m_bAnonymous(bAnonymous)
|
||||
{}
|
||||
|
||||
CVariableEntity::CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList,
|
||||
bool bConst, bool bAnonymous) :
|
||||
CDeclarationEntity(rptrContext, ptrParent, rlstTokenList), m_bConst(bConst), m_bAnonymous(bAnonymous)
|
||||
{}
|
||||
|
||||
std::string CVariableEntity::GetDeclTypeStr(bool bResolveTypedef) const
|
||||
{
|
||||
if (GetTypeEntity())
|
||||
return GetTypeEntity()->GetDeclTypeStr(bResolveTypedef);
|
||||
else
|
||||
return DeclTypeToString(GetBaseType());
|
||||
}
|
||||
|
||||
void CVariableEntity::Process()
|
||||
{
|
||||
CDeclarationEntity::Process();
|
||||
|
||||
// TODO: Const variables cannot contain:
|
||||
// - dynamic arrays when no assignment is there
|
||||
// - interfaces
|
||||
// - structure or unions with unassigned dynamic arrays or interfaces
|
||||
}
|
||||
|
||||
135
sdv_executables/sdv_idl_compiler/entities/variable_entity.h
Normal file
135
sdv_executables/sdv_idl_compiler/entities/variable_entity.h
Normal file
@@ -0,0 +1,135 @@
|
||||
#ifndef DECLARATOR_ENTITY_H
|
||||
#define DECLARATOR_ENTITY_H
|
||||
|
||||
#include "declaration_entity.h"
|
||||
|
||||
/**
|
||||
* @brief The variable declaration.
|
||||
*/
|
||||
class CVariableEntity : public CDeclarationEntity
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] bConst When set, the variable is defined as const.
|
||||
* @param[in] bAnonymous When set, the variable is part of a struct and anonymous (unnamed and not declared) so its members are
|
||||
* seen as members of the struct. For example, used with unions.
|
||||
*/
|
||||
CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bConst, bool bAnonymous);
|
||||
|
||||
/**
|
||||
* @brief Constructor using the provided token-list to process the code.
|
||||
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
|
||||
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
|
||||
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
|
||||
* @param[in] bConst When set, the variable is defined as const.
|
||||
* @param[in] bAnonymous When set, the variable is part of a struct and anonymous (unnamed and not declared) so its members are
|
||||
* seen as members of the struct. For example, used with unions.
|
||||
*/
|
||||
CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList, bool bConst,
|
||||
bool bAnonymous);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CVariableEntity() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the entity. Overload of CEntity::GetType.
|
||||
* @return Returns the entity type.
|
||||
*/
|
||||
virtual sdv::idl::EEntityType GetType() const override
|
||||
{
|
||||
return m_bPartOfSwitch ? sdv::idl::EEntityType::type_switch_variable : sdv::idl::EEntityType::type_variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the qualified type of the entity. Overload of CEntity::GetDeclTypeStr.
|
||||
* @attention To get the qualified type including array sizes, use the GetDeclTypeStr of the CEntityValueNode class.
|
||||
* @details The qualified type consists of "<base type> <type identifier>".
|
||||
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
|
||||
* @return Returns the type string.
|
||||
*/
|
||||
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
|
||||
|
||||
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
|
||||
// cppcheck-suppress uselessOverride
|
||||
/**
|
||||
* @brief Process the code. Overload of CEntity::Process.
|
||||
*/
|
||||
virtual void Process() override;
|
||||
|
||||
/**
|
||||
* @brief Does the entity support assignments? Overload of CDeclarationEntity::SupportAssignments.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportAssignments() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Can the entity be used for assignments of complex types? Overload of
|
||||
* CDeclarationEntity::CanSupportComplexTypeAssignments.
|
||||
* @return Returns 'true' when the entity defined as declaration; 'false' otherwise.
|
||||
*/
|
||||
virtual bool CanSupportComplexTypeAssignments() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
|
||||
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportArrays() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
|
||||
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsReadOnly() const override { return m_bConst; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity require an assignment? Overload of CDeclarationEntity::RequiresAssignment.
|
||||
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
|
||||
*/
|
||||
virtual bool RequiresAssignment() const override { return m_bConst; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support multiple declarations on one line of code? Overload of
|
||||
* CDeclarationEntity::SupportMultipleDeclarations.
|
||||
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportMultipleDeclarations() const override { return true; }
|
||||
|
||||
/**
|
||||
* @brief Is the entity anonymous when used in a struct/union (unnamed and not declared)? Overload of
|
||||
* IDeclarationEntity::IsAnonymous.
|
||||
* @return Returns 'true' when the entity is anonymous; 'false' otherwise.
|
||||
*/
|
||||
virtual bool IsAnonymous() const override { return m_bAnonymous; }
|
||||
|
||||
/**
|
||||
* @brief Enable the variable to be used in a union switch.
|
||||
*/
|
||||
void UseAsSwitchVariable() { m_bPartOfSwitch = true; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Set the variable as anonymous variable (unnamed and not declared).
|
||||
*/
|
||||
void SetAnonymous() { m_bAnonymous = true; }
|
||||
|
||||
/**
|
||||
* @brief Does the entity support an interface as base type (non-const variables, operations and parameters do)?
|
||||
* @details Returns whether the entity supports the an interface as base type base type. Default value is 'false'.
|
||||
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
|
||||
*/
|
||||
virtual bool SupportInterface() const override { return !m_bConst; }
|
||||
|
||||
private:
|
||||
bool m_bConst = false; ///< When set, the variable is defined as const.
|
||||
bool m_bAnonymous = false; ///< When set, the variable declared anonymous (unnamed and not declared) so its members
|
||||
///< are directly part of the parent struct.
|
||||
bool m_bPartOfSwitch = false; ///< When set, the variable is used in a union switch.
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(DECLARATOR_ENTITY_H)
|
||||
320
sdv_executables/sdv_idl_compiler/environment.cpp
Normal file
320
sdv_executables/sdv_idl_compiler/environment.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "environment.h"
|
||||
#include "lexer.h"
|
||||
#include "codepos.h"
|
||||
#include "token.h"
|
||||
#include "codepos.h"
|
||||
#include "lexer.h"
|
||||
#include <cuchar>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
|
||||
CIdlCompilerEnvironment::CIdlCompilerEnvironment()
|
||||
{}
|
||||
|
||||
CIdlCompilerEnvironment::CIdlCompilerEnvironment(const std::vector<std::string>& rvecArgs) :
|
||||
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
|
||||
{
|
||||
// Create a classic argument array
|
||||
std::vector<const char*> vecArgPtrs;
|
||||
for (const std::string& rssArg : rvecArgs)
|
||||
vecArgPtrs.push_back(rssArg.c_str());
|
||||
|
||||
// Call the constructor
|
||||
*this = CIdlCompilerEnvironment(vecArgPtrs.size(), &vecArgPtrs.front());
|
||||
}
|
||||
|
||||
sdv::interface_t CIdlCompilerEnvironment::GetInterface(sdv::interface_id idInterface)
|
||||
{
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
|
||||
return static_cast<sdv::IInterfaceAccess*>(this);
|
||||
if (idInterface == sdv::GetInterfaceId<sdv::idl::ICompilerOption>())
|
||||
return static_cast<sdv::idl::ICompilerOption*>(this);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::filesystem::path CIdlCompilerEnvironment::GetNextFile()
|
||||
{
|
||||
m_iFileIndex++;
|
||||
if (static_cast<size_t>(m_iFileIndex) >= m_vecFileNames.size()) return std::filesystem::path();
|
||||
return m_vecFileNames[static_cast<size_t>(m_iFileIndex)];
|
||||
}
|
||||
|
||||
void CIdlCompilerEnvironment::AddDefinition(const char* szDefinition)
|
||||
{
|
||||
CCodePos code(szDefinition);
|
||||
SLexerDummyCallback sCallback;
|
||||
CLexer lexer(&sCallback, CaseSensitiveTypeExtension());
|
||||
|
||||
// Read the macro name
|
||||
CToken sNameToken = lexer.GetToken(code, nullptr);
|
||||
if (!sNameToken || sNameToken.GetType() != ETokenType::token_identifier)
|
||||
throw CCompileException(code.GetLocation(), "Definition name missing.");
|
||||
|
||||
// Check for the next character. If there is no space in between and the next token is a left parenthesis, there are
|
||||
// parameters.
|
||||
bool bHasParam = false;
|
||||
std::vector<std::string> vecParams;
|
||||
CToken sSymbolToken;
|
||||
if (*code == '(')
|
||||
{
|
||||
// Get the left parenthesis as a token.
|
||||
sSymbolToken = lexer.GetToken(code, nullptr);
|
||||
|
||||
// Parameter bracket has been provided
|
||||
bHasParam = true;
|
||||
if (sSymbolToken != "(")
|
||||
throw CCompileException(sSymbolToken, "Invalid character for macro definition; expecting '('.");
|
||||
|
||||
// Read zero or more parameter
|
||||
bool bDone = false;
|
||||
bool bInitial = true;
|
||||
while (!bDone)
|
||||
{
|
||||
// Check for closing bracket
|
||||
sSymbolToken = lexer.GetToken(code, nullptr);
|
||||
if (bInitial && sSymbolToken == ")")
|
||||
bDone = true;
|
||||
else if (sSymbolToken.GetType() != ETokenType::token_identifier)
|
||||
throw CCompileException(sSymbolToken, "Expecting a parameter name.");
|
||||
|
||||
bInitial = false;
|
||||
if (!bDone)
|
||||
{
|
||||
// The token should represent an identifier
|
||||
CToken sIdentifierToken = sSymbolToken;
|
||||
|
||||
// Check for duplicates
|
||||
if (std::find(vecParams.begin(), vecParams.end(), static_cast<std::string>(sIdentifierToken)) != vecParams.end())
|
||||
throw CCompileException(sSymbolToken, "Duplicate parameter names for macro definition.");
|
||||
|
||||
// Add the parameter to the list
|
||||
vecParams.push_back(sIdentifierToken);
|
||||
|
||||
// Check for a comma or a right parenthesis
|
||||
sSymbolToken = lexer.GetToken(code, nullptr);
|
||||
if (sSymbolToken == ")")
|
||||
bDone = true;
|
||||
else if (sSymbolToken != ",")
|
||||
throw CCompileException(sSymbolToken, "Unexpected symbol in parameter list.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for an equal sign
|
||||
sSymbolToken = lexer.GetToken(code, nullptr);
|
||||
std::string ssValue;
|
||||
if (sSymbolToken)
|
||||
{
|
||||
// Expect assignment symbol
|
||||
if (sSymbolToken != "=")
|
||||
throw CCompileException(sSymbolToken, "Invalid format.");
|
||||
ssValue = static_cast<std::string>(code.GetLocation());
|
||||
} else
|
||||
{
|
||||
// Expect no more code
|
||||
if (!code.HasEOF())
|
||||
throw CCompileException(sSymbolToken, "Invalid format.");
|
||||
}
|
||||
|
||||
// Create and store the macro structure
|
||||
CMacro macro(static_cast<std::string>(sNameToken).c_str(), bHasParam ? &vecParams : nullptr, ssValue.c_str());
|
||||
|
||||
// Add the macro
|
||||
AddDefinition(code.GetLocation(), macro);
|
||||
}
|
||||
|
||||
void CIdlCompilerEnvironment::AddDefinition(const CToken& rtoken, const CMacro& rMacro)
|
||||
{
|
||||
// Check for the macro to exist already; if so and different, throw exception. If not, add to macro map.
|
||||
CMacroMap::iterator itMacro = m_mapMacros.find(rMacro.GetName());
|
||||
if (itMacro != m_mapMacros.end())
|
||||
{
|
||||
if (itMacro->second != rMacro)
|
||||
throw CCompileException(rtoken, "Redefinition of macro with different content.");
|
||||
} else
|
||||
m_mapMacros.emplace(std::move(CMacroMap::value_type(rMacro.GetName(), rMacro)));
|
||||
}
|
||||
|
||||
void CIdlCompilerEnvironment::RemoveDefinition(const char* szMacro)
|
||||
{
|
||||
if (!szMacro) return;
|
||||
CMacroMap::iterator itMacro = m_mapMacros.find(szMacro);
|
||||
if (itMacro != m_mapMacros.end())
|
||||
m_mapMacros.erase(itMacro);
|
||||
}
|
||||
|
||||
bool CIdlCompilerEnvironment::Defined(const char* szMacro) const
|
||||
{
|
||||
if (!szMacro) return false;
|
||||
return m_mapMacros.find(szMacro) != m_mapMacros.end();
|
||||
}
|
||||
|
||||
bool CIdlCompilerEnvironment::TestAndExpand(const std::string& rssIdentifier, CCodePos& rcode, bool bInMacroExpansion /*= false*/,
|
||||
CUsedMacroSet& rsetPreviousExpanded /*= CUsedMacroSet()*/) const
|
||||
{
|
||||
if (rssIdentifier.empty()) return false;
|
||||
|
||||
// Which macro set to use?
|
||||
CUsedMacroSet& rsetUsedMacros = rsetPreviousExpanded.empty() ? m_setMacrosUsedInExpansion : rsetPreviousExpanded;
|
||||
|
||||
// If the provided identifier was created as part of a previous macro expansion (bInMacroExpansion is true) or the macro is
|
||||
// part of the current expansion (rsetPreviousExpanded is not empty), check whether the identifier defines a macro that was
|
||||
// used in the previous expansion, which is not allowed.
|
||||
// If no previous expansion took place or current expansion takes place, clear the expansion set.
|
||||
if (bInMacroExpansion || !rsetPreviousExpanded.empty())
|
||||
{
|
||||
if (rsetUsedMacros.find(rssIdentifier) != rsetUsedMacros.end())
|
||||
return false;
|
||||
} else
|
||||
rsetUsedMacros.clear();
|
||||
|
||||
// Test for the existence of a macro.
|
||||
CMacroMap::const_iterator itMacro = m_mapMacros.find(rssIdentifier);
|
||||
if (itMacro == m_mapMacros.end()) return false;
|
||||
|
||||
// Does the macro need parameters?
|
||||
CToken token = rcode.GetLocation();
|
||||
std::vector<std::string> vecParams;
|
||||
if (itMacro->second.ExpectParameters())
|
||||
{
|
||||
// Peek for left parenthesis. If not available, this is not an error. Do not deal with the macro
|
||||
CCodePos codeTemp(rcode);
|
||||
SLexerDummyCallback sCallback;
|
||||
CLexer lexer(&sCallback, CaseSensitiveTypeExtension());
|
||||
if (lexer.GetToken(codeTemp, nullptr) != "(")
|
||||
return false;
|
||||
|
||||
// Get the parenthesis once more.
|
||||
lexer.GetToken(rcode, nullptr);
|
||||
|
||||
std::string ssParam;
|
||||
CToken locationParam = rcode.GetLocation();
|
||||
auto fnTrimCheckAndAdd = [&]()
|
||||
{
|
||||
// Erase the whitespace from the beginning of the string
|
||||
std::string::iterator itStart = std::find_if(ssParam.begin(), ssParam.end(),
|
||||
[](char c)
|
||||
{ return !std::isspace<char>(c, std::locale::classic()); });
|
||||
ssParam.erase(ssParam.begin(), itStart);
|
||||
|
||||
// Ersase the whitespace form the end of the string
|
||||
std::string::reverse_iterator itEnd = std::find_if(ssParam.rbegin(), ssParam.rend(),
|
||||
[](char c)
|
||||
{ return !std::isspace<char>(c, std::locale::classic()); });
|
||||
ssParam.erase(itEnd.base(), ssParam.end());
|
||||
|
||||
// Check for a non-empty string
|
||||
if (ssParam.empty())
|
||||
throw CCompileException(locationParam, "Missing parameter for macro");
|
||||
|
||||
// Add the parameter to the vector.
|
||||
vecParams.emplace_back(std::move(ssParam));
|
||||
|
||||
// Set the token for the new parameter
|
||||
locationParam = rcode.GetLocation();
|
||||
};
|
||||
|
||||
bool bDone = false;
|
||||
size_t nInsideParenthesis = 0;
|
||||
while (!bDone)
|
||||
{
|
||||
switch(*rcode)
|
||||
{
|
||||
case '(':
|
||||
nInsideParenthesis++;
|
||||
ssParam += *rcode;
|
||||
token = rcode.GetLocation();
|
||||
break;
|
||||
case ')':
|
||||
if (nInsideParenthesis)
|
||||
{
|
||||
nInsideParenthesis--;
|
||||
ssParam += *rcode;
|
||||
} else
|
||||
{
|
||||
fnTrimCheckAndAdd();
|
||||
bDone = true;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (nInsideParenthesis)
|
||||
ssParam += *rcode;
|
||||
else
|
||||
fnTrimCheckAndAdd();
|
||||
break;
|
||||
case '\0':
|
||||
throw CCompileException(rcode.GetLocation(), "Unexpected end of file while parsing macro parameters.");
|
||||
break;
|
||||
default:
|
||||
ssParam += *rcode;
|
||||
break;
|
||||
}
|
||||
++rcode;
|
||||
}
|
||||
}
|
||||
|
||||
// The macro will be expanded, add it to the expansion set
|
||||
rsetUsedMacros.insert(rssIdentifier);
|
||||
|
||||
// Expand the macro and prepend the string to the code.
|
||||
rcode.PrependCode(itMacro->second.Expand(*this, token, vecParams, rsetUsedMacros));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIdlCompilerEnvironment::ResolveConst() const
|
||||
{
|
||||
return m_bResolveConst;
|
||||
}
|
||||
|
||||
bool CIdlCompilerEnvironment::NoProxyStub() const
|
||||
{
|
||||
return m_bNoPS;
|
||||
}
|
||||
|
||||
const std::string& CIdlCompilerEnvironment::GetProxStubCMakeTarget() const
|
||||
{
|
||||
return m_ssProxyStubLibName;
|
||||
}
|
||||
|
||||
sdv::u8string CIdlCompilerEnvironment::GetOption(const sdv::u8string& rssOption) const
|
||||
{
|
||||
return GetOptionN(rssOption, 0);
|
||||
}
|
||||
|
||||
uint32_t CIdlCompilerEnvironment::GetOptionCnt(const sdv::u8string& rssOption) const
|
||||
{
|
||||
if (rssOption.empty()) return 0;
|
||||
if (rssOption == sdv::idl::ssOptionDevEnvDir)
|
||||
return 1;
|
||||
else if (rssOption == sdv::idl::ssOptionOutDir)
|
||||
return 1;
|
||||
else if (rssOption == sdv::idl::ssOptionFilename)
|
||||
return 1;
|
||||
else if (rssOption == sdv::idl::ssOptionFilePath)
|
||||
return 1;
|
||||
else if (rssOption == sdv::idl::ssOptionCodeGen)
|
||||
return 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdv::u8string CIdlCompilerEnvironment::GetOptionN(const sdv::u8string& rssOption, uint32_t nIndex) const
|
||||
{
|
||||
if (rssOption.empty()) return sdv::u8string();
|
||||
if (nIndex >= GetOptionCnt(rssOption)) return sdv::u8string();
|
||||
|
||||
sdv::u8string ssValue;
|
||||
if (rssOption == sdv::idl::ssOptionDevEnvDir)
|
||||
ssValue = m_pathCompilerPath.parent_path().generic_u8string();
|
||||
else if (rssOption == sdv::idl::ssOptionOutDir)
|
||||
ssValue = "";
|
||||
else if (rssOption == sdv::idl::ssOptionFilename)
|
||||
ssValue = "";
|
||||
else if (rssOption == sdv::idl::ssOptionFilePath)
|
||||
ssValue = "";
|
||||
else if (rssOption == sdv::idl::ssOptionCodeGen)
|
||||
ssValue = "";
|
||||
return ssValue;
|
||||
}
|
||||
|
||||
316
sdv_executables/sdv_idl_compiler/environment.h
Normal file
316
sdv_executables/sdv_idl_compiler/environment.h
Normal file
@@ -0,0 +1,316 @@
|
||||
#ifndef ENV_H
|
||||
#define ENV_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
#include "logger.h"
|
||||
#include "core_idl_backup.h"
|
||||
#include "../global/cmdlnparser/cmdlnparser.h"
|
||||
#include "includes.h"
|
||||
#include "macro.h"
|
||||
#include "token.h"
|
||||
#include "exception.h"
|
||||
|
||||
/**
|
||||
* @brief Parser environment management class.
|
||||
*/
|
||||
class CIdlCompilerEnvironment
|
||||
: public sdv::idl::ICompilerOption
|
||||
, public sdv::IInterfaceAccess
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CIdlCompilerEnvironment();
|
||||
|
||||
/**
|
||||
* @brief Constructor with program arguments.
|
||||
* @param[in] rvecArgs Reference to the vector with program arguments
|
||||
*/
|
||||
CIdlCompilerEnvironment(const std::vector<std::string>& rvecArgs);
|
||||
|
||||
/**
|
||||
* @brief Constructor with program arguments.
|
||||
* @tparam TCharType Character type.
|
||||
* @param[in] nArgs The amount of arguments.
|
||||
* @param[in] rgszArgs Array of arguments.
|
||||
*/
|
||||
template <typename TCharType>
|
||||
CIdlCompilerEnvironment(size_t nArgs, const TCharType** rgszArgs);
|
||||
|
||||
/**
|
||||
* @brief Get access to another interface. Overload of IInterfaceAccess::GetInterface.
|
||||
* @param[in] idInterface The interface id to get access to.
|
||||
* @return Returns a pointer to the interface or NULL when the interface is not supported.
|
||||
*/
|
||||
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
|
||||
|
||||
/**
|
||||
* @brief Get the path of the next file.
|
||||
* @return Returns the path to the next file or an empty path.
|
||||
*/
|
||||
std::filesystem::path GetNextFile();
|
||||
|
||||
/**
|
||||
* @brief Help was requested on the command line.
|
||||
* @return Returns 'true' when help was requested. Otherwise returns 'false'.
|
||||
*/
|
||||
bool Help() const { return m_bCLHelp; }
|
||||
|
||||
/**
|
||||
* @brief Show command line help.
|
||||
*/
|
||||
void ShowHelp() const { m_cmdln.PrintHelp(std::cout); }
|
||||
|
||||
/**
|
||||
* @brief Version information was requested on the command line.
|
||||
* @return Returns 'true' when version info was requested. Otherwise returns 'false'.
|
||||
*/
|
||||
bool Version() const { return m_bCLVersion; }
|
||||
|
||||
/**
|
||||
* @brief Get the vector of include directories.
|
||||
* @return Reference to the vector of include directories.
|
||||
*/
|
||||
const std::vector<std::filesystem::path>& GetIncludeDirs() const { return m_vecIncludeDirs; }
|
||||
|
||||
/**
|
||||
* @brief Get the output directory.
|
||||
* @return The output directory.
|
||||
*/
|
||||
std::filesystem::path GetOutputDir() const { return m_pathOutputDir; }
|
||||
|
||||
/**
|
||||
* @brief Add macro definition in the form of name, name=value or name(arg1, arg2, arg3)=value.
|
||||
* @param[in] szDefinition The definition string
|
||||
*/
|
||||
void AddDefinition(const char* szDefinition);
|
||||
|
||||
/**
|
||||
* @brief Add macro definition.
|
||||
* @param[in] rtoken Token in the source file of the provided macro.
|
||||
* @param[in] rMacro Reference to the macro to add.
|
||||
*/
|
||||
void AddDefinition(const CToken& rtoken, const CMacro& rMacro);
|
||||
|
||||
/**
|
||||
* @brief Remove macro definition.
|
||||
* @param[in] szMacro The name of the macro.
|
||||
* @remarks If the macro doesn#t exists, doesn't do anything.
|
||||
*/
|
||||
void RemoveDefinition(const char* szMacro);
|
||||
|
||||
/**
|
||||
* @brief Check whether a macro definition exists.
|
||||
* @param[in] szMacro The name of the macro.
|
||||
* @returns Returns 'true' when the definition exists; 'false' otherwise.
|
||||
*/
|
||||
bool Defined(const char* szMacro) const;
|
||||
|
||||
/**
|
||||
* @brief Test for a macro and replace the code.
|
||||
* @details This function will check for the existence of the macro with the supplied name. If it does, it will read any
|
||||
* parameter from the code (depends on whether the macro needs parameters) and create a string with the filled in parameters.
|
||||
* This string, then, is prepended to the code replacing the identifiert and its optional parameters. Reparsing of the code
|
||||
* needs to take place - the return value is 'true'. If there is no macro with the supplied name, the return value is 'false'
|
||||
* and the supplied identifier is to be treated as an identifier.
|
||||
* Macro parameters can have commas if they are parenthesized before.
|
||||
* The value can have the '#' unary operator to stringificate the following parameter and the '##' operator to join the
|
||||
* preceding or succeeding operator to the adjacent identifier.
|
||||
* @param[in] rssIdentifier Reference to the string object containing the name of the identifier to test for macro definition.
|
||||
* @param[in, out] rcode The code holding the potential parameters and to be replaced and prepended with the resolved macro.
|
||||
* @param[in] bInMacroExpansion Set 'true' when the identifier was the (part) result of a macro expansion. If this is the
|
||||
* case, previously used macros cannot be reused - to prevent circular expansion.
|
||||
* @param[in, out] rsetPreviousExpanded Reference to the set of previously expanded macros, preventing circular expansion. If
|
||||
* the used macro set is empty, use the default set of the environment. This set will b eextended with macros used within the
|
||||
* macro expansion.
|
||||
* @return Returns 'true' if macro replacement was successful, or 'false' when the identifier is not a macro.
|
||||
*/
|
||||
bool TestAndExpand(const std::string& rssIdentifier,
|
||||
CCodePos& rcode,
|
||||
bool bInMacroExpansion,
|
||||
CUsedMacroSet& rsetPreviousExpanded) const;
|
||||
|
||||
/**
|
||||
* @brief Test for a macro and replace the code.
|
||||
* @details This function will check for the existence of the macro with the supplied name. If it does, it will read any
|
||||
* parameter from the code (depends on whether the macro needs parameters) and create a string with the filled in parameters.
|
||||
* This string, then, is prepended to the code replacing the identifiert and its optional parameters. Reparsing of the code
|
||||
* needs to take place - the return value is 'true'. If there is no macro with the supplied name, the return value is 'false'
|
||||
* and the supplied identifier is to be treated as an identifier.
|
||||
* Macro parameters can have commas if they are parenthesized before.
|
||||
* The value can have the '#' unary operator to stringificate the following parameter and the '##' operator to join the
|
||||
* preceding or succeeding operator to the adjacent identifier.
|
||||
* @param[in] rssIdentifier Reference to the string object containing the name of the identifier to test for macro definition.
|
||||
* @param[in, out] rcode The code holding the potential parameters and to be replaced and prepended with the resolved macro.
|
||||
* @param[in] bInMacroExpansion Set 'true' when the identifier was the (part) result of a macro expansion. If this is the
|
||||
* case, previously used macros cannot be reused - to prevent circular expansion.
|
||||
* @return Returns 'true' if macro replacement was successful, or 'false' when the identifier is not a macro.
|
||||
*/
|
||||
bool TestAndExpand(const std::string& rssIdentifier, CCodePos& rcode, bool bInMacroExpansion = false) const
|
||||
{
|
||||
CUsedMacroSet setDummy;
|
||||
return TestAndExpand(rssIdentifier, rcode, bInMacroExpansion, setDummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolve const expressions.
|
||||
* @return Returns 'true' when const expressions should be resolved. Otherwise the expression should be exported during code
|
||||
* generation.
|
||||
*/
|
||||
bool ResolveConst() const;
|
||||
|
||||
/**
|
||||
* @brief Suppress the generation of proxy and stub code.
|
||||
* @return Returns 'true' when proxy stub code should not be generated. Otherwise the proxy and stub code should be generated.
|
||||
*/
|
||||
bool NoProxyStub() const;
|
||||
|
||||
/**
|
||||
* @brief Get library target name for the proxy stub cmake file.
|
||||
* @return Returns a reference to the target name if set in the command line or an empty string otherwise.
|
||||
*/
|
||||
const std::string& GetProxStubCMakeTarget() const;
|
||||
|
||||
/**
|
||||
* @brief Get the compiler option. Overload of sdv::idl::ICompilerOption::GetOption.
|
||||
* @param[in] rssOption Reference to the string containing the name of the option to retrieve.
|
||||
* @return The requested compiler option (if available).
|
||||
*/
|
||||
virtual sdv::u8string GetOption(/*in*/ const sdv::u8string& rssOption) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the amount of option values. Overload of sdv::idl::ICompilerOption::GetOptionCnt.
|
||||
* @param[in] rssOption Reference to the string containing the name of the option to retrieve.
|
||||
* @return The amount of option values.
|
||||
*/
|
||||
virtual uint32_t GetOptionCnt(/*in*/ const sdv::u8string& rssOption) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the compiler option. Overload of sdv::idl::ICompilerOption::GetOptionN.
|
||||
* @param[in] rssOption Reference to the string containing the name of the option to retrieve.
|
||||
* @param[in] uiIndex The index of the option value.
|
||||
* @return The requested compiler option value.
|
||||
*/
|
||||
virtual sdv::u8string GetOptionN(/*in*/ const sdv::u8string& rssOption, /*in*/ uint32_t uiIndex) const override;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Extensions
|
||||
* @return Returns true when the extension is enabled; false when not.
|
||||
*/
|
||||
bool InterfaceTypeExtension() const { return m_bEnableInterfaceTypeExtension; }
|
||||
bool ExceptionTypeExtension() const { return m_bEnableExceptionTypeExtension; }
|
||||
bool PointerTypeExtension() const { return m_bEnablePointerTypeExtension; }
|
||||
bool UnicodeExtension() const { return m_bEnableUnicodeExtension; }
|
||||
bool CaseSensitiveTypeExtension() const { return m_bEnableCaseSensitiveNameExtension; }
|
||||
bool ContextDependentNamesExtension() const { return m_bEnableContextDependentNamesExtension; }
|
||||
bool MultiDimArrayExtension() const { return m_bEnableMultiDimArrayExtension; }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
private:
|
||||
CCommandLine m_cmdln; ///< Command line parsing class.
|
||||
CMacroMap m_mapMacros; ///< Map containing macros.
|
||||
std::vector<std::filesystem::path> m_vecIncludeDirs; ///< Vector containing all search paths for finding files.
|
||||
std::vector<std::filesystem::path> m_vecFileNames; ///< Vector containing file paths of the files to process.
|
||||
std::filesystem::path m_pathOutputDir; ///< Output directory.
|
||||
mutable CUsedMacroSet m_setMacrosUsedInExpansion; ///< Set of macros used in the expansion to prevent circular expansion
|
||||
///< when the macro being expanded generate a call to itself.
|
||||
bool m_bCLHelp = false; ///< Help was requested at the command line.
|
||||
bool m_bCLVersion = false; ///< Version info was request at the command line.
|
||||
bool m_bResolveConst = false; ///< When set, store the value of a const assignment; otherwise, store
|
||||
///< the expression of the const assignment.
|
||||
bool m_bNoPS = false; ///< Doesn't generate proxy/stub code.
|
||||
std::string m_ssProxyStubLibName = "proxystub"; ///< Proxy and stub library target name in the generated cmake file.
|
||||
std::filesystem::path m_pathCompilerPath; ///< The path to the compiler.
|
||||
int32_t m_iFileIndex = -1; ///< The IDL file to process.
|
||||
bool m_bEnableInterfaceTypeExtension = true; ///< Enable the 'inteface_t', 'inteface_id' and 'null' keywords.
|
||||
bool m_bEnableExceptionTypeExtension = true; ///< Enable the 'exception_id' keyword.
|
||||
bool m_bEnablePointerTypeExtension = true; ///< Enable the 'pointer' keyword.
|
||||
bool m_bEnableUnicodeExtension = true; ///< Enable UTF-8, UTF-16 and UTF-32 character and string extensions.
|
||||
bool m_bEnableCaseSensitiveNameExtension = true; ///< Enable sensitive name restriction.
|
||||
bool m_bEnableContextDependentNamesExtension = true; ///< Enable relaxed uniqueness extension.
|
||||
bool m_bEnableMultiDimArrayExtension = true; ///< Enable multi-dimensional array support.
|
||||
};
|
||||
|
||||
template <typename TCharType>
|
||||
CIdlCompilerEnvironment::CIdlCompilerEnvironment(size_t nArgs, const TCharType** rgszArgs) :
|
||||
m_cmdln(static_cast<uint32_t>(CCommandLine::EParseFlags::no_assignment_character))
|
||||
{
|
||||
try
|
||||
{
|
||||
bool bSilent = false;
|
||||
bool bVerbose = false;
|
||||
bool bStrict = false;
|
||||
std::vector<std::string> vecMacros;
|
||||
auto& rArgHelpDef = m_cmdln.DefineOption("?", m_bCLHelp, "Show help");
|
||||
rArgHelpDef.AddSubOptionName("help");
|
||||
auto& rArgSilentDef = m_cmdln.DefineOption("s", bSilent, "Do not show any information on STDOUT. Not compatible with 'verbose'.");
|
||||
rArgSilentDef.AddSubOptionName("silent");
|
||||
auto& rArgVerboseDef = m_cmdln.DefineOption("v", bVerbose, "Provide verbose information. Not compatible with 'silent'.");
|
||||
rArgVerboseDef.AddSubOptionName("verbose");
|
||||
m_cmdln.DefineSubOption("version", m_bCLVersion, "Show version information");
|
||||
m_cmdln.DefineOption("I", m_vecIncludeDirs, "Set include directory");
|
||||
m_cmdln.DefineOption("O", m_pathOutputDir, "Set output directory");
|
||||
m_cmdln.DefineOption("D", vecMacros, "Set a macro definition in the form of macro, macro=<value>, macro(arg1,...)=<value>");
|
||||
m_cmdln.DefineSubOption("resolve_const", m_bResolveConst, "Use the calculated value for const values, instead of the defined expression.");
|
||||
m_cmdln.DefineSubOption("no_ps", m_bNoPS, "Do not create any proxy and stub code (interface definitions only).");
|
||||
m_cmdln.DefineSubOption("ps_lib_name", m_ssProxyStubLibName, "Proxy and stub library target name in the generated cmake file (default=\"proxystub\").");
|
||||
|
||||
m_cmdln.DefineGroup("Extensions", "Enable/disable compatibility extensions.");
|
||||
m_cmdln.DefineFlagSubOption("interface_type", m_bEnableInterfaceTypeExtension, "Enable/disable support of the interface type extensions 'interface_t' and 'interface_id'.Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("exception_type", m_bEnableExceptionTypeExtension, "Enable/disable support of the exception type extension 'exception_id'. Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("pointer_type", m_bEnablePointerTypeExtension, "Enable/disable support of the pointer type extension 'pointer'. Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("unicode_char", m_bEnableUnicodeExtension, "Enable/disable support of the UTF-8, UTF-16 and UTF-32 Unicode extensions. Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("case_sensitive", m_bEnableCaseSensitiveNameExtension, "Enable/disable case sensitive name restriction extension. Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("context_names", m_bEnableContextDependentNamesExtension, "Enable/disable the use of context dependent names in declarations. Default enabled.");
|
||||
m_cmdln.DefineFlagSubOption("multi_dimensional_array", m_bEnableMultiDimArrayExtension, "Enable/disable support of multi-dimensional arrays extension. Default enabled.");
|
||||
m_cmdln.DefineSubOption("strict", bStrict, "Strictly maintaining OMG-IDL conformance; disabling extensions.");
|
||||
|
||||
m_cmdln.DefineDefaultArgument(m_vecFileNames, "IDL files");
|
||||
m_cmdln.Parse(nArgs, rgszArgs);
|
||||
|
||||
// Add the macros.
|
||||
for (const std::string& rssMacro : vecMacros)
|
||||
{
|
||||
try
|
||||
{
|
||||
AddDefinition(rssMacro.c_str());
|
||||
}
|
||||
catch (const sdv::idl::XCompileError&)
|
||||
{
|
||||
throw CCompileException("Invalid command line option: -D");
|
||||
}
|
||||
}
|
||||
|
||||
// If strict, disable all extensions.
|
||||
if (bStrict)
|
||||
{
|
||||
m_bEnableInterfaceTypeExtension = false;
|
||||
m_bEnableExceptionTypeExtension = false;
|
||||
m_bEnablePointerTypeExtension = false;
|
||||
m_bEnableUnicodeExtension = false;
|
||||
m_bEnableCaseSensitiveNameExtension = false;
|
||||
m_bEnableContextDependentNamesExtension = false;
|
||||
m_bEnableMultiDimArrayExtension = false;
|
||||
}
|
||||
|
||||
// Set the verbosity mode.
|
||||
if (bSilent)
|
||||
g_log_control.SetVerbosityMode(EVerbosityMode::report_none);
|
||||
else if (bVerbose)
|
||||
g_log_control.SetVerbosityMode(EVerbosityMode::report_all);
|
||||
}
|
||||
catch (const SArgumentParseException& rsExcept)
|
||||
{
|
||||
m_bCLHelp = true;
|
||||
throw CCompileException(rsExcept.what());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined ENV_H
|
||||
50
sdv_executables/sdv_idl_compiler/exception.cpp
Normal file
50
sdv_executables/sdv_idl_compiler/exception.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "exception.h"
|
||||
#include <cassert>
|
||||
|
||||
CCompileException::CCompileException(const sdv::idl::XCompileError& rxCompileError)
|
||||
{
|
||||
static_cast<sdv::idl::XCompileError&>(*this) = rxCompileError;
|
||||
}
|
||||
|
||||
std::string CCompileException::GetPath() const
|
||||
{
|
||||
return ssFile;
|
||||
}
|
||||
|
||||
std::string CCompileException::GetReason() const
|
||||
{
|
||||
return ssReason;
|
||||
}
|
||||
|
||||
void CCompileException::SetPath(const std::filesystem::path& rpath)
|
||||
{
|
||||
if (ssFile.empty())
|
||||
ssFile = rpath.generic_u8string();
|
||||
}
|
||||
|
||||
void CCompileException::SetLocation(const CToken& rtoken)
|
||||
{
|
||||
uiLine = rtoken.GetLine();
|
||||
uiCol = rtoken.GetCol();
|
||||
ssToken = rtoken;
|
||||
}
|
||||
|
||||
uint32_t CCompileException::GetLineNo() const
|
||||
{
|
||||
return uiLine;
|
||||
}
|
||||
|
||||
uint32_t CCompileException::GetColNo() const
|
||||
{
|
||||
return uiCol;
|
||||
}
|
||||
|
||||
std::string CCompileException::GetToken() const
|
||||
{
|
||||
return ssToken;
|
||||
}
|
||||
|
||||
std::string CCompileException::GetLine() const
|
||||
{
|
||||
return ssLine;
|
||||
}
|
||||
170
sdv_executables/sdv_idl_compiler/exception.h
Normal file
170
sdv_executables/sdv_idl_compiler/exception.h
Normal file
@@ -0,0 +1,170 @@
|
||||
#ifndef EXCEPTION_H
|
||||
#define EXCEPTION_H
|
||||
|
||||
#include "logger.h"
|
||||
#include "token.h"
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
// Forward declaration
|
||||
class CParser;
|
||||
|
||||
/**
|
||||
* @brief Lexer exception
|
||||
*/
|
||||
struct CCompileException : public sdv::idl::XCompileError
|
||||
{
|
||||
friend class CParser;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Copy the compile error.
|
||||
* @param[in] rxCompileError Reference to the compile error.
|
||||
*/
|
||||
CCompileException(const sdv::idl::XCompileError& rxCompileError);
|
||||
|
||||
/**
|
||||
* @brief Constructor without token and path. The parser might add the last used token.
|
||||
* @remarks The path can be added to the exception using the SetPath function.
|
||||
* @param[in] szReason Zero terminated string containing the reason of the exception. Must not be NULL.
|
||||
* @param[in] tAdditionalReasons Optional other reasons.
|
||||
*/
|
||||
template <class... TAdditionalReason>
|
||||
explicit CCompileException(const char* szReason, TAdditionalReason... tAdditionalReasons);
|
||||
|
||||
/**
|
||||
* @brief Constructor without path.
|
||||
* @remarks The path can be added to the exception using the SetPath function.
|
||||
* @param[in] rtoken Token in the source file that triggered the exception.
|
||||
* @param[in] szReason Zero terminated string containing the reason of the exception. Must not be NULL.
|
||||
* @param[in] tAdditionalReasons Optional other reasons.
|
||||
*/
|
||||
template <class... TAdditionalReason>
|
||||
explicit CCompileException(const CToken& rtoken, const char* szReason, TAdditionalReason... tAdditionalReasons);
|
||||
|
||||
/**
|
||||
* @brief Constructor with path.
|
||||
* @param[in] rpath Reference to the source file path.
|
||||
* @param[in] rtoken Token in the source file that triggered the exception.
|
||||
* @param[in] szReason Zero terminated string containing the reason of the exception. Must not be NULL.
|
||||
* @param[in] tAdditionalReasons Optional other reasons.
|
||||
*/
|
||||
template <class... TAdditionalReason>
|
||||
explicit CCompileException(const std::filesystem::path& rpath, const CToken& rtoken,
|
||||
const char* szReason, TAdditionalReason... tAdditionalReasons);
|
||||
|
||||
/**
|
||||
* @brief Get the path.
|
||||
* @return Reference to the path of the file causing the exception (if there is one).
|
||||
*/
|
||||
std::string GetPath() const;
|
||||
|
||||
/**
|
||||
* @brief Get the reason.
|
||||
* @return The explanatory text.
|
||||
*/
|
||||
std::string GetReason() const;
|
||||
|
||||
/**
|
||||
* @brief Get the line number (starts at 1).
|
||||
* @return The line number or 0 when there is no specific code causing this error.
|
||||
*/
|
||||
uint32_t GetLineNo() const;
|
||||
|
||||
/**
|
||||
* @brief Get the column number (starts at 1).
|
||||
* @return The column number or 0 when there is no specific code causing this error.
|
||||
*/
|
||||
uint32_t GetColNo() const;
|
||||
|
||||
/**
|
||||
* @brief Get the token causing the compilation error.
|
||||
* @return The token string or an empty string when no specific code is causing this error.
|
||||
*/
|
||||
std::string GetToken() const;
|
||||
|
||||
/**
|
||||
* @brief Get the line containing the error.
|
||||
* @return The line that contains the error or an empty string when no specific code is causiong this error.
|
||||
*/
|
||||
std::string GetLine() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Set the path if not assigned before.
|
||||
* @param[in] rpath Reference to the source file path.
|
||||
*/
|
||||
void SetPath(const std::filesystem::path& rpath);
|
||||
|
||||
/**
|
||||
* @brief Set the location if not assigned before.
|
||||
* @param[in] rtoken The token that caused the exception.
|
||||
*/
|
||||
void SetLocation(const CToken& rtoken);
|
||||
};
|
||||
|
||||
template <class TParam>
|
||||
void AddParamListToString(std::stringstream& rsstream, TParam param)
|
||||
{
|
||||
rsstream << param;
|
||||
}
|
||||
|
||||
template <class TParam, class... TAdditionalParams>
|
||||
void AddParamListToString(std::stringstream& rsstream, TParam param, TAdditionalParams... tAdditionalParams)
|
||||
{
|
||||
rsstream << param;
|
||||
AddParamListToString(rsstream, tAdditionalParams...);
|
||||
}
|
||||
|
||||
template <class... TAdditionalReason>
|
||||
CCompileException::CCompileException(const char* szReason, TAdditionalReason... tAdditionalReasons) : sdv::idl::XCompileError{}
|
||||
{
|
||||
assert(szReason);
|
||||
if (szReason)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
AddParamListToString(sstream, szReason, tAdditionalReasons...);
|
||||
ssReason = sstream.str();
|
||||
}
|
||||
CLog log;
|
||||
log << "EXCEPTION: " << ssReason << std::endl;
|
||||
}
|
||||
|
||||
template <class... TAdditionalReason>
|
||||
CCompileException::CCompileException(const CToken& rtoken, const char* szReason, TAdditionalReason... tAdditionalReasons) :
|
||||
sdv::idl::XCompileError{}
|
||||
{
|
||||
assert(szReason);
|
||||
if (szReason)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
AddParamListToString(sstream, szReason, tAdditionalReasons...);
|
||||
ssReason = sstream.str();
|
||||
}
|
||||
SetLocation(rtoken);
|
||||
CLog log;
|
||||
log << "EXCEPTION " << "[" << GetLineNo() << ", " << GetColNo() << "]: " << ssReason << std::endl;
|
||||
}
|
||||
|
||||
template <class... TAdditionalReason>
|
||||
CCompileException::CCompileException(const std::filesystem::path& rpath, const CToken& rtoken,
|
||||
const char* szReason, TAdditionalReason... tAdditionalReasons) :
|
||||
CCompileException::CCompileException(rtoken, szReason, tAdditionalReasons...)
|
||||
{
|
||||
assert(szReason);
|
||||
if (szReason)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
AddParamListToString(sstream, szReason, tAdditionalReasons...);
|
||||
ssReason = sstream.str();
|
||||
}
|
||||
SetLocation(rtoken);
|
||||
ssFile = rpath.generic_u8string();
|
||||
CLog log;
|
||||
log << "EXCEPTION " << rpath.generic_u8string() << " [" << GetLineNo() << ", " << GetColNo() << "]: " << ssReason << std::endl;
|
||||
}
|
||||
|
||||
#endif // !defined EXCEPTION_H
|
||||
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)
|
||||
17
sdv_executables/sdv_idl_compiler/includes.h
Normal file
17
sdv_executables/sdv_idl_compiler/includes.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef INCLUDES_IDL_COMPILER_H
|
||||
#define INCLUDES_IDL_COMPILER_H
|
||||
|
||||
// Comment the following file to use the backup file. Uncomment to use the IDL file. Both files should contain identical
|
||||
// definitions and declarations.
|
||||
//#include <interfaces/core_idl.h>
|
||||
|
||||
// REMARKS: Using the "core_idl.h" works once; after that CMake detects circular dependencies and doesn't want to build any
|
||||
// more. Therefore, it is advisable to use it only for checking the interfaces.
|
||||
// To re-allow building again after a circular reference, clear the CMake cache (in the project-menu item).
|
||||
|
||||
#ifndef __IDL_GENERATED__CORE_IDL_DEF_H__
|
||||
// BACKUP MODE - IN CASE "core_idl.h" is destroyed or doesn't exist
|
||||
#include "core_idl_backup.h"
|
||||
#endif
|
||||
|
||||
#endif // !defined(INCLUDES_IDL_COMPILER_H)
|
||||
1102
sdv_executables/sdv_idl_compiler/lexer.cpp
Normal file
1102
sdv_executables/sdv_idl_compiler/lexer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
sdv_executables/sdv_idl_compiler/lexer.h
Normal file
269
sdv_executables/sdv_idl_compiler/lexer.h
Normal file
@@ -0,0 +1,269 @@
|
||||
#ifndef LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include "lexerbase.h"
|
||||
#include "token.h"
|
||||
#include "tokenlist.h"
|
||||
#include "codepos.h"
|
||||
#include <cinttypes>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* @brief OMG IDL 4.2 keywords
|
||||
* @remarks Dependable on the extension settings, the keywords are extended with: char16, char32, u8string, u16string, u32string,
|
||||
* null, pointer, interface_id, interface_t and exception_id.
|
||||
*/
|
||||
const std::vector<std::string> g_vecOmgIdlKeywords = {
|
||||
"abstract", "any", "alias", "attribute", "bitfield", "bitmask", "bitset", "boolean", "case", "char", "component", "connector",
|
||||
"const", "consumes", "context", "custom", "default", "double", "exception", "emits", "enum", "eventtype", "factory", "finder",
|
||||
"fixed", "float", "getraises", "home", "import", "in", "inout", "interface", "local", "long", "manages", "map", "mirrorport",
|
||||
"module", "multiple", "native", "Object", "octet", "oneway", "out", "primarykey", "private", "port", "porttype", "provides",
|
||||
"public", "publishes", "raises", "readonly", "setraises", "sequence", "short", "string", "struct", "supports", "switch",
|
||||
"truncatable", "typedef", "typeid", "typename", "typeprefix", "unsigned", "union", "uses", "ValueBase", "valuetype", "void",
|
||||
"wchar", "wstring", "int8", "uint8", "int16", "int32", "int64", "uint16", "uint32", "uint64"
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SDV IDL lexer class
|
||||
*/
|
||||
class CLexer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Lexing mode enumerator.
|
||||
*/
|
||||
enum class ELexingMode
|
||||
{
|
||||
lexing_idl, ///< Lexing IDL code.
|
||||
lexing_preproc, ///< Lexing preprocessor directives (valid for the current line only).
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] pCallback Pointer to the lexer callback interface. Must not be NULL.
|
||||
* @param[in] bCaseSensitive When set, allow identical names that only differ in case.
|
||||
* @param[in] eLexingMode The lexing mode the lexer should run in. This determines the rule-set to use while lexing.
|
||||
*/
|
||||
CLexer(ILexerCallback* pCallback, bool bCaseSensitive, ELexingMode eLexingMode = ELexingMode::lexing_idl);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~CLexer() = default;
|
||||
|
||||
/**
|
||||
* Add keywords to the reserved keyword list (based on the enabled extension).
|
||||
* @param[in] rssKeyword Reference to the keyword string to add.
|
||||
*/
|
||||
void AddKeyword(const std::string& rssKeyword);
|
||||
|
||||
/**
|
||||
* @brief Get a token from the code.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @param[in] rptrContext Reference to the smart pointer to the source code context.
|
||||
* @throws Throws CCompileException on parse error.
|
||||
* @remarks Whitespace, comments and preprocessor directions are not provided as a result, but are provided through the
|
||||
* callback interface.
|
||||
* @post Updates the position to the token following the token.
|
||||
* @return Returns the read token or an empty token when OEF has been reached.
|
||||
*/
|
||||
CToken GetToken(CCodePos& rCode, const CContextPtr& rptrContext) const;
|
||||
|
||||
/**
|
||||
* @brief Get the last valid token.
|
||||
* @return Returns a reference to the member variable containing the last read token or an empty token when no token was read
|
||||
* before.
|
||||
*/
|
||||
const CToken& GetLastValidToken() const;
|
||||
|
||||
/**
|
||||
* @brief Read until the provided symbol or the end of the text.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @param[in] cSymbol The symbol to mark the end.
|
||||
* @post Updates the position to the token of the symbol.
|
||||
* @return Returns the token until the symbol or end of text has been reached.
|
||||
*/
|
||||
CToken GetCustom(CCodePos& rCode, char cSymbol) const;
|
||||
|
||||
/**
|
||||
* @brief Skip the rest of the line.
|
||||
* @remarks End position is at the carriage return or newline for preprocessing directives and past the carriage return or
|
||||
* newline for code.
|
||||
* @remarks Sets the newline-occurred flag for code.
|
||||
* @remarks Back-slash at the end of the line causes the inclusion of the next line.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
*/
|
||||
void SkipLine(CCodePos& rCode) const;
|
||||
|
||||
/**
|
||||
* @brief Enable preproc processing.
|
||||
* @details While parsing preprocessor directive, further preprocessor processing is disabled. If including an additional
|
||||
* file, preprocessing needs to be enabled again.
|
||||
*/
|
||||
void EnablePreprocProcessing();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Get whitespace (space, form feed, line feed, carriage return, horizontal tab, vertical tab) until there is no white
|
||||
* space any more.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @param[out] rbNewline Set when a newline has been passed.
|
||||
* @throws Throws CCompileException on parse error.
|
||||
* @post Updates the position to the token following the whitespace.
|
||||
*/
|
||||
CToken GetWhitespace(CCodePos& rCode, bool& rbNewline) const;
|
||||
|
||||
/**
|
||||
* @brief Get C-style and C++ comments.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @throws Throws CCompileException on parse error.
|
||||
* @post Updates the position to the token following the comment.
|
||||
*/
|
||||
CToken GetComments(CCodePos& rCode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the identifier or keyword.
|
||||
* @details Get the identifier or keyword. A keyword corresponds to the list of keywords defined by the OMG IDL. All others
|
||||
* are identifiers. Identifiers that differ from a keyword through case differences are illegal.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @throws Throws CCompileException on parse error.
|
||||
* @post Updates the position to the token following the identifier.
|
||||
* @return Returns the identifier token or an empty token when OEF has been reached.
|
||||
*/
|
||||
CToken GetIdentifierOrKeyword(CCodePos& rCode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the separator: { } ( ) : :: ; .
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @post Updates the position to the token following the separator.
|
||||
* @return Returns the separator token or an empty token when no separator is at the requested token.
|
||||
*/
|
||||
CToken GetSeparator(CCodePos& rCode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the operator: = + - * / % ^ ! ~ , | # || & && == != < <= > >= ?
|
||||
* @remarks The '#' symbol is only an operator when lexing preprocessor directives. This is covered by the GetToken function.
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @post Updates the position to the token following the operator.
|
||||
* @return Returns the operator token or an empty token when no operator is at the requested token.
|
||||
*/
|
||||
CToken GetOperator(CCodePos& rCode) const;
|
||||
|
||||
/**
|
||||
* @brief Get the literal: hex, decimal or octal number, floating/fixed point number, character, strings, boolean and nullptr
|
||||
* values.
|
||||
* @remarks The following extension on the OMG IDL specification are possible:
|
||||
* - binary integer literal as is part of the C++ 14 standard.
|
||||
* - integer suffixes as are part of the C++ standard.
|
||||
* - unicode UTF-16 and UTF-32 character literals as part of the C++ 11 standard.
|
||||
* - ASCII and wide string sequences (2, 4 or 8 characters) as part oft the C++ standard.
|
||||
* - Unicode UTF-8, UTF-16, UTF-32 and wide string literals as part of the C++ 11 standard.
|
||||
* - raw ASCII, UTF-8, UTF-16, UTF-32 and wide string literals as is part of the C++ 11 standard.
|
||||
* - character and string escape sequence using 8 digits to specify a Unicode character as is part of the C++ standard.
|
||||
* - hexadecimal floating points as are part of the C++ 17 standard.
|
||||
* - floating point suffixes as are part of the C++ standard.
|
||||
* - boolean literal as part of the C++ standard (the values 'true' and 'false' as well as 'TRUE' and 'FALSE').
|
||||
* - nullptr literal as part of the C++ 11 standard (the values 'nullptr' and 'NULL').
|
||||
* @param[in, out] rCode Reference to the code to be parsed.
|
||||
* @throws Throws CCompileException on parse error.
|
||||
* @post Updates the position to the token following the literal.
|
||||
* @return Returns the literal token or an empty token when OEF has been reached.
|
||||
*/
|
||||
CToken GetLiteral(CCodePos& rCode) const;
|
||||
|
||||
ILexerCallback* m_pLexerCallback = nullptr; ///< The lexer callback for inserting comments
|
||||
bool m_bCaseSensitive = true; ///< Case sensitivity during name comparison.
|
||||
ELexingMode m_eLexingMode = ELexingMode::lexing_idl; ///< Lexing mode (changes the lexing rules).
|
||||
mutable bool m_bNewlineOccurred = true; ///< A newline occurred - a preprocessor directive could take place.
|
||||
mutable CToken m_tokenLastValid; ///< The last valid token.
|
||||
std::vector<std::string> m_vecReservedKeywords; ///< List of reserved keywords.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tokenize a string into a token list.
|
||||
* @param[in] szCode The code to tokenize.
|
||||
* @param[in] rptrContext Reference to the smart pointer to the source code context.
|
||||
* @return The tokenized string.
|
||||
*/
|
||||
CTokenList Tokenize(const char* szCode, const CContextPtr& rptrContext);
|
||||
|
||||
/**
|
||||
* @brief Tokenize a string into a token list.
|
||||
* @param[in] rssCode The code to tokenize.
|
||||
* @param[in] rptrContext Reference to the smart pointer to the source code context.
|
||||
* @return The tokenized string.
|
||||
*/
|
||||
CTokenList Tokenize(const std::string& rssCode, const CContextPtr& rptrContext);
|
||||
|
||||
/**
|
||||
* @brief Dummy callback interface for the lexer ignoring all calls.
|
||||
*/
|
||||
struct SLexerDummyCallback : public ILexerCallback
|
||||
{
|
||||
/**
|
||||
* @brief Insert whitespace. Dummy implementation. Overload of ILexerCallback::InsertWhitespace.
|
||||
*/
|
||||
virtual void InsertWhitespace(const CToken& /*rtoken*/) override {}
|
||||
|
||||
/**
|
||||
* @brief Insert a comment. Dummy implementation. Overload of ILexerCallback::InsertComment.
|
||||
*/
|
||||
virtual void InsertComment(const CToken& /*rtoken*/) override {}
|
||||
|
||||
/**
|
||||
* @brief Process a preprocessor directive. Overload of ILexerCallback::ProcessPreprocDirective.
|
||||
* @param[in] rCode Reference to the source code to process the preproc directive for.
|
||||
*/
|
||||
virtual void ProcessPreprocDirective(CCodePos& rCode) override
|
||||
{ SLexerDummyCallback sCallback; CLexer(&sCallback, true).SkipLine(rCode); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callback interface for the lexer storing the provided information.
|
||||
*/
|
||||
struct SLexerStoreCallback : public ILexerCallback
|
||||
{
|
||||
/**
|
||||
* @brief Clear the value of the callback structure.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
tokenWhitespace = CToken();
|
||||
tokenComment = CToken();
|
||||
ssPreprocLine.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert whitespace. Overload of ILexerCallback::InsertWhitespace.
|
||||
* @param[in] rtoken Reference to token containing the whitespace.
|
||||
*/
|
||||
virtual void InsertWhitespace(const CToken &rtoken) override { tokenWhitespace = rtoken; }
|
||||
|
||||
/**
|
||||
* @brief Insert a comment. Overload of ILexerCallback::InsertComment.
|
||||
* @param[in] rtoken Reference to the token containing the comment.
|
||||
*/
|
||||
virtual void InsertComment(const CToken &rtoken) override { tokenComment = rtoken; }
|
||||
|
||||
/**
|
||||
* @brief Process a preprocessor directive. Overload of ILexerCallback::ProcessPreprocDirective.
|
||||
* @param[in] rCode Reference to the source code to process the preproc directive for.
|
||||
*/
|
||||
virtual void ProcessPreprocDirective(CCodePos &rCode) override
|
||||
{
|
||||
SLexerDummyCallback sCallback;
|
||||
CLexer lexer(&sCallback, true);
|
||||
CToken token = rCode.GetLocation();
|
||||
lexer.SkipLine(rCode);
|
||||
rCode.UpdateLocation(token);
|
||||
ssPreprocLine = static_cast<std::string>(token);
|
||||
}
|
||||
|
||||
CToken tokenWhitespace; ///< Token holding whitespace.
|
||||
CToken tokenComment; ///< Token holding comment.
|
||||
std::string ssPreprocLine; ///< String holding preprocessing line.
|
||||
};
|
||||
|
||||
#endif // !defined LEXER_H
|
||||
89
sdv_executables/sdv_idl_compiler/lexerbase.h
Normal file
89
sdv_executables/sdv_idl_compiler/lexerbase.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifndef LEXERBASE_H
|
||||
#define LEXERBASE_H
|
||||
|
||||
/**
|
||||
* @brief Token type
|
||||
*/
|
||||
enum class ETokenType
|
||||
{
|
||||
token_none, ///< No token
|
||||
token_whitespace, ///< Token is whitespace
|
||||
token_comments, ///< Token is C-style or C++ comments
|
||||
token_identifier, ///< Token is an identifier
|
||||
token_keyword, ///< Token is a keyword
|
||||
token_literal, ///< Token is a literal
|
||||
token_separator, ///< Token is a separator
|
||||
token_operator, ///< Token is a operator
|
||||
token_meta, ///< Token contains meta data
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Token literal type (valid when token is a literal token).
|
||||
*/
|
||||
enum class ETokenLiteralType
|
||||
{
|
||||
token_undefined, ///< No literal type defined
|
||||
token_literal_dec_integer, ///< Decimal integer literal
|
||||
token_literal_oct_integer, ///< Octal integer literal
|
||||
token_literal_hex_integer, ///< IsHexadecimal() integer literal
|
||||
token_literal_bin_integer, ///< Binary integer literal
|
||||
token_literal_dec_floating_point, ///< Decimal floating point literal
|
||||
token_literal_hex_floating_point, ///< IsHexadecimal() floating point literal
|
||||
token_literal_fixed_point, ///< Fixed point literal
|
||||
token_literal_string, ///< String literal (ASCII ISO Latin-1 (8859-1) character set, UTF-8, UTF-16,
|
||||
///< UTF-32, wide - platform specific)
|
||||
token_literal_raw_string, ///< Raw string literal (ASCII ISO Latin-1 (8859-1) character set, UTF-8, UTF-16,
|
||||
///< UTF-32, wide - platform specific)
|
||||
token_literal_character, ///< Character literal (ASCII ISO Latin-1 (8859-1) character set, UTF-16, UTF-32,
|
||||
///< wide - platform specific)
|
||||
token_literal_character_sequence, ///< Character sequence literal (ASCII or wide - both platform cpecific)
|
||||
token_literal_boolean, ///< Boolean literal
|
||||
token_literal_nullptr, ///< Nullptr literal
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Token meta type (valid when token is a metza token).
|
||||
*/
|
||||
enum class ETokenMetaType
|
||||
{
|
||||
token_undefined, ///< No meta type defined
|
||||
token_meta_include_local, ///< Local include file
|
||||
token_meta_include_global, ///< Global include file
|
||||
token_meta_define, ///< Definition
|
||||
token_meta_undef, ///< Remove definition
|
||||
token_meta_verbatim, ///< Verbatim text to be inserted by the generator
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
class CToken;
|
||||
class CCodePos;
|
||||
|
||||
/**
|
||||
* @brief Lexer callback interface
|
||||
*/
|
||||
struct ILexerCallback
|
||||
{
|
||||
/**
|
||||
* @brief Insert whitespace - used to preserve whitespace.
|
||||
* @param[in] rtoken Reference to the token structure pointing to the whitespace.
|
||||
*/
|
||||
virtual void InsertWhitespace(const CToken &rtoken) = 0;
|
||||
|
||||
/**
|
||||
* @brief Insert a comment, either standalone, belonging to the last statement or belonging to the next statement.
|
||||
* @param[in] rtoken Reference to the token structure pointing to the comment.
|
||||
*/
|
||||
virtual void InsertComment(const CToken& rtoken) = 0;
|
||||
|
||||
/**
|
||||
* @brief Process a preprocessor directive. Preprocessor directives occur at the beginning of a line and can be preceded by
|
||||
* whitespace. The directive starts with the '#' character.
|
||||
* @param[in] rCode Reference to the current code position starting the directive.
|
||||
*/
|
||||
virtual void ProcessPreprocDirective(CCodePos& rCode) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !defined LEXERBASE_H
|
||||
109
sdv_executables/sdv_idl_compiler/logger.cpp
Normal file
109
sdv_executables/sdv_idl_compiler/logger.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "logger.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma push_macro("interface")
|
||||
#undef interface
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#pragma execution_character_set( "utf-8" )
|
||||
#ifdef GetClassInfo
|
||||
#undef GetClassInfo
|
||||
#endif
|
||||
#pragma pop_macro("interface")
|
||||
#endif
|
||||
|
||||
CLogControl g_log_control;
|
||||
|
||||
CLogControl::CLogControl()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
SetConsoleOutputCP( 65001 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void CLogControl::SetVerbosityMode(EVerbosityMode eMode)
|
||||
{
|
||||
m_eVerbosityMode = eMode;
|
||||
}
|
||||
|
||||
EVerbosityMode CLogControl::GetVerbosityMode() const
|
||||
{
|
||||
return m_eVerbosityMode;
|
||||
}
|
||||
|
||||
void CLogControl::IncreaseIndent()
|
||||
{
|
||||
m_iIndent++;
|
||||
}
|
||||
|
||||
void CLogControl::DecreaseIndent()
|
||||
{
|
||||
m_iIndent--;
|
||||
}
|
||||
|
||||
void CLogControl::Log(const std::string& rssText, bool bError) const
|
||||
{
|
||||
// Reporting is determined by the verbosity mode.
|
||||
switch (m_eVerbosityMode)
|
||||
{
|
||||
case EVerbosityMode::report_none:
|
||||
// No reporting wanted
|
||||
return;
|
||||
case EVerbosityMode::report_errors:
|
||||
// Only report errors
|
||||
if (!bError) return;
|
||||
break;
|
||||
case EVerbosityMode::report_all:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Create indentation string
|
||||
std::string ssIndent;
|
||||
for (int32_t iCnt = 0; !bError && iCnt < m_iIndent; iCnt++)
|
||||
ssIndent += " ";
|
||||
|
||||
// Replace all the newlines by the newline + indentation
|
||||
size_t nPos = 0;
|
||||
while (nPos < rssText.size() && nPos != std::string::npos)
|
||||
{
|
||||
// Find the next newline
|
||||
size_t nStart = nPos;
|
||||
nPos = rssText.find('\n');
|
||||
|
||||
// Log indentation?
|
||||
if (m_bNewline) std::clog << ssIndent;
|
||||
m_bNewline = false;
|
||||
|
||||
// Newline not found, log the text
|
||||
if (nPos == std::string::npos)
|
||||
{
|
||||
std::clog << rssText.substr(nStart);
|
||||
break;
|
||||
}
|
||||
|
||||
// Include the newline
|
||||
nPos++;
|
||||
m_bNewline = true;
|
||||
|
||||
// Log the text
|
||||
std::clog << rssText.substr(nStart, nPos - nStart);
|
||||
}
|
||||
}
|
||||
|
||||
CLog::~CLog()
|
||||
{
|
||||
if (!m_ssTask.empty())
|
||||
*this << "Leaving: " << m_ssTask << std::endl;
|
||||
g_log_control.DecreaseIndent();
|
||||
}
|
||||
|
||||
int CLog::CLogStringBuf::sync()
|
||||
{
|
||||
g_log_control.Log(str());
|
||||
str(std::string());
|
||||
return 0;
|
||||
}
|
||||
141
sdv_executables/sdv_idl_compiler/logger.h
Normal file
141
sdv_executables/sdv_idl_compiler/logger.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
|
||||
enum class EVerbosityMode
|
||||
{
|
||||
report_none = -1, ///< Do not report anything.
|
||||
report_errors = 0, ///< Report errors only (default).
|
||||
report_all = 10, ///< Report all intermediate stepts.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Log control class used to control the log data.
|
||||
* @remarks Logging is done to std::clog ostream.
|
||||
*/
|
||||
class CLogControl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
CLogControl();
|
||||
|
||||
/**
|
||||
* @brief Set verbosity mode.
|
||||
* @param[in] eMode The verbosity mode to set.
|
||||
*/
|
||||
void SetVerbosityMode(EVerbosityMode eMode);
|
||||
|
||||
/**
|
||||
* @brief Get verbosity mode.
|
||||
* @return Returns the current verbosity mode.
|
||||
*/
|
||||
EVerbosityMode GetVerbosityMode() const;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Increase and decrease indentation.
|
||||
*/
|
||||
void IncreaseIndent();
|
||||
void DecreaseIndent();
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Report information; indentation will be inserted automatically after a newline.
|
||||
* @remarks Will only be shown when the verbosity mode is on report_all. Errors will be shown when the verbosity mode is on
|
||||
* report_all and report_errors.
|
||||
* @param[in] rssText Reference to the string to log.
|
||||
* @param[in] bError When set, the text indicates an error.
|
||||
*/
|
||||
void Log(const std::string& rssText, bool bError = false) const;
|
||||
|
||||
private:
|
||||
int32_t m_iIndent = -1; ///< Indentation after newline
|
||||
mutable bool m_bNewline = true; ///< When set, start inserting an indentation
|
||||
EVerbosityMode m_eVerbosityMode = EVerbosityMode::report_errors; ///< The level of verbosity while reporting
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief One global instance of log control.
|
||||
*/
|
||||
extern CLogControl g_log_control;
|
||||
|
||||
/**
|
||||
* @brief Logger class responsible for reporting the progress and errors. The logger class derives from std::ostream to provide
|
||||
* stream access reporting.
|
||||
*/
|
||||
class CLog : public std::ostream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor forming a test string by streaming.
|
||||
* @tparam TArgs Argument types within the parameter pack.
|
||||
* @param[in] tArgs Arguments forming the task description.
|
||||
*/
|
||||
template <typename... TArgs>
|
||||
CLog(TArgs... tArgs);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CLog();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Compose a string without any arguments; doing nothing... ending the unpacking of the parameter pack of the variadic
|
||||
* template.
|
||||
* @param[in, out] rss Reference to the string stream to fill.
|
||||
*/
|
||||
static void ComposeString([[maybe_unused]] std::stringstream& rss) {}
|
||||
|
||||
/**
|
||||
* @brief Compose a string with one or more arguments.
|
||||
* @tparam TArg Type of the first argument.
|
||||
* @tparam TArgs Types of additional arguments
|
||||
* @param[in, out] rss Reference to the string stream to fill.
|
||||
* @param[in] tArg First argument.
|
||||
* @param[in] tAdditionalArgs Optional additional arguments as parameter pack.
|
||||
*/
|
||||
template <typename TArg, typename... TArgs>
|
||||
static void ComposeString(std::stringstream& rss, TArg tArg, TArgs... tAdditionalArgs)
|
||||
{
|
||||
rss << tArg;
|
||||
ComposeString(rss, tAdditionalArgs...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Logger string buf implementing dedicated streaming to the log using std::ostream.
|
||||
*/
|
||||
class CLogStringBuf : public std::stringbuf
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* @brief Synchronize the controlled character sequence. Overload of std::stringbuf::sync.
|
||||
* @return int Returns 0 on success; -1 otherwise.
|
||||
*/
|
||||
virtual int sync() override;
|
||||
};
|
||||
|
||||
std::string m_ssTask; ///< Task description
|
||||
CLogStringBuf m_buffer; ///< The logger specific string buffer.
|
||||
};
|
||||
|
||||
template <typename... TArgs>
|
||||
inline CLog::CLog(TArgs... tArgs) : std::ostream(&m_buffer)
|
||||
{
|
||||
std::stringstream sstreamTaskDescr;
|
||||
ComposeString(sstreamTaskDescr, tArgs...);
|
||||
m_ssTask = sstreamTaskDescr.str();
|
||||
|
||||
g_log_control.IncreaseIndent();
|
||||
if (!m_ssTask.empty())
|
||||
*this << "Entering: " << m_ssTask << std::endl;
|
||||
}
|
||||
|
||||
#endif // !defined(LOGGER_H)
|
||||
342
sdv_executables/sdv_idl_compiler/macro.cpp
Normal file
342
sdv_executables/sdv_idl_compiler/macro.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
#include "macro.h"
|
||||
#include "exception.h"
|
||||
#include "lexer.h"
|
||||
#include "environment.h"
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief Callback class for the lexer allowing to insert the whitespace and comments into the provided stream.
|
||||
*/
|
||||
class CMacroResolveCallback : public ILexerCallback
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor providing a reference of the resolved string to use for concatenating comments and whitepace.
|
||||
* @param[in] rssName Reference to the macro name.
|
||||
* @param[in] rssTargetValue Reference to the value.
|
||||
* @param[in] rbSuppressWhitespace Reference to a boolean stating whether to suppress whitespace.
|
||||
*/
|
||||
CMacroResolveCallback(const std::string& rssName, std::string& rssTargetValue, const bool& rbSuppressWhitespace) :
|
||||
m_ssName(rssName), m_rssTargetValue(rssTargetValue), m_rbSuppressWhitespace(rbSuppressWhitespace)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Insert whitespace. Overload of ILexerCallback::InsertWhitespace.
|
||||
*/
|
||||
virtual void InsertWhitespace(const CToken&) override
|
||||
{
|
||||
// Multiple spaces are reduced to one space.
|
||||
if (!m_rbSuppressWhitespace)
|
||||
m_rssTargetValue += ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a comment. Overload of ILexerCallback::InsertComment.
|
||||
*/
|
||||
virtual void InsertComment(const CToken&) override
|
||||
{
|
||||
// Comments are ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Process a preprocessor directive. Overload of ILexerCallback::ProcessPreprocDirective.
|
||||
*/
|
||||
virtual void ProcessPreprocDirective(CCodePos& /*rCode*/) override
|
||||
{
|
||||
// Should not be called.
|
||||
throw CCompileException("Internal error trying to resolve the ", m_ssName, " macro.");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_ssName; //!< Macro name.
|
||||
std::string& m_rssTargetValue; //!< Reference to the string to concatenate the comments and whitespace onto.
|
||||
const bool& m_rbSuppressWhitespace; //!< Reference to a boolean stating whether to prevent concatination of whitespace.
|
||||
};
|
||||
|
||||
CMacro::CMacro(const char* szName, const std::vector<std::string>* pvecParams, const char* szValue) :
|
||||
m_ssName(szName),
|
||||
m_bExpectParams(pvecParams ? true : false),
|
||||
m_vecParamDefs(pvecParams ? *pvecParams : std::vector<std::string>()),
|
||||
m_ssValue(szValue ? szValue : "")
|
||||
{
|
||||
// Remove any whitespace from the end of the value.
|
||||
while (m_ssValue.size() && std::isspace(m_ssValue.back()))
|
||||
m_ssValue.erase(m_ssValue.size() - 1);
|
||||
|
||||
// Remove any whitespace from the beginning of the value.
|
||||
while (m_ssValue.size() && std::isspace(m_ssValue.front()))
|
||||
m_ssValue.erase(0, 1);
|
||||
}
|
||||
|
||||
CMacro::CMacro(const CMacro& rMacro) :
|
||||
m_ssName(rMacro.m_ssName),
|
||||
m_bExpectParams(rMacro.m_bExpectParams),
|
||||
m_vecParamDefs(rMacro.m_vecParamDefs),
|
||||
m_ssValue(rMacro.m_ssValue)
|
||||
{}
|
||||
|
||||
CMacro::CMacro(CMacro&& rMacro) noexcept :
|
||||
m_ssName(std::move(rMacro.m_ssName)),
|
||||
m_bExpectParams(rMacro.m_bExpectParams),
|
||||
m_vecParamDefs(std::move(rMacro.m_vecParamDefs)),
|
||||
m_ssValue(std::move(rMacro.m_ssValue))
|
||||
{
|
||||
rMacro.m_bExpectParams = false;
|
||||
}
|
||||
|
||||
CMacro& CMacro::operator=(const CMacro& rMacro)
|
||||
{
|
||||
m_ssName = rMacro.m_ssName;
|
||||
m_bExpectParams = rMacro.m_bExpectParams;
|
||||
m_vecParamDefs = rMacro.m_vecParamDefs;
|
||||
m_ssValue = rMacro.m_ssValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CMacro& CMacro::operator=(CMacro&& rMacro) noexcept
|
||||
{
|
||||
m_ssName = std::move(rMacro.m_ssName);
|
||||
m_bExpectParams = rMacro.m_bExpectParams;
|
||||
m_vecParamDefs = std::move(rMacro.m_vecParamDefs);
|
||||
m_ssValue = std::move(rMacro.m_ssValue);
|
||||
rMacro.m_bExpectParams = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CMacro::operator==(const CMacro& rMacro)
|
||||
{
|
||||
if (m_bExpectParams != rMacro.m_bExpectParams) return false;
|
||||
if (m_ssName != rMacro.m_ssName) return false;
|
||||
if (m_bExpectParams && m_vecParamDefs != rMacro.m_vecParamDefs) return false;
|
||||
if (m_ssValue != rMacro.m_ssValue) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMacro::operator!=(const CMacro& rMacro)
|
||||
{
|
||||
return !operator==(rMacro);
|
||||
}
|
||||
|
||||
const std::string& CMacro::GetName() const
|
||||
{
|
||||
return m_ssName;
|
||||
}
|
||||
|
||||
bool CMacro::ExpectParameters() const
|
||||
{
|
||||
return m_bExpectParams;
|
||||
}
|
||||
|
||||
std::string CMacro::Expand(const CIdlCompilerEnvironment& renv, const CToken& rtoken, const std::vector<std::string>& rvecParams,
|
||||
CUsedMacroSet& rsetUsedMacros) const
|
||||
{
|
||||
// Parameters in function like macros are expanded before being inserted into the value if not part of a stringification
|
||||
// operation.
|
||||
// Commments are ignored in a macro value.
|
||||
// Multiple spaces in the value are reduced to one space.
|
||||
// The result of the macro is expanded before being returned.
|
||||
// Circular references to macros within the expanded code are prevented for
|
||||
// - each paramerer separately with the used macro list provided by the function.
|
||||
// - macro expansion result with the used macros from all the parameters and the used macro list provided to the function.
|
||||
// Macros used in the expansion of the paramters and the results are added to the used macro set provided to this function.
|
||||
|
||||
// Check whether the amount of provided params corresponds to the amount of param definitions.
|
||||
if (rvecParams.size() < m_vecParamDefs.size())
|
||||
throw CCompileException(rtoken, "Missing parameters while calling macro");
|
||||
if (rvecParams.size() > m_vecParamDefs.size())
|
||||
throw CCompileException(rtoken, "Provided too many parameters while calling macro");
|
||||
|
||||
std::string ssTargetValue;
|
||||
bool bConcatenateNext = false;
|
||||
bool bStringificateNext = false;
|
||||
CMacroResolveCallback callback(m_ssName, ssTargetValue, bConcatenateNext);
|
||||
CLexer lexer(&callback, renv.CaseSensitiveTypeExtension(), CLexer::ELexingMode::lexing_preproc);
|
||||
CCodePos codeValue(m_ssValue.c_str());
|
||||
|
||||
// The set with used macros for all parameters should stay the same, wheresas the provided set should be extended.
|
||||
CUsedMacroSet setUsedMacrosStored = rsetUsedMacros;
|
||||
|
||||
// Stringificate the supplied string.
|
||||
auto fnStringificate = [](const std::string &rss)
|
||||
{
|
||||
std::string ssTarget;
|
||||
ssTarget += '\"';
|
||||
for (char cVal : rss)
|
||||
{
|
||||
switch (cVal)
|
||||
{
|
||||
case '\"':
|
||||
ssTarget += "\\\"";
|
||||
break;
|
||||
case '\'':
|
||||
ssTarget += "\\\'";
|
||||
break;
|
||||
case '\a':
|
||||
ssTarget += "\\a";
|
||||
break;
|
||||
case '\b':
|
||||
ssTarget += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
ssTarget += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
ssTarget += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
ssTarget += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
ssTarget += "\\t";
|
||||
break;
|
||||
case '\v':
|
||||
ssTarget += "\\v";
|
||||
break;
|
||||
default:
|
||||
ssTarget += cVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ssTarget += '\"';
|
||||
return ssTarget;
|
||||
};
|
||||
|
||||
// Expand the supplied code
|
||||
auto fnExpand = [&](const char* szCode) -> std::string
|
||||
{
|
||||
// Expand the parameter before inserting into the value.
|
||||
std::string ssTarget;
|
||||
bool bConcatenateDummy = false;
|
||||
CMacroResolveCallback callbackParam(m_ssName, ssTarget, bConcatenateDummy);
|
||||
CLexer lexerLocal(&callbackParam, renv.CaseSensitiveTypeExtension(), CLexer::ELexingMode::lexing_preproc);
|
||||
CCodePos code(szCode);
|
||||
|
||||
// Create a copy of the set of used macros to provide this to the parameter expansion. These are the stored
|
||||
// original used macros.
|
||||
CUsedMacroSet setUsedMacrosParam = setUsedMacrosStored;
|
||||
|
||||
// Expand the parameter
|
||||
while (!code.HasEOF())
|
||||
{
|
||||
// If the current position is not part of the macro expansion, reset the set of macros used in a expansion.
|
||||
bool bInMacroExpansion = code.CurrentPositionInMacroExpansion();
|
||||
|
||||
// In case the code is not part of the macro expansion, use the stored set of used macros provided to this function.
|
||||
// Otherwise the set still contains the macros used in the expansion.
|
||||
if (!bInMacroExpansion)
|
||||
setUsedMacrosParam = setUsedMacrosStored;
|
||||
|
||||
// Get a token.
|
||||
CToken token = lexerLocal.GetToken(code, rtoken.GetContext());
|
||||
|
||||
// Check whether the token is an identifier, if so, check for any macro
|
||||
if (token.GetType() == ETokenType::token_identifier)
|
||||
{
|
||||
// Test and expand the
|
||||
if (renv.TestAndExpand(static_cast<std::string>(token).c_str(), code, bInMacroExpansion, setUsedMacrosParam))
|
||||
{
|
||||
// Add all the used macros of the parameter expansion to the set of used macros provided to this function.
|
||||
for (const std::string& rssMacro : setUsedMacrosStored)
|
||||
rsetUsedMacros.insert(rssMacro);
|
||||
|
||||
continue; // macro was replaced, get a token again.
|
||||
}
|
||||
}
|
||||
|
||||
ssTarget += static_cast<std::string>(token);
|
||||
}
|
||||
return ssTarget;
|
||||
};
|
||||
|
||||
// Parse through the value and deal with parameter names, with stringification operators '#' and concatenating operators '##'.
|
||||
while (!codeValue.HasEOF())
|
||||
{
|
||||
CToken token = lexer.GetToken(codeValue, rtoken.GetContext());
|
||||
|
||||
// Check for concatinating token
|
||||
if (token == "##")
|
||||
{
|
||||
// Concatination and stringification is not allowed to be selected already before.
|
||||
if (bConcatenateNext)
|
||||
throw CCompileException(rtoken, "Double concatinating operator while resolving macro ", m_ssName);
|
||||
if (bStringificateNext)
|
||||
throw CCompileException(rtoken, "Cannot stringificate and then concatenate the result while resolving macro ",
|
||||
m_ssName);
|
||||
|
||||
// Remove whitespace from end of the target value
|
||||
std::string::reverse_iterator itEnd = std::find_if(ssTargetValue.rbegin(), ssTargetValue.rend(),
|
||||
[](char c)
|
||||
{ return !std::isspace<char>(c, std::locale::classic()); });
|
||||
ssTargetValue.erase(itEnd.base(), ssTargetValue.end());
|
||||
|
||||
// Set the concatination flag (this will also prevent concatinating whitespace to the target).
|
||||
bConcatenateNext = true;
|
||||
|
||||
// Next processing
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for stringification token
|
||||
if (token == "#")
|
||||
{
|
||||
// Multiple stringification tokens following each other is not allowed.
|
||||
if (bStringificateNext)
|
||||
throw CCompileException(rtoken, "Double stringification operator while resolving macro ", m_ssName);
|
||||
|
||||
// Set the stringification flag and enable concatination to prevent whitespace to be inserted.
|
||||
bStringificateNext = true;
|
||||
bConcatenateNext = true;
|
||||
|
||||
// Next processing
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether the token represents a parameter name
|
||||
if (token.GetType() == ETokenType::token_identifier)
|
||||
{
|
||||
// Check if the token corresponds to one of the parameters.
|
||||
size_t nParamPos = 0;
|
||||
for (; nParamPos < m_vecParamDefs.size(); nParamPos++)
|
||||
if (m_vecParamDefs[nParamPos] == static_cast<std::string>(token))
|
||||
break;
|
||||
|
||||
if (nParamPos < m_vecParamDefs.size())
|
||||
{
|
||||
// Add the parameter content to the target. Stringitificate if needed.
|
||||
if (bStringificateNext)
|
||||
ssTargetValue += fnStringificate(rvecParams[nParamPos]);
|
||||
else
|
||||
ssTargetValue += fnExpand(rvecParams[nParamPos].c_str());
|
||||
} else
|
||||
{
|
||||
// Stringification is not allowed when not using a parameter.
|
||||
if (bStringificateNext)
|
||||
throw CCompileException(rtoken, "Cannot stringificate while resolving macro ", m_ssName);
|
||||
|
||||
// Add the token to the target
|
||||
ssTargetValue += static_cast<std::string>(token);
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Stringification is not allowed when not using a parameter.
|
||||
if (bConcatenateNext)
|
||||
throw CCompileException(rtoken, "Cannot stringificate while resolving macro ", m_ssName);
|
||||
|
||||
// Add the token to the target
|
||||
ssTargetValue += static_cast<std::string>(token);
|
||||
}
|
||||
|
||||
// Stringification and concatenating finalized.
|
||||
bConcatenateNext = false;
|
||||
bStringificateNext = false;
|
||||
}
|
||||
|
||||
// The provided set of used macros now contain all the used macros by the parent, this macro and the macros of any of the
|
||||
// parameters. Use this set for the expansion of the result - this will prevent circular calling of macros already used
|
||||
// in parameters.
|
||||
setUsedMacrosStored = rsetUsedMacros;
|
||||
|
||||
// Return the expanded the macro result. This will automatically add any macros expanded in the result to the used macro set.
|
||||
return fnExpand(ssTargetValue.c_str());
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user