/******************************************************************************** * Copyright (c) 2025-2026 ZF Friedrichshafen AG * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #ifndef ENTITY_BASE_H #define ENTITY_BASE_H #include "../includes.h" #include "../token.h" #include "../tokenlist.h" #include "../exception.h" #include #include #include #include #include #include #include "hash_calc.h" #define DONT_LOAD_CORE_TYPES #include // Forward declaration class CEntity; class CParser; class CEntityValueNode; class CTypedefEntity; class CContext; /** * @brief Entity smart pointer. */ using CEntityPtr = std::shared_ptr; /** * @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; /** * @brief List with entities in the order they appear in code. */ using CEntityList = std::list; /** * @brief Vector with entities in the order they appear in code. */ using CEntityVector = std::vector; /** * @brief Entity value shared pointer. */ using CValueNodePtr = std::shared_ptr; /** * @brief Entity value vector. */ using CEntityValueVector = std::vector; /** * @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; default: return false; } } /** * @brief Declaration type name association. */ using TDeclTypeAssoc = std::pair; /** * @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 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& 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& 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 m_ptrValueType; ///< The value type template parameter for "sequence", "pointer", "map" and ///< "bitfield". std::shared_ptr 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 { 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 " ". * @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 TEntity* Get(); template 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 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 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 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 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 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 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 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 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 m_ptrChildDefMap; ///< Shared children map containing all the child definitions ///< for the entities with the same scope. std::shared_ptr 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 m_vecDeclTypes; ///< Decl types extended with additional types based on the ///< enabled extension on the command line. }; template TEntity* CEntity::Get() { return dynamic_cast(this); } template const TEntity* CEntity::Get() const { return dynamic_cast(this); } template 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); // 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(rptrContext, ptrParent, tParams...); // Add the entity to the parent's children list. pParent->AddChild(ptrEntity); return ptrEntity; } template TEntity* CEntity::Find(const std::string& rssScopedName) const { return dynamic_cast(Find(rssScopedName).get()); } template TValueNode* CEntity::FindValue(const std::string& rssScopedNameInclMembers) const { auto ptrtValueNode = FindValue(rssScopedNameInclMembers); return dynamic_cast(ptrtValueNode.get()); } #endif // !defined(ENTITY_BASE_H)