Files
tompzf 6ed4b1534e Precommit (#1)
* first commit

* cleanup
2025-11-04 13:28:06 +01:00

1067 lines
53 KiB
C++

#ifndef ENTITY_BASE_H
#define ENTITY_BASE_H
#include "../includes.h"
#include "../token.h"
#include "../tokenlist.h"
#include "../exception.h"
#include <memory>
#include <string>
#include <list>
#include <map>
#include <vector>
#include <type_traits>
#include "hash_calc.h"
#define DONT_LOAD_CORE_TYPES
#include <support/interface_ptr.h>
// Forward declaration
class CEntity;
class CParser;
class CEntityValueNode;
class CTypedefEntity;
class CContext;
/**
* @brief Entity smart pointer.
*/
using CEntityPtr = std::shared_ptr<CEntity>;
/**
* @brief Map with entities sorted by name.
* @remarks The key of the entity should be stored in lower case to allow case insensitive searching.
*/
using CEntityMap = std::map<std::string, CEntityPtr>;
/**
* @brief List with entities in the order they appear in code.
*/
using CEntityList = std::list<CEntityPtr>;
/**
* @brief Vector with entities in the order they appear in code.
*/
using CEntityVector = std::vector<CEntityPtr>;
/**
* @brief Entity value shared pointer.
*/
using CValueNodePtr = std::shared_ptr<CEntityValueNode>;
/**
* @brief Entity value vector.
*/
using CEntityValueVector = std::vector<CValueNodePtr>;
/**
* @brief Is declaration type an integral type?
* @param[in] eType The declaration type.
* @return Returns whether the declaration type is an integral type.
*/
inline bool IsIntegralDeclType(sdv::idl::EDeclType eType)
{
switch (eType)
{
case sdv::idl::EDeclType::decltype_short:
case sdv::idl::EDeclType::decltype_long:
case sdv::idl::EDeclType::decltype_long_long:
case sdv::idl::EDeclType::decltype_unsigned_short:
case sdv::idl::EDeclType::decltype_unsigned_long:
case sdv::idl::EDeclType::decltype_unsigned_long_long:
case sdv::idl::EDeclType::decltype_char:
case sdv::idl::EDeclType::decltype_char16:
case sdv::idl::EDeclType::decltype_char32:
case sdv::idl::EDeclType::decltype_wchar:
case sdv::idl::EDeclType::decltype_boolean:
case sdv::idl::EDeclType::decltype_native:
case sdv::idl::EDeclType::decltype_octet:
return true;
default:
return false;
}
}
/**
* @brief Is declaration type signed?
* @param[in] eType The declaration type.
* @return Returns whether the declaration type is signed.
*/
inline bool IsSignedDeclType(sdv::idl::EDeclType eType)
{
switch (eType)
{
case sdv::idl::EDeclType::decltype_short:
case sdv::idl::EDeclType::decltype_long:
case sdv::idl::EDeclType::decltype_long_long:
case sdv::idl::EDeclType::decltype_char:
case sdv::idl::EDeclType::decltype_float:
case sdv::idl::EDeclType::decltype_double:
case sdv::idl::EDeclType::decltype_long_double:
case sdv::idl::EDeclType::decltype_fixed:
return true;
default:
return false;
}
}
/**
* @brief Is declaration type unsigned?
* @param[in] eType The declaration type.
* @return Returns whether the declaration type is unsigned.
*/
inline bool IsUnsignedDeclType(sdv::idl::EDeclType eType)
{
switch (eType)
{
case sdv::idl::EDeclType::decltype_unsigned_short:
case sdv::idl::EDeclType::decltype_unsigned_long:
case sdv::idl::EDeclType::decltype_unsigned_long_long:
case sdv::idl::EDeclType::decltype_char16:
case sdv::idl::EDeclType::decltype_char32:
case sdv::idl::EDeclType::decltype_wchar:
case sdv::idl::EDeclType::decltype_boolean:
case sdv::idl::EDeclType::decltype_octet:
return true;
case sdv::idl::EDeclType::decltype_native:
return std::is_unsigned_v<size_t>;
default:
return false;
}
}
/**
* @brief Declaration type name association.
*/
using TDeclTypeAssoc = std::pair<std::string, sdv::idl::EDeclType>;
/**
* @brief Mapping between declaration type and string name.
* @attention Some types have multiple string representatives (e.g. sdv::idl::EDeclType::decltype_short vs. 'short' and
* 'int16').
* @attention Based on the provided extensions on the command line, the types might be extended by: char16, char32, u8string,
* u16string, u32string, pointer, interface_id, interface_t and exception_id
*/
const std::vector<TDeclTypeAssoc> g_vecDeclTypes = {
{"short", sdv::idl::EDeclType::decltype_short},
{"unsigned short", sdv::idl::EDeclType::decltype_unsigned_short},
{"long", sdv::idl::EDeclType::decltype_long},
{"unsigned long", sdv::idl::EDeclType::decltype_unsigned_long},
{"long long", sdv::idl::EDeclType::decltype_long_long},
{"unsigned long long", sdv::idl::EDeclType::decltype_unsigned_long_long},
{"fixed", sdv::idl::EDeclType::decltype_fixed},
{"float", sdv::idl::EDeclType::decltype_float},
{"double", sdv::idl::EDeclType::decltype_double},
{"long double", sdv::idl::EDeclType::decltype_long_double},
{"char", sdv::idl::EDeclType::decltype_char},
{"wchar", sdv::idl::EDeclType::decltype_wchar},
{"int8", sdv::idl::EDeclType::decltype_char},
{"int16", sdv::idl::EDeclType::decltype_short},
{"int32", sdv::idl::EDeclType::decltype_long},
{"int64", sdv::idl::EDeclType::decltype_long_long},
{"int", sdv::idl::EDeclType::decltype_long},
{"uint8", sdv::idl::EDeclType::decltype_octet},
{"uint16", sdv::idl::EDeclType::decltype_unsigned_short},
{"uint32", sdv::idl::EDeclType::decltype_unsigned_long},
{"uint64", sdv::idl::EDeclType::decltype_unsigned_long_long},
{"uint", sdv::idl::EDeclType::decltype_unsigned_long},
{"boolean", sdv::idl::EDeclType::decltype_boolean},
{"native", sdv::idl::EDeclType::decltype_native},
{"octet", sdv::idl::EDeclType::decltype_octet},
{"byte", sdv::idl::EDeclType::decltype_octet},
{"string", sdv::idl::EDeclType::decltype_string},
{"wstring", sdv::idl::EDeclType::decltype_wstring},
{"enum", sdv::idl::EDeclType::decltype_enum},
{"struct", sdv::idl::EDeclType::decltype_struct},
{"union", sdv::idl::EDeclType::decltype_union},
{"operation", sdv::idl::EDeclType::decltype_operation},
{"attribute", sdv::idl::EDeclType::decltype_parameter},
{"enum_entry", sdv::idl::EDeclType::decltype_enum_entry},
{"case_entry", sdv::idl::EDeclType::decltype_case_entry},
{"typedef", sdv::idl::EDeclType::decltype_typedef},
{"sequence", sdv::idl::EDeclType::decltype_sequence},
{"map", sdv::idl::EDeclType::decltype_map},
{"bitset", sdv::idl::EDeclType::decltype_bitset},
{"bitfield", sdv::idl::EDeclType::decltype_bitfield},
{"bitmask", sdv::idl::EDeclType::decltype_bitmask},
{"any", sdv::idl::EDeclType::decltype_any},
{"void", sdv::idl::EDeclType::decltype_void}
};
/**
* @brief Type declaration struct containing all the type information of this declaration including dependent type information
* of templated types and information.
*/
class CTypeDeclaration : public sdv::idl::IDeclarationType, public sdv::IInterfaceAccess
{
public:
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::IInterfaceAccess)
SDV_INTERFACE_ENTRY(sdv::idl::IDeclarationType)
END_SDV_INTERFACE_MAP()
/**
* @brief Return the base type. Overload of sdv::idl::IDeclarationType::GetBaseType.
* @details The bse type might be a templated type (string, sequence, map, etc.) which means that additional
* information is needed. Furthermore, the type might be a complex type (struct, union, enum) or a typedef. In these
* cases the type definition interface is available.
* @return The base type of this type.
*/
virtual sdv::idl::EDeclType GetBaseType() const override;
/**
* @brief Set the base type.
* @param[in] eBaseType The base type to set.
*/
void SetBaseType(sdv::idl::EDeclType eBaseType);
/**
* @brief Return the string that described the type in the code. Overload of
* sdv::idl::IDeclarationType::GetTypeString.
* @return The type string.
*/
virtual sdv::u8string GetTypeString() const override;
/**
* @brief Set the type string.
* @param[in] rssType Reference to the type string.
*/
void SetTypeString(const sdv::u8string& rssType);
/**
* @brief Add a string chunk to the type string.
* @param[in] rss Reference to the chunk string to add.
*/
void AddTypeString(const sdv::u8string& rss);
/**
* @brief Return the type definition for complex types or typedefs.
* Overload of sdv::idl::IDeclarationType::GetTypeDefinition.
* @return Pointer to the interface representing the type definition. Will be NULL for all other types.
*/
virtual sdv::IInterfaceAccess* GetTypeDefinition() const override;
/**
* @brief Return the type definition entity pointer.
* @return The type definition entity pointer.
*/
CEntityPtr GetTypeDefinitionEntityPtr() const;
/**
* @brief Set the definition entity pointer.
* @param[in] rptrDefinition Reference to the definition entity pointer.
*/
void SetTypeDefinitionEntityPtr(const CEntityPtr& rptrDefinition);
/**
* @brief Fixed length parameter for some templated types. Overload of sdv::idl::IDeclarationType::GetFixedLength.
* @details Fixed length template parameter for "fixed", "string", "sequence", "pointer", "map" and "bitfields".
* When not compulsory (for "fixed", "string", "sequence", "pointer" and "map") could be 0 to indicate a dynamic
* length (or defined over assignment with "fixed"). Bitfields allow a length between 1 and 64 bits.
* @return Returns the fixed length for some templated types or 0 for all other other types.
*/
virtual uint32_t GetFixedLength() const override;
/**
* @brief Set the fixed length.
* @param[in] uiFixedLength The fixed length or 0 for dynamic length.
*/
void SetFixedLength(uint32_t uiFixedLength);
/**
* @brief The amount of decimals of the "fixed" data type. Must be equal or smaller than the fixed length. Overload of
* sdv::idl::IDeclarationType::GetDecimals.
* @return The amount of decimals for the "fixed" data type or 0 for all other data types.
*/
virtual uint32_t GetDecimals() const override;
/**
* @brief Set the amount of decimals for the fixed type.
* @param[in] uiDecimals The amount of decimals to set.
*/
void SetDecimals(uint32_t uiDecimals);
/**
* @brief The value type template parameter for the "sequence", "pointer", "map" and "bitfield" data types. Overload of
* sdv::idl::IDeclarationType::GetValueType.
* @return Interface to the value data type for some templated types of NULL for all other types.
*/
virtual sdv::IInterfaceAccess* GetValueType() const override;
/**
* @brief Set value type pointer.
* @param[in] rptrValueType Reference to the value type pointer.
*/
void SetValueTypePtr(const std::shared_ptr<CTypeDeclaration>& rptrValueType);
/**
* @brief The key type template parameter for the "map" data type. Overload of
* sdv::idl::IDeclarationType::GetKeyType.
* @return Interface to the key data type for the "map" type of NULL for all other types.
*/
virtual sdv::IInterfaceAccess* GetKeyType() const override;
/**
* @brief Set key type pointer.
* @param[in] rptrKeyType Reference to the key type pointer.
*/
void SetKeyTypePtr(const std::shared_ptr<CTypeDeclaration>& rptrKeyType);
private:
/// The base type of the identifier.
sdv::idl::EDeclType m_eBaseType = sdv::idl::EDeclType::decltype_unknown;
std::string m_ssOriginalType; ///< The type string that resulted in the base type. This could be a system
///< type as well as a scoped name of an enum, struct, union or typedef.
CEntityPtr m_ptrOriginalType; ///< The type entity if the type is defined through an entity.
uint32_t m_uiFixedLen = 0; ///< Fixed length template parameter for "fixed", "string", "sequence",
///< "pointer", "map" and "bitfields". When not compulsory (for "fixed",
///< "string", "sequence", "pointer" and "map") could be 0 to indicate a
///< dynamic length (or defined
///< over assignment with "fixed"). Bitfields allow a length between 1 and
///< 64 bits.
uint32_t m_uiDecimals = 0; ///< The amount of decimals of the "fixed" data type. Must be equal or
///< smaller than the fixed length.
std::shared_ptr<CTypeDeclaration> m_ptrValueType; ///< The value type template parameter for "sequence", "pointer", "map" and
///< "bitfield".
std::shared_ptr<CTypeDeclaration> m_ptrKeyType; ///< The key type template parameter for map.
};
// TODO:
// - Const complex entities need to be told, that they are const during assignment.
// - Deal with the case of forward declaration (why is this needed, there are no references and no pointers)?
// - Deal with the case of ambiguity through inheritance:
// struct S1{ const int32 i1 = 10; };
// struct S2{ const int32 i1 = 20; };
// struct S3 : S1, S2 { int32 j1[i1]; }; --> ERROR
// - Not allowed to assign dynamic values when the parent value is a const value.
/**
* @brief Base of the entities allowing generic access to the entity.
* @remarks Normally a declaration entity cannot have child entities. It would make sense to manage child entities only by the
* definition entity. OMG IDL imposes naming restrictions for all the entities. And forward declarations are allowed. This
* requires that child management is implemented on a base level, even though declarations will not have any children.
*/
class CEntity : public sdv::idl::IEntityInfo, public sdv::idl::IEntityComments, public sdv::idl::IEntityContext,
public sdv::idl::IForwardDeclarationEntity, public sdv::IInterfaceAccess, public std::enable_shared_from_this<CEntity>
{
friend CTypedefEntity;
public:
/**
* @brief Constructor using the parser 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.
*/
CEntity(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.
*/
CEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList);
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.
*/
CEntity(CParser& rParser, const CContextPtr& rptrContext);
public:
/**
* @brief Destructor.
*/
virtual ~CEntity() = 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. Default type is sdv::idl::EEntityType::type_unknown. Overload of
* sdv::idl::IEntityInfo::GetType.
* @return Returns the entity type.
*/
virtual sdv::idl::EEntityType GetType() const override;
/**
* @brief Get the entity if this is a forward declared entity. Overload of sdv::idl::IForwardDeclarationEntity.
* @return Pointer to the entity this forward declaration is referring to. Or NULL when no entity was defined.
*/
virtual sdv::IInterfaceAccess* GetEntity() override;
/**
* @brief Get the declaration type of the entity as string.
* @attention To get the qualified type including array sizes, use the GetDeclTypeStr of the CEntityValueNode class.
* @details For declaration entities, the type returned includes the declaration type. For definition entities, the type returned
* have the for of "<base type> <type identifier>".
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns the entity declaration type string.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const;
/**
* @{
* @brief Get the derived entity class.
* @tparam TEntity The entity 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 entity.
*/
template <class TEntity>
TEntity* Get();
template <class TEntity>
const TEntity* Get() const;
/**
* @}
*/
/**
* @brief Process the code. Entity specific processing function. Must be derived.
* @details The processing of follows the following stages:
* - Process definition - determine the type blue-print
* - Process declaration - determine the identifier
* - Process assignment - build value chains
* It is not required to process all three steps. A definition can be made without a following declaration. A declaration can
* be made based on a previous definition.
* Whether or not a definition is made, is determined from the token sequence (grammar). In principal, if the statements are
* not specifying a definition, they are specifying a declaration or both (a declaration following the definition). Processing
* assignments is triggered by the complex processing entities (modules, structs, unions, interfaces, enums). In modules and
* enums, a declaration statement is processed for assignents directly. In structs and unions, the use of member variables is
* allowed even if they are defined later and have not been processed yet. Therefore, the declarations of all members in the
* structs and unions are processed first and the assignments are following after this.
* Assignments are only possible following a declaration. Therefore, the process assignment function is only implemented in
* the CDeclarationEntity class implementing typedefs, const declarations and variable declarations. The assignment of values is
* possible also for enums, structs, unions and interfaces. The overloadable ProcessAsignmentValue function is used for this.
*/
virtual void Process() = 0;
/**
* @brief Get the name of the entity. Overload of IEntityInfo::GetName.
* @return The name string.
*/
virtual sdv::u8string GetName() const override;
/**
* @brief Get the scoped name of the entity (including the modules separated by the scope separator). Overload of
* IEntityInfo::GetScopedName.
* @return The scoped name build from the entities of the parents separated by '::'. An empty name means global scope.
*/
virtual sdv::u8string GetScopedName() const override;
/**
* @brief Replace any identifier in the expression with a relative scope to this entity by a full scoped identifier.
* @remarks If an entity in the expression cannot be found within the current scope, the entity is not corrected and replaced
* without change in the retargeted expression.
* @param[in] rssExpression Reference to the expression to use for retargeting.
* @return The expression with full scoped identifiers.
*/
std::string MakeFullScoped(const std::string& rssExpression) const;
/**
* @brief Has equal.
* @param[in] ptrEntity Pointer to the entity to use for the comparison.
* @return Returns 'true' when the entities have the identical scoped names.
*/
bool IsEqual(CEntityPtr ptrEntity) { return GetScopedName() == ptrEntity->GetScopedName(); }
/**
* @{
* @brief Get the parse context.
* @return Returns the parse context.
*/
CContextPtr GetContext() const;
CContextPtr GetContext();
/**
* @}
*/
/**
* @{
* @brief Get the parent entity of this entity.
* @return Returns the smart pointer to the parent entity or NULL when this is the root entity.
*/
CEntityPtr GetParentEntity() const;
CEntityPtr GetParentEntity();
/**
* @}
*/
/**
* @brief Get the parent entity of this entity. Overload of IEntityInfo::GetParent.
* @return Returns an interface to the parent entity or NULL when this is the root parent (when there is no parent).
*/
virtual sdv::IInterfaceAccess* GetParent() const override;
/**
* @{
* @brief Get the root entity.
* @return Returns the root entity.
*/
CEntityPtr GetRootEntity() const;
CEntityPtr GetRootEntity();
/**
* @}
*/
/**
* @{
* @brief Get resolved entity if the entity is a typedef (or multiple typedefs).
* @return Returns resolved entity.
*/
CEntityPtr GetResolvedEntity() const;
CEntityPtr GetResolvedEntity();
/**
* @}
*/
/**
* @brief Set the comment tokens for this entity.
* @attention This function doesn't set any comment if there is already a comment assigned (either through a forward
* declaration or when a comment is provided beforee and after a declaration). Unless, the new comments have additional
* information on the comment format (brief, java doc or doxygen) and the initial comments didn't have this.
* @param[in] rlstComments Reference to the comments token list.
* @param[in] bPreceeding When set, the comments are preceding the next statement; otherwise they are succeeding.
*/
void SetCommentTokens(const CTokenList& rlstComments, bool bPreceeding = true);
/**
* @brief Get the preceding comment token list.
* @details Preceding comments must be located in the same source file as the next token and must be adjacent and end at the
* latest one line before the next token.
* @return Returns the preceding comment token list.
*/
CTokenList GetPreCommentTokenList();
/**
* @brief Process the succeeding comment token list and assign to the current entity.
* @details Succeeding comments must be located in the same source file as the entity and must be adjacent and start at the
* provided line.
* @param[in] uiLine The line to start checking for succeeding comments at.
*/
void ProcessPostCommentTokenList(uint32_t uiLine);
/**
* @brief Get the comment lines for this entity as one string. Overload of IEntityComments::GetComments.
* @remarks For c-style multi-line comments, the indentation and additional asterisk character at the beginning of each line
* is removed.
* @param[out] ruiFlags Reference to the variable receiving the comment flags (a bitmask combination of
* sdv::idl::IEntityComments::ECommentMask).
* @return Returns the comment string. If the comment contains multiple lines, each line is ending with a newline.
*/
virtual sdv::u8string GetComments(uint32_t& ruiFlags) const override;
/**
* @brief Get the location. Overload of sdv::idl::IEntityContext::GetLocation.
* @return Returns the location.
*/
virtual sdv::idl::IEntityContext::ELocation GetLocation() const override;
/**
* @brief Get the path to the file. Overload of sdv::idl::IEntityContext::GetSourcePath.
* @return Returns the source path string.
*/
virtual sdv::u8string GetSourcePath() const override;
/**
* @brief Get the position in the file. Overload of sdv::idl::IEntityContext::GetPosition.
* @remarks Not all entities have a position. If no position is available, the position return value has the value 0.
* @param[out] ruiLineBegin Reference to the variable receiving the line number of the entity beginning.
* @param[out] ruiColBegin Reference to the variable receiving the column number of the entity beginning.
* @param[out] ruiLineEnd Reference to the variable receiving the line number of the entity ending.
* @param[out] ruiColEnd Reference to the variable receiving the column number of the entity ending.
*/
virtual void GetPosition(uint32_t& ruiLineBegin, uint32_t& ruiColBegin, uint32_t& ruiLineEnd, uint32_t& ruiColEnd) override;
/**
* @{
* @brief Set the position during parsing.
* @param[in] uiLine The line number.
* @param[in] uiCol The column number.
*/
void SetBeginPosition(uint32_t uiLine, uint32_t uiCol) { m_uiLineBegin = uiLine; m_uiColBegin = uiCol; }
void SetEndPosition(uint32_t uiLine, uint32_t uiCol) { m_uiLineEnd = uiLine; m_uiColEnd = uiCol; }
/**
* @}
*/
/**
* @brief Calculate the hash of this entity and all encapsulated entities.
* @param[in, out] rHash Hash object to be filled with data.
*/
virtual void CalcHash(CHashObject& rHash) const;
/**
* @{
* @brief Get the parser.
* @return Returns a reference to the parser.
*/
const CParser& GetParserRef() const;
CParser& GetParserRef();
/**
* @}
*/
protected:
/**
* @brief Get a token from the parser with moving the current position.
* @return Returns the token.
*/
CToken GetToken();
/**
* @brief Get the last valid token.
* @return Returns the last read token or an empty token when no token was read before.
*/
CToken GetLastValidToken() const;
/**
* @brief Get a token from the parser without moving the current position.
* @param[in] nIndex The amount of tokens to skip before returning the token.
* @return Returns the token.
*/
CToken PeekToken(size_t nIndex = 0);
/**
* @brief Insert token for parsing at the front of the parsing list.
* @param[in] rToken Reference to token object containing the code to insert.
*/
void PrependToken(CToken& rToken);
/**
* @brief Create a child entity and optionally add it to the list of children.
* @tparam TEntity The entity class to create. This class must derive from CEntity.
* @tparam TParams Zero or more parameter types to use for the constructor of the entity class.
* @remarks The parameters defined by the parameter type TParams must correspond to the parameters needed for the constructor
* of TEntity minus the compulsory ptrParent parameter.
* @remarks The parse context of the child is the same as the parent.
* @param[in] rptrContext Reference to the context.
* @param[in] pParent Pointer to the parent entity.
* @param[in] tParams Zero or more parameters to use for the constructor of the entity class.
* @return Returns a smart pointer to the entity.
*/
template <class TEntity, typename... TParams>
static CEntityPtr CreateChild(const CContextPtr& rptrContext, CEntity* pParent, TParams... tParams);
public:
/**
* @brief Find the entity using a scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppermost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* @tparam TEntity The entity type to return.
* @param[in] rssScopedName Reference to a string object containing the relative or absolute scoped entity name consisting of
* zero or more parents definitions and one entity name all separated with the scope separator '::' followed by declaration
* members separated by a member separator '.'. The name must not be empty.
* @param[in] bCheckParent When set, check the parent(s) as well if the scoped name fits on one of the children of a parent;
* otherwise the parent(s) is(are) not taken into account.
* @return The first version returns an entity smart pointer. The second version returns the entity pointer converted to the
* requested entity type (if the entity is of this type). If the entity doesn't exists or is of the wrong type a NULL pointer
* is returned.
*/
CEntityPtr Find(const std::string& rssScopedName, bool bCheckParent = true) const;
/**
* @brief Find the entity using a scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppermost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* @tparam TEntity The entity type to return.
* @param[in] rssScopedName Reference to a string object containing the relative or absolute scoped entity name consisting of
* zero or more parents definitions and one entity name all separated with the scope separator '::' followed by declaration
* members separated by a member separator '.'. The name must not be empty.
* @return The first version returns an entity smart pointer. The second version returns the entity pointer converted to the
* requested entity type (if the entity is of this type). If the entity doesn't exists or is of the wrong type a NULL pointer
* is returned.
*/
template <typename TEntity>
TEntity* Find(const std::string& rssScopedName) const;
/**
* @brief Find the value belonging to the scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppormost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* Following the scoped name, members and indices can be specified to navigate to the correct value declaration. Members are
* separated by a dot '.' and indices are specified using square brackets '[...]'. For example "::parent::entity.first[1]".
* @param[in] rlstScopedNameInclMembers Token list consisting of tokens representing the scoped name as well as any array and
* member names.
* @return Returns a value node smart pointer. If the value node doesn't exists or is of the wrong type a NULL pointer is
* returned.
*/
CValueNodePtr FindValue(const CTokenList& rlstScopedNameInclMembers) const;
/**
* @brief Find the value belonging to the scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppormost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* Following the scoped name, members and indices can be specified to navigate to the correct value declaration. Members are
* separated by a dot '.' and indices are specified using square brackets '[...]'. For example "::parent::entity.first[1]".
* @param[in] rssScopedNameInclMembers Reference to a string object containing the relative or absolute scoped entity name
* consisting of zero or more parents and one entity name all separated with the scope separator '::'. The name must not be
* empty.
* @return Returns a value node smart pointer. If the value node doesn't exists or is of the wrong type a NULL pointer is
* returned.
*/
CValueNodePtr FindValue(const std::string& rssScopedNameInclMembers) const;
/**
* @brief Find the value belonging to the scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppormost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* Following the scoped name, members and indices can be specified to navigate to the correct value declaration. Members are
* separated by a dot '.' and indices are specified using square brackets '[...]'. For example "::parent::entity.first[1]".
* @tparam TValueNode Type of the value node to return.
* @param[in] rssScopedNameInclMembers Reference to a string object containing the relative or absolute scoped entity name
* consisting of zero or more parents and one entity name all separated with the scope separator '::'. The name must not be
* empty.
* @return Returns the value node pointer converted to the requested value node type (if the value node is of this type). If the
* value node doesn't exists or is of the wrong type a NULL pointer is returned.
*/
template <typename TValueNode>
TValueNode* FindValue(const std::string& rssScopedNameInclMembers) const;
/**
* @brief Find the value variant belonging to the scoped name.
* @details A scoped name defines an entity name with possible entity parent names. Each name is separated by the scope
* separator '::'. For example: "parent_1::parent_1_a::parent_1_a_I::entity". The first entity that will be searched for is
* the uppormost parent (here parent_1). The search starts at the current entity. If the search was not successful, the search
* is done using the parent and if the search also there was not successful, the parent of the parent is searched for, and so
* on. The search is successful if all the requested parents match and the entity is found. An exception to the rule of the
* scoped name is, when the name starts with the scope separator indicating that the search is not relative but should start
* at the root entity. For example: "::parent::entity".
* Following the scoped name, members and indices can be specified to navigate to the correct value declaration. Members are
* separated by a dot '.' and indices are specified using square brackets '[...]'. For example "::parent::entity.first[1]".
* @param[in] rssScopedNameInclMembers Reference to a string object containing the relative or absolute scoped entity name
* consisting of zero or more parents and one entity name all separated with the scope separator '::'. The name must not be
* empty.
* @return On success, return a const variant structure with the value belonging to the requested value node. On failure, a
* const variant is returned that is initialized with 0 using the boolean data type (the first type and first value).
*/
CConstVariant FindValueVariant(const std::string& rssScopedNameInclMembers) const;
/**
* @brief Get the entity ID. Overload of IEntityInfo::GetId.
* @return Returns the entity ID.
*/
virtual uint64_t GetId() const override;
/**
* @brief Is the entity defined as (forward) declaration only? Overload of IEntityInfo::ForwardDeclaration.
* @return Returns whether this entity class instance is defined as forward declaration.
*/
virtual bool ForwardDeclaration() const override { return m_bForwardDeclaration; }
/**
* @brief Is this definition a root entity?
* @details The root entity is not expecting curly brackets '{...}'.
* @return Returns whether this entity is the root entity (which is not the case).
*/
virtual bool IsRootEntity() const { return false; }
/**
* @brief Is the entity extendable (can multiple definitions at the same scope exist and do they extend each other)?
* @details The default implementation doesn't allow extending the entity.
* @return Returns whether the entity is extendable (which is not the case).
*/
virtual bool IsExtendable() const { return false; }
/**
* @brief Does the entity support children?
* @details The default implementation doesn't allow children.
* @return Returns whether the entity supports children (which is not the case).
*/
virtual bool SupportsChildren() const { return false; }
/**
* @{
* @brief Get a reference to the calculated value. Consider
* @throw Throws an exception when the index doesn't correspond to the size of the array.
* @return The value struct smart pointer of the specified type.
*/
const CValueNodePtr& ValueRef() const { return m_ptrValue; }
CValueNodePtr& ValueRef() { return m_ptrValue; }
/**
* @}
*/
/**
* @brief Process the code for a soped name (a name composed of identifiers and scope operators).
* @param[in] bNoSearchError When set, do not throw exception during search to an entity with the name.
* @return Returns a pair object with the first element the scoped name and the second element a pointer to the found entity.
* In case the object doesn't exists, returns a nullptr as second element.
*/
std::pair<std::string, CEntityPtr> ProcessScopedName(bool bNoSearchError = false);
/**
* @brief Process the code for a soped name (a name composed of identifiers and scope operators).
* @param[in] rlstExpression Reference to the token list holding the expression.
* @param[in] bNoSearchError When set, do not throw exception during search to an entity with the name.
* @return Returns a pair object with the first element the scoped name and the second element a pointer to the found entity.
* In case the object doesn't exists, returns a nullptr as second element.
*/
std::pair<std::string, CEntityPtr> ProcessScopedName(const CTokenList& rlstExpression, bool bNoSearchError = false) const;
protected:
/**
* @brief Calculate the value based on the precedence of operators.
* @details Parse through the string and calculate a value. Values and arithmetic operators are read and a result is
* calculated as long as the operator precedence doesn't undercut the current precedence.
* - identifiers can be used
* - operators allowed for floating and fixed point operations: + - / * < <= > >= == !=
* - operators allowed for integral types: + - / % * & | ^ ~ << >> && || ! > >= < <= == !=
* - parenthesis are allowed
*
* Operator precedence:
* +------------+-----------------+-------------------------------------------+
* | precedence | operators | description |
* +============+=================+===========================================+
* | 0 | ~ ! ( ) defined | Bitwise NOT, logical NOT and parenthesis |
* +------------+-----------------+-------------------------------------------+
* | 1 | * / % | Multiplication, division, and remainder |
* +------------+-----------------+-------------------------------------------+
* | 2 | + - | Addition and subtraction |
* +------------+-----------------+-------------------------------------------+
* | 3 | << >> | Bitwise left shift and right shift |
* +------------+-----------------+-------------------------------------------+
* | 4 | < <= > >= | Relational operators |
* +------------+-----------------+-------------------------------------------+
* | 5 | == != | Equality operators |
* +------------+-----------------+-------------------------------------------+
* | 6 | & | Bitwise AND |
* +------------+-----------------+-------------------------------------------+
* | 7 | ^ | Bitwise XOR |
* +------------+-----------------+-------------------------------------------+
* | 8 | | | Bitwise OR |
* +------------+-----------------+-------------------------------------------+
* | 9 | && | Logical AND |
* +------------+-----------------+-------------------------------------------+
* | 10 | || | Logical OR |
* +------------+-----------------+-------------------------------------------+
* @param[in] rlstExpression Reference to the expression token list.
* @param[in] uiPrecedence [in] Current precedence level (default 100).
* @return Returns a pair containing the calculated value and a boolean that indicates whether the result is dynamic. In the
* latter case, the calculated value will be 0.
*/
std::pair<CConstVariant, bool> ProcessNumericExpression(const CTokenList& rlstExpression, uint32_t uiPrecedence = 100) const;
/**
* @brief Process the string expression.
* @param[in] rlstExpression Reference to the expression token list.
* @return Returns a pair containing the result string and a boolean that indicates whether the result is dynamic. In the
* latter case, the result string will be empty.
*/
std::pair<CConstVariant, bool> ProcessStringExpression(const CTokenList& rlstExpression) const;
/**
* @brief Process the code for a type.
* @param[in] bNoSearchError When set, does not throw an exception during the search of an entity with the defined name.
* @return The type declaration.
*/
CTypeDeclaration ProcessType(bool bNoSearchError = false);
/**
* @brief Set the name of the entity. This function must be called by the derived class and will check for a duplicate name
* (case insensitive comparison) and registers the entity under its name.
* @param[in] rssName String object containing the name of the entity. Cannot be empty.
* @param[in] bForwardDeclaration When set, the entity is part of forward declaration. When the declaration exists already,
* this function doesn't do anything. When it doesn't exists, the entity is created and marked as declared.
* @param[in] bNoInsert When set, do not insert the entity in the child map of the parent. Use only when local entities are
* needed.
*/
void SetName(const std::string& rssName, bool bForwardDeclaration = false, bool bNoInsert = false);
/**
* @brief In case there are any unassigned system type entities, process the entities.
*/
void ProcessSystemTypeAssignments();
/**
* @brief Add the child to the children list. Called by CreateChild function.
* @param[in] ptrChild Pointer to the child entity to add.
*/
virtual void AddChild(CEntityPtr ptrChild);
/**
* @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.
* @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;
/**
* @brief Find the member entity by looking at the entity declaration map of the type.
* @remarks Only compound entities (struct, union, exception) can have declarations.
* @param[in] rssScopedName Name of the entity separated by dots (name.name.name) indicating the declaration within a compound
* entity.
* @return The declaration entity that is represented by the scoped name or NULL when no entity was found.
*/
CEntityPtr FindMember(const std::string& rssScopedName) const;
/**
* @brief Get the children vector for creation of the iterator.
* @return Returns the reference to the child vector.
*/
CEntityVector& GetChildrenVector() { return m_vecChildren; }
/**
* @brief Return the declaration type as string.
* @param[in] eType The declaration type.
* @return The declaration type as string.
*/
std::string DeclTypeToString(sdv::idl::EDeclType eType) const;
/**
* @brief Return the declaration type as enum type.
* @param[in] rssType The declaration type as string.
* @return The declaration type as enum type.
*/
sdv::idl::EDeclType StringToDeclType(const std::string& rssType) const;
/**
* @brief Entity iterator helper class.
*/
class CEntityIterator : public sdv::idl::IEntityIterator, public sdv::IInterfaceAccess
{
public:
/**
* @brief Constructor
* @param[in] rvecEntities Reference to the entity vector to create the iterator for.
*/
CEntityIterator(CEntityVector& rvecEntities);
/**
* @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 amount of child entities. Overload of IEntityIterator::GetCount.
* @return Returns the amount of entities in this iterator.
*/
virtual uint32_t GetCount() const override;
/**
* @brief Get entity at supplied index. Overload of IEntityIterator::GetEntityByIndex.
* @param[in] uiIndex Index of the entity to return.
* @return Returns interface pointer to the entity or NULL when the index was too large.
*/
virtual sdv::IInterfaceAccess* GetEntityByIndex(uint32_t uiIndex) override;
private:
CEntityVector& m_rvecEntities; ///< Reference to the entity vector.
};
private:
CContextPtr m_ptrContext; ///< Parse context of the code represented by this entity.
CEntityPtr m_ptrParent; ///< Parent entity (could be NULL for the root entity).
CParser* m_pParser = nullptr; ///< Pointer to the parser.
CTokenList m_lstLocalTokenList; ///< Local token list to be taken during processing (instead
///< of the parser functions).
std::string m_ssName; ///< The entity name.
CEntityVector m_vecChildren; ///< Vector with child entities in the order they appear in the
///< code. Some entities allow to be defined in chunks, which
///< means multiple entries with the same name exist.
CEntityList m_lstUnassigned; ///< List of basic type child entities that were not processed
///< for assignments yet.
std::shared_ptr<CEntityMap> m_ptrChildDefMap; ///< Shared children map containing all the child definitions
///< for the entities with the same scope.
std::shared_ptr<CEntityMap> m_ptrChildDeclMap; ///< Shared children map containing all the child declarations
///< for the entities with the same scope.
bool m_bForwardDeclaration = false; ///< When set, the entity is only declared and not defined yet.
CValueNodePtr m_ptrValue; ///< Smart pointer to the entity value.
std::string m_ssComments; ///< Entity comments (could be multiple lines separated by
///< newline).
uint32_t m_uiCommentFlags = 0; ///< Entity comment flags (bitmask made of
///< sdv::idl::IEntityComments::ECommentMask).
uint32_t m_uiLineBegin = 0; ///< Begin line position of the entity.
uint32_t m_uiColBegin = 0; ///< Begin column position of the entity.
uint32_t m_uiLineEnd = 0; ///< End line position of the entity.
uint32_t m_uiColEnd = 0; ///< End column position of the entity.
std::vector<TDeclTypeAssoc> m_vecDeclTypes; ///< Decl types extended with additional types based on the
///< enabled extension on the command line.
};
template <class TEntity>
TEntity* CEntity::Get()
{
return dynamic_cast<TEntity*>(this);
}
template <class TEntity>
const TEntity* CEntity::Get() const
{
return dynamic_cast<const TEntity*>(this);
}
template <class TEntity, typename... TParams>
inline CEntityPtr CEntity::CreateChild(const CContextPtr& rptrContext, CEntity* pParent, TParams... tParams)
{
// Check to see if TEntity derives from CEntity.
static_assert(std::is_base_of_v<CEntity, TEntity>);
// Valid parent entity?
if (!pParent) throw CCompileException("Internal error: missing parent.");
// Is the creation of children allowed?
if (!pParent->SupportsChildren())
throw CCompileException("Internal error: trying to add an entity to a parent entity that doesn't support this.");
// Get the shared pointer
CEntityPtr ptrParent = pParent->shared_from_this();
// Create the entity class
CEntityPtr ptrEntity = std::make_shared<TEntity>(rptrContext, ptrParent, tParams...);
// Add the entity to the parent's children list.
pParent->AddChild(ptrEntity);
return ptrEntity;
}
template <typename TEntity>
TEntity* CEntity::Find(const std::string& rssScopedName) const
{
return dynamic_cast<TEntity*>(Find(rssScopedName).get());
}
template <typename TValueNode>
TValueNode* CEntity::FindValue(const std::string& rssScopedNameInclMembers) const
{
auto ptrtValueNode = FindValue(rssScopedNameInclMembers);
return dynamic_cast<TValueNode*>(ptrtValueNode.get());
}
#endif // !defined(ENTITY_BASE_H)