Precommit (#1)

* first commit

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

View File

@@ -0,0 +1,59 @@
#include "attribute_entity.h"
CAttributeEntity::CAttributeEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bReadOnly) :
CDeclarationEntity(rptrContext, ptrParent), m_bReadOnly(bReadOnly),
m_iteratorReadExceptions(GetReadExceptionVector()), m_iteratorWriteExceptions(GetWriteExceptionVector())
{}
sdv::interface_t CAttributeEntity::GetInterface(sdv::interface_id idInterface)
{
// Expose interfaces
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IAttributeEntity>())
return static_cast<sdv::idl::IAttributeEntity*>(this);
return CDeclarationEntity::GetInterface(idInterface);
}
sdv::idl::IEntityIterator* CAttributeEntity::GetReadExceptions()
{
if (!GetReadExceptionVector().empty()) return &m_iteratorReadExceptions;
return nullptr;
}
sdv::idl::IEntityIterator* CAttributeEntity::GetWriteExceptions()
{
if (!GetWriteExceptionVector().empty()) return &m_iteratorWriteExceptions;
return nullptr;
}
void CAttributeEntity::Process()
{
CDeclarationEntity::Process();
}
bool CAttributeEntity::SupportArrays() const
{
return false;
}
bool CAttributeEntity::IsReadOnly() const
{
return m_bReadOnly;
}
bool CAttributeEntity::SupportMultipleDeclarations() const
{
return true;
}
bool CAttributeEntity::SupportRaiseExceptions() const
{
return true;
}
bool CAttributeEntity::SupportSeparateSetGetRaiseExceptions() const
{
return true;
}

View File

@@ -0,0 +1,99 @@
#ifndef ATTRIBUTE_ENTITY_H
#define ATTRIBUTE_ENTITY_H
#include "declaration_entity.h"
/**
* @brief The attribute definition of an IDL file.
* @details The attribute section of the IDL file defines attribute values.
*/
class CAttributeEntity : public CDeclarationEntity, public sdv::idl::IAttributeEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] bReadOnly When set, the attribute is defined as readonly.
*/
CAttributeEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bReadOnly);
/**
* @brief Destructor
*/
virtual ~CAttributeEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get the list of possible exceptions that might be fired during a read operation. Overload of
* sdv::idl::IAttributeEntity::GetReadExceptions.
* @return Returns a pointer to the exceptions iterator or NULL when no exceptions were defined.
*/
virtual sdv::idl::IEntityIterator* GetReadExceptions() override;
/**
* @brief Get the list of possible exceptions that might be fired during a write operation. Overload of
* sdv::idl::IAttributeEntity::GetWriteExceptions.
* @return Returns a pointer to the exceptions iterator or NULL when no exceptions were defined.
*/
virtual sdv::idl::IEntityIterator* GetWriteExceptions() override;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the attribute entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_attribute; }
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
protected:
/**
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const override;
/**
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override;
/**
* @brief Does the entity support multiple declarations on one line of code? Overload of
* CDeclarationEntity::SupportMultipleDeclarations.
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
*/
virtual bool SupportMultipleDeclarations() const override;
/**
* @brief Does the entity support raising exceptions? Overload of CDeclarationEntity::SupportRaiseExceptions.
* @return Returns 'true' when the entity supports exceptions; 'false' otherwise.
*/
virtual bool SupportRaiseExceptions() const override;
/**
* @brief Does the entity support separate set/get raising exceptions? Overload of
* CDeclarationEntity::SupportSeparateSetGetRaiseExceptions.
* @return Returns 'true' when the entity supports separate set/get raise exceptions; 'false' otherwise.
*/
virtual bool SupportSeparateSetGetRaiseExceptions() const override;
private:
bool m_bReadOnly = false; ///< When set, the attribute is readonly.
CEntityIterator m_iteratorReadExceptions; ///< Exceptions iterator for read exceptions
CEntityIterator m_iteratorWriteExceptions; ///< Exceptions iterator for write exceptions
};
#endif // !defined(ATTRIBUTE_ENTITY_H)

View File

@@ -0,0 +1,749 @@
#include "declaration_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "../token.h"
#include "../tokenlist.h"
#include "../support.h"
#include "../lexer.h"
#include "../constvariant.inl"
#include "../parser.h"
#include "struct_entity.h"
#include "interface_entity.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include "attribute_entity.h"
#include "operation_entity.h"
#include "exception_entity.h"
#include "parameter_entity.h"
#include "enum_entity.h"
#include "union_entity.h"
#include <functional>
#include <type_traits>
#include <limits>
CDeclarationEntity::CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CEntity(rptrContext, ptrParent)
{}
CDeclarationEntity::CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
const CTokenList& rlstTokenList) :
CEntity(rptrContext, ptrParent, rlstTokenList)
{}
sdv::interface_t CDeclarationEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IDeclarationEntity>())
return static_cast<sdv::idl::IDeclarationEntity*>(this);
return CEntity::GetInterface(idInterface);
}
sdv::IInterfaceAccess* CDeclarationEntity::GetDeclarationType() const
{
return const_cast<CTypeDeclaration*>(&m_typedecl);
}
CEntityPtr CDeclarationEntity::GetTypeEntity() const
{
return m_typedecl.GetTypeDefinitionEntityPtr();
}
bool CDeclarationEntity::HasArray() const
{
return m_vecMultiArraySizeTokenList.size() ? true : false;
}
sdv::sequence<sdv::idl::SArrayDimension> CDeclarationEntity::GetArrayDimensions() const
{
sdv::sequence<sdv::idl::SArrayDimension> seqArrayDimensions;
if (!HasArray()) return seqArrayDimensions;
// Traverse through each array entry
std::function<void(const CValueNodePtr& ptrValue)> fnCollectArrayDimensions =
[&](const CValueNodePtr& ptrValue)
{
// Is the value node an array at all?
CArrayValueNode* pArrayValue = ptrValue->Get<CArrayValueNode>();
if (!pArrayValue) return;
// Fill the array dimension struct
sdv::idl::SArrayDimension sArrayDimension{};
sArrayDimension.eType = sdv::idl::SArrayDimension::EDimensionType::bound;
if (pArrayValue->IsUnbound())
sArrayDimension.eType = sdv::idl::SArrayDimension::EDimensionType::unbound;
sArrayDimension.ssExpression = MakeFullScoped(pArrayValue->GetSizeExpression());
// Store in sequence
seqArrayDimensions.push_back(sArrayDimension);
// Process the next array dimension
if (pArrayValue->GetSize() != 0)
fnCollectArrayDimensions((*pArrayValue)[0]);
};
// Collect the array dimensions.
fnCollectArrayDimensions(ValueRef());
return seqArrayDimensions;
}
bool CDeclarationEntity::HasAssignment() const
{
return !m_lstAssignmentTokenList.empty();
}
sdv::u8string CDeclarationEntity::GetAssignment() const
{
std::stringstream sstreamAssignment;
bool bInitial = true;
for (const CToken& rToken : m_lstAssignmentTokenList)
{
if (!bInitial) sstreamAssignment << " ";
bInitial = false;
sstreamAssignment << static_cast<std::string>(rToken);
}
return sstreamAssignment.str();
}
void CDeclarationEntity::Process()
{
CLog log("Processing declaration (preparation)...");
// Determine whether the comments are preceding the token (either on the same line or the line before).
CTokenList lstPreComments = GetPreCommentTokenList();
if (!lstPreComments.empty()) SetCommentTokens(lstPreComments);
// Process the type
CTypeDeclaration sTypeDecl = ProcessType();
// Check for the support of interface and void types
if (sTypeDecl.GetBaseType() == sdv::idl::EDeclType::decltype_interface && !SupportInterface())
throw CCompileException("The declaration of interfaces is not supported.");
if (sTypeDecl.GetBaseType() == sdv::idl::EDeclType::decltype_void && !SupportVoid())
throw CCompileException("The use of 'void' as type is not supported.");
// Preprocess potential array declaration (only for operations).
if (GetType() == sdv::idl::EEntityType::type_operation)
PreprocessArrayDeclaration();
// Process the declaration
ProcessDeclaration(sTypeDecl);
}
void CDeclarationEntity::ProcessDeclaration(const CTypeDeclaration& rTypeDecl)
{
// Store the type
m_typedecl = rTypeDecl;
CLog log("Processing declaration...");
// Expecting an identifier.
CToken token = GetToken();
if (token.GetType() == ETokenType::token_keyword)
{
// Keywords as names are allowed if the extension is enabled.
if (!GetParserRef().GetEnvironment().ContextDependentNamesExtension())
throw CCompileException(token, "The identifier cannot be a reserved keyword.");
}
else if (token.GetType() != ETokenType::token_identifier)
throw CCompileException(token, "Expecting an identifier.");
SetName(token);
log << "Declaration name '" << GetName() << "'..." << std::endl;
// Preprocess potential array declaration (not for operations).
if (GetType() != sdv::idl::EEntityType::type_operation)
PreprocessArrayDeclaration();
// Further processing...
token = GetToken();
// Requires parameters?
if (RequiresParameters())
{
// Expect a left bracket
if (token != "(") throw CCompileException(token, "Expected left bracket '('.");
log << "Reading parameter list..." << std::endl;
PreprocessTokenListVector(m_vecParametersTokenList);
// Expect a right bracket
token = GetToken();
if (token != ")")
throw CCompileException(token, "Expected right bracket ')'.");
// Get the next token...
token = GetToken();
// Check for the 'const' keyword. If set, the operation is defined as const-operation.
if (token == "const")
{
SetOperationAsConst();
token = GetToken();
}
}
// Supports exceptions
if (SupportRaiseExceptions())
{
while (true)
{
// Check for the 'raises' keyword.
enum class EExceptType {raises, getraises, setraises, none} eExceptType = EExceptType::none;
if (token == "raises")
eExceptType = EExceptType::raises;
else if (token == "getraises")
eExceptType = EExceptType::getraises;
else if (token == "setraises")
eExceptType = EExceptType::setraises;
if (eExceptType == EExceptType::none)
break;
// Check for validity
if (!SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::getraises)
throw CCompileException(token,
"Cannot set a separate 'get-raises' exception list; use the 'raises' keyword instead.");
if (!SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::setraises)
throw CCompileException(token,
"Cannot set a separate 'set-raises' exception list; use the 'raises' keyword instead.");
if (SupportSeparateSetGetRaiseExceptions() && eExceptType == EExceptType::raises && IsReadOnly())
eExceptType = EExceptType::getraises;
if (eExceptType == EExceptType::setraises && IsReadOnly())
throw CCompileException(token, "Cannot set a set-raises exception list for a readonly type.");
if ((eExceptType == EExceptType::raises) && !m_vecRaisesExceptionsTokenList.empty())
throw CCompileException(token, "Multiple definitions of 'raises' exceptions are not allowed.");
if ((eExceptType == EExceptType::setraises) && !m_vecSetRaisesExceptionsTokenList.empty())
throw CCompileException(token, "Multiple definitions of 'set-raises' exceptions are not allowed.");
if ((eExceptType == EExceptType::getraises) && !m_vecGetRaisesExceptionsTokenList.empty())
throw CCompileException(token, "Multiple definitions of 'get-raises' exceptions are not allowed.");
// Expect a left bracket
token = GetToken();
if (token != "(") throw CCompileException(token, "Expected left bracket '('.");
// Processes raises exception list.
switch (eExceptType)
{
case EExceptType::raises:
log << "Reading 'raises' exception list..." << std::endl;
PreprocessTokenListVector(m_vecRaisesExceptionsTokenList);
if (m_vecRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
break;
case EExceptType::setraises:
log << "Reading 'setraises' exception list..." << std::endl;
PreprocessTokenListVector(m_vecSetRaisesExceptionsTokenList);
if (m_vecSetRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
break;
case EExceptType::getraises:
log << "Reading 'getraises' exception list..." << std::endl;
PreprocessTokenListVector(m_vecGetRaisesExceptionsTokenList);
if (m_vecGetRaisesExceptionsTokenList.empty()) throw CCompileException(token, "Missing exception types.");
break;
default:
break;
}
// Expect a right bracket
token = GetToken();
if (token != ")")
throw CCompileException(token, "Expected right bracket ')'.");
// Get the next token...
token = GetToken();
}
}
// Is there an assignment?
if (token == "=")
{
if (!SupportAssignments())
throw CCompileException(token, "Assignment operator detected, but type doesn't support assignments.");
log << "Declaration assignment detected; storing expression for later processing..." << std::endl;
// Read the tokens for the assignment expression. Read until ';' or ','; the latter not within an expression
// sub-statement.
size_t nDepth = 0;
log << "Assignment expression:" << std::endl;
while(true)
{
token = GetToken();
if (!token)
throw CCompileException("Unexpected end of file found; missing ';'.");
if (token == ";" || ((token == "," || token == "}") && !nDepth))
break;
log << " " << static_cast<std::string>(token);
if (token == "{") nDepth++;
if (token == "}") nDepth--;
m_lstAssignmentTokenList.push_back(token);
}
log << std::endl;
} else
{
// Does the entity need an assignment?
if (RequiresAssignment())
throw CCompileException(token, "Expecting an assignment operator.");
}
// Assign any succeeding comments
ProcessPostCommentTokenList(token.GetLine());
// Another declaration?
if (token == ",")
{
if (!SupportMultipleDeclarations())
throw CCompileException(token, "Multiple declarations on a single line of code is not supported for this type.");
log << "Another declaration of the same type..." << std::endl;
// Peek for ending the definition
if (DoNotEnfoceNextDeclarationAfterComma() && PeekToken() == "}") return;
// Create another declaration
CDeclarationEntity* pTypeEntity = nullptr;
if (Get<CVariableEntity>()) pTypeEntity = CreateChild<CVariableEntity>(token.GetContext(), GetParentEntity().get(), IsReadOnly(), false)->Get<CDeclarationEntity>();
else if (Get<CEnumEntry>()) pTypeEntity = CreateChild<CEnumEntry>(token.GetContext(), GetParentEntity().get())->Get<CDeclarationEntity>();
else if (Get<CAttributeEntity>()) pTypeEntity = CreateChild<CAttributeEntity>(token.GetContext(), GetParentEntity().get(), IsReadOnly())->Get<CDeclarationEntity>();
else
throw CCompileException(token, "Unexpected token ','.");
if (!pTypeEntity) throw CCompileException(token, "Internal error: failed to create another declaration entity.");
// Set the new begin position of the declaration
CToken tokenTemp = PeekToken();
pTypeEntity->SetBeginPosition(tokenTemp.GetLine(), tokenTemp.GetCol());
// Use the same type for the processing.
pTypeEntity->ProcessDeclaration(m_typedecl);
// Done.
return;
}
// Set the end position of the declaration
SetEndPosition(token.GetLine(), token.GetCol());
// Reinsert the token
PrependToken(token);
}
void CDeclarationEntity::PreprocessArrayDeclaration()
{
CLog log("Checking for array...");
// For each array dimension, add a tokenlist to the m_vecMultiArraySizeTokenList variable.
bool bIsArray = false;
while (true)
{
// Check for an array
CToken token = GetToken();
if (token != "[")
{
PrependToken(token);
break;
}
if (!SupportArrays())
throw CCompileException(token, "Unexpected token '['.");
log << "Array detected; storing expression for later processing..." << std::endl;
log << "Array expression: [";
// Check for multidimensional arrays
if (bIsArray && !GetParserRef().GetEnvironment().MultiDimArrayExtension())
throw CCompileException(token, "Multi-dimentsional arrays are not allowed. Unexpected token '['.");
bIsArray = true;
// Read the tokens for the array size. Read until ']'.
CTokenList lstArraySize;
size_t nDepth = 1;
while (true)
{
token = GetToken();
log << " " << static_cast<std::string>(token);
if (!token)
throw CCompileException("Unexpected end of file found; missing ']'.");
if (token == ";")
throw CCompileException("Unexpected end of declaration; missing ']'.");
if (token == "[")
nDepth++;
if (token == "]")
{
nDepth--;
if (!nDepth)
{
m_vecMultiArraySizeTokenList.push_back(std::move(lstArraySize));
break;
}
}
lstArraySize.push_back(token);
}
log << std::endl;
}
}
void CDeclarationEntity::PreprocessTokenListVector(std::vector<CTokenList>& rvecTokenList)
{
CLog log("Checking for comma separated token lists...");
CTokenList lstTokens;
bool bInitial = true;
while (true)
{
// Check for array index (allowed in certain situations)
CToken token = GetToken();
if (token == "[")
{
do
{
lstTokens.push_back(token);
token = GetToken();
} while (token && token != "]");
lstTokens.push_back(token);
token = GetToken();
}
// Check for template parameters
if (token == "<")
{
size_t nDepth = 0;
do
{
if (token == "<") nDepth++;
if (token == ">>") // Special case when closing nested templates.
{
token = CToken(">", ETokenType::token_operator);
PrependToken(token);
}
if (token == ">") nDepth--;
lstTokens.push_back(token);
token = GetToken();
} while (token && static_cast<bool>(nDepth));
lstTokens.push_back(token);
token = GetToken();
}
// Check for end of processing
if (!token || token == "]" || token == ")" || token == ";")
{
if (!bInitial)
rvecTokenList.push_back(std::move(lstTokens));
PrependToken(token);
break;
}
if (bInitial)
log << "Comma separated list detected: ";
bInitial = false;
log << " " << static_cast<std::string>(token);
// Check for comma separator
if (token == ",")
{
rvecTokenList.push_back(std::move(lstTokens));
continue;
}
// Add the token to the token list
lstTokens.push_back(token);
}
if (rvecTokenList.empty())
log << "No comma separated list detected..." << std::endl;
else
log << std::endl;
}
void CDeclarationEntity::PostProcess()
{
CLog log("Post process declaration...");
// Check the assignment processing progression state...
switch (m_eProcAssState)
{
case EProcessAssignmentProgression::unprocessed:
// Not processed yet, start processing...
m_eProcAssState = EProcessAssignmentProgression::currently_processing;
break;
case EProcessAssignmentProgression::currently_processing:
log << "Post processing declaration assignment takes place already; cannot do this more than once at the same time..."
<< std::endl;
// Alarm, circular references... cannot continue.
throw CCompileException("Circular referencing entity.");
case EProcessAssignmentProgression::processed:
default:
// Already done...
log << "Post processing declaration was done before; no need to repeat..." << std::endl;
return;
}
// The parent value is the value of the parent entity, if there is any value.
CValueNodePtr ptrValueParent = GetParentEntity() ? GetParentEntity()->ValueRef() : nullptr;
if (ptrValueParent)
log << "The parent entity '" << GetParentEntity()->GetName() << "' has a value node..." << std::endl;
else
log << "No parent entity or no value node assigned to the parent entity..." << std::endl;
// Create a value at each bottom leaf of a multi-dimensional array.
std::function<void(CValueNodePtr&, const CValueNodePtr, std::function<CValueNodePtr(const CValueNodePtr)>)> fnCreateAtBottomLeaf =
[&](CValueNodePtr& rptrValue, const CValueNodePtr& rptrValueParent, std::function<CValueNodePtr(const CValueNodePtr)> fnCreate)
{
// Check for an array value
CArrayValueNode* psArrayValue = dynamic_cast<CArrayValueNode*>(rptrValue.get());
// If there is an array value, call the function once more for each leaf.
if (psArrayValue)
{
for (size_t nIndex = 0; nIndex < psArrayValue->GetSize(); nIndex++)
fnCreateAtBottomLeaf((*psArrayValue)[nIndex], rptrValue, fnCreate);
return;
}
// Create a new element...
rptrValue = fnCreate(rptrValueParent);
};
// Process parameters - since parameters might depend on other parameters, do the processing in two steps.
size_t nIndex = 1;
for (const CTokenList& rlstTokenList : m_vecParametersTokenList)
{
log << "Processing parameter #" << nIndex++ << std::endl;
CEntityPtr ptrEntity = std::make_shared<CParameterEntity>(GetContext(), shared_from_this(), rlstTokenList);
ptrEntity->Process();
m_vecParameters.push_back(ptrEntity);
}
for (CEntityPtr& rptrParameter : m_vecParameters)
rptrParameter->Get<CParameterEntity>()->PostProcess();
// Build array tree
if (m_vecMultiArraySizeTokenList.empty()) log << "No array processing needed..." << std::endl;
else if (m_vecMultiArraySizeTokenList.size() == 1) log << "Single-dimensional array processing needed..." << std::endl;
else log << "Multi-dimensional array processing needed..." << std::endl;
for (const CTokenList& rlstArrayExpression : m_vecMultiArraySizeTokenList)
{
std::pair<CConstVariant, bool> prArraySize = {0, false};
log << "Start processing array dimension..." << std::endl;
// Empty expression indicates retrieving the size from the assignment.
if (!rlstArrayExpression.empty())
{
log << "Calculate the array size..." << std::endl;
prArraySize = ProcessNumericExpression(rlstArrayExpression);
// Is the array size dynamic?
if (prArraySize.second)
throw CCompileException(*rlstArrayExpression.begin(), "Cannot use non-const variable for the array size.");
log << "The array has " << prArraySize.first.Get<uint32_t>() << " elements..." << std::endl;
// Check whether the size is integral
if (!prArraySize.first.IsIntegral())
throw CCompileException(*rlstArrayExpression.begin(), "Only integral data types are supported for the array size.");
if ((prArraySize.first < CConstVariant(0)).Get<bool>())
throw CCompileException(*rlstArrayExpression.begin(), "Invalid array size.");
} else
{
log << "Array is defined as unbound array retrieving the size from the variable assignment..." << std::endl;
// Unbound arrays are not possible for writable variables. Exception are operations, attributes and parameters of local
// interfaces.
bool bError = true;
switch (GetType())
{
case sdv::idl::EEntityType::type_typedef:
bError = false;
break;
case sdv::idl::EEntityType::type_variable:
// When not read-only, this is an error.
if (IsReadOnly()) bError = false;
break;
default:
break;
}
if (bError)
throw CCompileException("Retrieving the size of the array through its assignment is"
" only possible with const declarations and typedefs.");
}
// The array creation function
auto fnCreateArray = [&, this](const CValueNodePtr& rptrValueParent) -> CValueNodePtr
{
std::shared_ptr<CArrayValueNode> ptrArrayValue = std::make_shared<CArrayValueNode>(shared_from_this(), rptrValueParent);
if (rlstArrayExpression.empty())
ptrArrayValue->SetFixedSizeUnbound();
else if (prArraySize.second)
ptrArrayValue->SetDynamicSize(prArraySize.first.Get<size_t>(), rlstArrayExpression);
else
ptrArrayValue->SetFixedSize(prArraySize.first.Get<size_t>(), rlstArrayExpression);
return ptrArrayValue;
};
// Create the array value at the bottom leaf.
fnCreateAtBottomLeaf(ValueRef(), ptrValueParent, fnCreateArray);
log << "Finalized processing array dimension..." << std::endl;
}
// Add the values of the type.
if (m_vecMultiArraySizeTokenList.size() == 0)
log << "Copy the existing type value tree or create a declaration value node for this assignment..." << std::endl;
else
log << "For each array element, copy the existing type value tree or create a"
" declaration value node for this assignment..." << std::endl;
auto fnCreateTypeValues = [&, this](const CValueNodePtr& rptrValueParent) -> CValueNodePtr
{
if (m_typedecl.GetTypeDefinitionEntityPtr())
{
// In case the original type was not processed yet, do so now.
CDeclarationEntity* pOriginalType = m_typedecl.GetTypeDefinitionEntityPtr()->Get<CDeclarationEntity>();
if (pOriginalType) pOriginalType->PostProcess();
// Copy the existing entity of the type... this contains all the default assignments already...
log << "Copy type value tree..." << std::endl;
CValueNodePtr ptrValue = m_typedecl.GetTypeDefinitionEntityPtr()->ValueRef();
if (ptrValue)
return ptrValue->CreateCopy(shared_from_this(), rptrValueParent);
else
{
if (pOriginalType)
throw CCompileException("Internal error: value tree must be available for '", GetName(), "'.");
log << "No value tree present; nothing to copy..." << std::endl;
return nullptr;
}
}
else
{
log << "Create declaration value node..." << std::endl;
return std::make_shared<CSimpleTypeValueNode>(shared_from_this(), ptrValueParent);
}
};
fnCreateAtBottomLeaf(ValueRef(), ptrValueParent, fnCreateTypeValues);
// If this is a variable declaration, add the value as part of the parent tree
if (CanSupportComplexTypeAssignments() && ptrValueParent)
{
log << "The entity value tree is part of the value tree of the parent node..." << std::endl;
ptrValueParent->AddChild(ValueRef());
}
// Add the assignment.
if (!m_lstAssignmentTokenList.empty())
{
log << "Assignment was available, process the assignment..." << std::endl;
if (!SupportAssignments())
throw CCompileException(*m_lstAssignmentTokenList.begin(), "Type definitions cannot be assigned any values.");
ValueRef()->ProcessValueAssignment(m_lstAssignmentTokenList);
} else
{
// Does the entity need an assignment?
if (RequiresAssignment())
throw CCompileException("Expecting an assignment operator for '", GetName(), "'.");
}
// Build raises exception lists
for (const CTokenList& rlstTokenList : m_vecRaisesExceptionsTokenList)
{
log << "Processing raising exception..." << std::endl;
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
throw CCompileException("Exception definition not found.");
if (SupportSeparateSetGetRaiseExceptions())
{
m_vecGetRaisesExceptions.push_back(prBase.second);
m_vecSetRaisesExceptions.push_back(prBase.second);
} else
m_vecRaisesExceptions.push_back(prBase.second);
log << "Entity could raise exception on operation/attribute: " << prBase.first << std::endl;
}
for (const CTokenList& rlstTokenList : m_vecSetRaisesExceptionsTokenList)
{
log << "Processing set-raising exception..." << std::endl;
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
throw CCompileException("Exception definition not found.");
m_vecSetRaisesExceptions.push_back(prBase.second);
log << "Entity could raise exception on set attribute: " << prBase.first << std::endl;
}
for (const CTokenList& rlstTokenList : m_vecGetRaisesExceptionsTokenList)
{
log << "Processing get-raising exception..." << std::endl;
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName(rlstTokenList);
if (prBase.first.empty() || !prBase.second || !prBase.second->Get<CExceptionEntity>())
throw CCompileException("Exception definition not found.");
m_vecGetRaisesExceptions.push_back(prBase.second);
log << "Entity could raise exception on get attribute: " << prBase.first << std::endl;
}
// Processing is finalized...
m_eProcAssState = EProcessAssignmentProgression::processed;
}
bool CDeclarationEntity::RequiresAssignment() const
{
if (!ValueRef()) return false; // No value assigned yet...
// If the type has an unbound array in its value, it requires assignment to determine the size of the type.
CValueNodePtr ptrValue = ValueRef();
while (ptrValue)
{
if (ptrValue->IsArray() && ptrValue->IsUnbound())
return true;
ptrValue = ptrValue->GetParentNode();
}
return false;
}
void CDeclarationEntity::CalcHash(CHashObject& rHash) const
{
// Add the type
if (m_typedecl.GetTypeDefinitionEntityPtr())
m_typedecl.GetTypeDefinitionEntityPtr()->CalcHash(rHash);
else
rHash << m_typedecl.GetTypeString();
// Add base entity
CEntity::CalcHash(rHash);
// Add array dimensions
sdv::sequence<sdv::idl::SArrayDimension> seqArray = GetArrayDimensions();
for (const sdv::idl::SArrayDimension& rsDimentation : seqArray)
{
rHash << "[";
if (!rsDimentation.ssExpression.empty())
rHash << rsDimentation.ssExpression;
rHash << "]";
}
// Get the assignment
std::string ssAssignment = GetAssignment();
if (!ssAssignment.empty()) rHash << ssAssignment;
// Add parameters
for (const CEntityPtr& rptrEntity : m_vecParameters)
rptrEntity->CalcHash(rHash);
// Add exceptions
for (const CEntityPtr& rptrEntity : m_vecRaisesExceptions)
{
rHash << "raises";
rptrEntity->CalcHash(rHash);
}
// Add get-exceptions
for (const CEntityPtr& rptrEntity : m_vecGetRaisesExceptions)
{
rHash << "get_raises";
rptrEntity->CalcHash(rHash);
}
// Add set-exceptions
for (const CEntityPtr& rptrEntity : m_vecSetRaisesExceptions)
{
rHash << "set_raises";
rptrEntity->CalcHash(rHash);
}
// Add whether it is readonly
if (IsReadOnly())
rHash << "const";
}

View File

@@ -0,0 +1,372 @@
#ifndef BASIC_TYPE_ENTITY_H
#define BASIC_TYPE_ENTITY_H
#include "entity_base.h"
#include "entity_value.h"
#include "../constvariant.h"
#include <vector>
/**
* @brief The base for declaration entity definitions within an IDL file (declarations, typedefs, attributes, operations,
* parameters, case declarations, enum entries).
* @details The declaration entity definitions all have a similar setup with small differences in detail. Consider the following
* structures:
* @code
* <type> <name> = <value>
* const <type> <name> = <value>
* readonly attribute <name>
* <operation_type> <operation_name>(<parameter_type> <parameter_name>) const
* @endcode
* The following generalized structure applies to all declaration structures:
* @code
* prefix type name
* prefix type name = value
* prefix type name(parameters) postfix
* @endcode
* The first statement is a declaration. The second statement is a declaration with an assignment. The last statement represents
* an operation.
* The prefix is used to provide a specific interpretation to the declaration (in, out, inout, const, attribute, readonly,
* typedef, struct, union, enum).
* The type defines the type the declaration represents (either a system type or a typedefed type - scoped name).
* The name is the defined name o the declaration.
* The value is the expression used for the assignment.
* The parameters are a list of zero or more declaration statements.
* The postfix is used to provide a specific interpretation to the declaration (const).
* Some declarations might start as a complex type (e.g. struct, union, enum). The might contain the type definition as well as
* the declaration. For example:
* @code
* struct <def_name> { <definition> } <decl_name>
* struct { <definition> } <decl_name>
* @endcode
* In the first statement, the struct is defined and declared in one statement. In the second statement, an anonymous struct is
* defined and declared in one statement.
* Multiple declarations are possible for many types. The declarations are separated by a comma and follow the same rules as a
* single declaration starting at the &lt;name&gt;.
* @code
* <type> <name_1> = <value_1>, <name_2> = <value_2>, <name_3>, <name_4> = <value_4>
* @endcode
*/
class CDeclarationEntity : public CEntity, public sdv::idl::IDeclarationEntity
{
friend CSimpleTypeValueNode;
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Constructor using the provided token-list to process the code.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
*/
CDeclarationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList);
/**
* @brief Destructor
*/
virtual ~CDeclarationEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get declaration type. Overload of sdv::idl::IDeclarationEntity::GetDeclarationType.
* @return Interface to the declaration type object.
*/
virtual sdv::IInterfaceAccess* GetDeclarationType() const override;
/**
* @brief Is array? Overload of sdv::idl::IDeclarationEntity::HasArray/HasDynamicArray.
* @return Retrurns whether the declaration reqpresents an array.
*/
virtual bool HasArray() const override;
/**
* @brief Get the array dimensions (if there are any). Overload of IDeclarationEntity::GetDimensionCount.
* @return Smart pointer to the sequence of array dimensions.
*/
virtual sdv::sequence<sdv::idl::SArrayDimension> GetArrayDimensions() const override;
/**
* @brief Has assignment? Overload of sdv::idl::IDeclarationEntity::HasAssignment.
* @return Returns whether the declaration has an assignment.
*/
virtual bool HasAssignment() const override;
/**
* @brief Get assignment string. Overload of sdv::idl::IDeclarationEntity::GetAssignment.
* @details The assignment can be an algebraic expression composed from constants and variables. If the assignment is an array,
* the expression is composed like this: {{expr1},{expr2},{expr...}}
* @return On success, returns the assignment string object or an empty string when no assignment is available.
*/
virtual sdv::u8string GetAssignment() const override;
/**
* @brief Get the base type of the entity.
* @return Returns the base type.
*/
virtual sdv::idl::EDeclType GetBaseType() const { return m_typedecl.GetBaseType(); }
/**
* @brief Get the type entity if the type is not a system type.
* @details Complex types (struct, enum, union) and type definitions are based on a type entity.
* @return Returns a pointer to the type entity if available.
*/
CEntityPtr GetTypeEntity() const;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Process a declaration.
* @details The processing of a declaration is done through several steps: processing the declaration type, processing the
* declaration identifier, processing (multi-dimensional) arrays, processing assignments, processing the next declaration
* identifier and so on.
* The following statement are examples:
* @code
* <type> <identifier>; // No assignment, one declaration
* <type> <identifier>, <identifier>; // No assignment, multiple declarations
* <type> <identifier>=<expression>; // One definition (declaration with assignment)
* <type> <identifier>=<expressoin>, <identifier>=<expression>; // Multiple definitions
* <type> <identifier>=<expression>, <identifier>; // Mixed expression, definition
* <type> <identifier>[]={<expression>, <expression>}; // Array definition
* <type> <identifier>[<expression>]; // Array declaration
* <type> <identifier>[<expression>]={<expression>, <expression>}; // Array definition
* struct <type> <identifier>; // Struct declaration with explicit struct keyword
* struct <type> <identifier>={<expression>, <expression>}; // Struct declaration with assignment
* union <type> <identifier>; // Union declaration with explicit union keyword
* enum <type> <identifier>; // Enum declaration with explicit enum keyword
* enum <type> <identifier>=<exppression>; // Enum definition with explicit enum keyword
* @endcode
* The 'type' can be a system type (short, int64, float) or a scoped type definition (MyType, \::MyModule\::MyType). Without
* assignment the type can be 'struct' or 'union', with or without the 'struct' and 'union' type identification (not allowed
* for const entities, which need an assignment).
* The 'identifier' is the unique name for the declaration. This name must be case-insensitive unique within the current
* scope. The identifier can be followed by square-brackets indicating an array. The size of the array can either be retrieved
* through the assignment or through the expression. If both an assignment and an expression are available, they must match.
* The array expression must be of an integral type and is not allowed to become negative. Furthermore, it can be created
* through a mathematical expression existing of constants and/or when not defined to be a constant entity, through
* declarations made before (this deviates to C/C++, where dynamic arrays are not allowed). In case of a dynamic array, an
* assignment is not supported.
* The assignment 'expression' defines a mathematical expression existing of constants and/or when not defined to be a
* constant entity, through declarations made before.
* @remarks Array size expressions and assignment expressions are stored as tokenlists to be processed by the
* ProcessValueAssignment function.
* @param[in] rTypeDecl Reference to the type identifier (can be a system type as well as a scoped name to a previously
* defined type).
*/
void ProcessDeclaration(const CTypeDeclaration& rTypeDecl);
/**
* @brief Preprocess the multi-dimensional array declaration.
* @details Preprocess the potential multi-dimensional array declaration by detecting square brackets and storing the tokens
* between the brackets. The tokens for each dimension are placed in the m_vecMultiArraySizeTokenList vector.
*/
void PreprocessArrayDeclaration();
/**
* @brief Preprocess a list of comma separated declarations.
* @details Preprocess a list of tokens separated by the comma ',' separator and place the tokens in the provided vector. The
* processing is continued until a square bracket ']' or normal bracket ')' or no token exists any more.
* @param[in] rvecTokenList Reference to the vector containing the token lists to be filled.
*/
void PreprocessTokenListVector(std::vector<CTokenList>& rvecTokenList);
/**
* @brief Postprocess the token lists that where read in the preprocess functions.
* @pre SupportAssignments returns true and at least m_vecMultiArraySizeTokenList or m_lstAssignmentTokenList is filled.
* @details For typedef, const and declaration entities, create the value structure containing the arrays and the values of
* the type entity. For const and declaration entities, fill the value structure using the assignment stored in the assignment
* expression token list. For attributes and operations build the raising exception lists. For the operations process the
* parameter list.
*/
void PostProcess();
/**
* @brief Does the entity support assignments (const and variable declarations do, others don't)?
* @details Determines whether the entity supports assignments. Default value is 'false'.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportAssignments() const { return false; }
/**
* @brief Does the entity require an assignment (const declarations do)?
* @details Determines whether the entity requires an assignment. Default value is is based on the presence of an unbound
* value in the type.
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
*/
virtual bool RequiresAssignment() const;
/**
* @brief Can the entity be used for assignments of complex types (variable declarations do)?
* @details Returns whether the entity is defined to be usable for complex type assignments. Default value is 'false'.
* @return Returns 'true' when the entity defined as declaration; 'false' otherwise.
*/
virtual bool CanSupportComplexTypeAssignments() const { return false; }
/**
* @brief Does the entity support arrays (const and variable declarations, as well as typedefs and attributes do)?
* @details Determines whether the entity supports arrays. Default value is 'false'.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const { return false; }
/**
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of
* IDeclarationEntity::IsReadOnly.
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
* 'true'.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override { return true; }
/**
* @brief Is the entity transparent when used in a struct? Overload of IDeclarationEntity::IsAnonymous.
* @details Returns whether the entity is anonymous when used in a struct/union (unnamed and not declared). This allows its
* members to appear directly as members within the struct. Default value is 'false'.
* @return Returns 'true' when the entity defined as anonymous; 'false' otherwise.
*/
virtual bool IsAnonymous() const override { return false; }
/**
* @brief Does the entity support multiple declarations on one line of code (const and var declarations and attributes do)?
* @details Returns whether the entity supports multiple declarations separated by a comma ','. Default value is 'false'.
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
*/
virtual bool SupportMultipleDeclarations() const { return false; }
/**
* @brief Do not enforce next declaration after comma (enums do)?
* @pre SupportMultipleDeclarations needs to be supported.
* @details Returns whether the entity supports ending the definition after a comma ','. Default value is 'false'.
* @return Returns 'true' when not enforcing the next declaration; 'false' otherwise.
*/
virtual bool DoNotEnfoceNextDeclarationAfterComma() const { return false; }
/**
* @brief Does the entity support raising exceptions (attributes and operations do)?
* @details Returns whether the entity supports exceptions (defined through the keywords: raises, getraises and setraises).
* Default value is 'false'.
* @return Returns 'true' when the entity supports exceptions; 'false' otherwise.
*/
virtual bool SupportRaiseExceptions() const { return false; }
/**
* @brief Does the entity support separate set/get raising exceptions (only attributes do)?
* @details Returns whether the entity supports exceptions (defined through the keywords: getraises and setraises).
* Default value is 'false'.
* @return Returns 'true' when the entity supports separate set/get raise exceptions; 'false' otherwise.
*/
virtual bool SupportSeparateSetGetRaiseExceptions() const { return false; }
/**
* @brief Does the entity support an interface as base type (non-const variables, operations and parameters do)?
* @details Returns whether the entity supports the an interface as base type base type. Default value is 'false'.
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
*/
virtual bool SupportInterface() const { return false; }
/**
* @brief Does the entity support 'void' as base type (operations do)?
* @details Returns whether the entity supports the 'void' base type. Default value is 'false'.
* @return Returns 'true' when the entity supports void as base type; 'false' otherwise.
*/
virtual bool SupportVoid() const { return false; }
/**
* @brief Does the entity require parameters (operations do)?
* @details Returns whether the entity requires parameters. Default value is 'false'.
* @return Returns 'true' when the entity requires parameters; 'false' otherwise.
*/
virtual bool RequiresParameters() const { return false; }
/**
* @brief Set operation as const (operations only).
* @details If the declaration requires parameters, the declaration is checked for being defined as const operation. If so,
* this function is called. Default implementation doesn't do anything.
* @pre Only called when RequiresParameters is true and the declaration is defined as const.
*/
virtual void SetOperationAsConst() {}
/**
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
* @param[in, out] rHash Hash object to be filled with data.
*/
virtual void CalcHash(CHashObject& rHash) const override;
protected:
/**
* @brief Get parameter vector.
* @return Returns the vector with the parameter entities.
*/
CEntityVector& GetParamVector() { return m_vecParameters; }
/**
* @brief Get parameter vector.
* @return Returns the vector with the parameter entities.
*/
const CEntityVector& GetParamVector() const { return m_vecParameters; }
/**
* @brief Get "raises" exceptions vector.
* @return Returns the vector with the exception entities.
*/
CEntityVector& GetExceptionVector() { return m_vecRaisesExceptions; }
/**
* @brief Get "get_raises" exceptions vector.
* @return Returns the vector with the exception entities.
*/
CEntityVector& GetReadExceptionVector() { return m_vecGetRaisesExceptions; }
/**
* @brief Get "set_raises" exceptions vector.
* @return Returns the vector with the exception entities.
*/
CEntityVector& GetWriteExceptionVector() { return m_vecSetRaisesExceptions; }
private:
/**
* @brief Process assignment state.
* @details The assignment processing progression state which is used to control the processing of assignments as well as to
* prevent circular use of assignments.
*/
enum class EProcessAssignmentProgression
{
unprocessed, ///< Assignment hasn't been processed yet
currently_processing, ///< Processing currently takes place
processed, ///< Processing has been done
};
CTypeDeclaration m_typedecl; ///< The type definition of this declaration.
std::vector<CTokenList> m_vecMultiArraySizeTokenList; ///< The list of tokens for each array dimension to be
///< calculated during the post processing phase.
CTokenList m_lstAssignmentTokenList; ///< The list of tokens forming the assignment.
std::vector<CTokenList> m_vecRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
///< during the post processing phase.
std::vector<CTokenList> m_vecSetRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
///< during the post processing phase.
std::vector<CTokenList> m_vecGetRaisesExceptionsTokenList; ///< The list of tokens for each exception to be parsed
///< during the post processing phase.
std::vector<CTokenList> m_vecParametersTokenList; ///< The list of tokens for each parameter to be parsed
///< during the post processing phase.
EProcessAssignmentProgression m_eProcAssState = EProcessAssignmentProgression::unprocessed; ///< Processing assignment
///< progression state.
CEntityVector m_vecRaisesExceptions; ///< Can raise the exceptions while reading/writing.
CEntityVector m_vecGetRaisesExceptions; ///< Can raise the exceptions while reading.
CEntityVector m_vecSetRaisesExceptions; ///< Can raise the exceptions while writing.
CEntityVector m_vecParameters; ///< Vector of parameters.
};
#endif // !defined(BASIC_TYPE_ENTITY_H)

View File

@@ -0,0 +1,765 @@
#include "definition_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "../parser.h"
#include "struct_entity.h"
#include "union_entity.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include "attribute_entity.h"
#include "operation_entity.h"
#include "enum_entity.h"
#include "exception_entity.h"
#include "interface_entity.h"
#include "meta_entity.h"
#include <iostream>
CDefinitionEntity::CDefinitionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CEntity(rptrContext, ptrParent), m_iteratorChildren(GetChildrenVector()), m_iteratorInheritance(m_vecInheritance)
{}
CDefinitionEntity::CDefinitionEntity(CParser& rParser, const CContextPtr& rptrContext) :
CEntity(rParser, rptrContext), m_iteratorChildren(GetChildrenVector()), m_iteratorInheritance(m_vecInheritance)
{}
sdv::interface_t CDefinitionEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::idl::IDefinitionEntity>())
return static_cast<sdv::idl::IDefinitionEntity*>(this);
return CEntity::GetInterface(idInterface);
}
void CDefinitionEntity::ProcessContent()
{
CLog log("Processing definition content...");
// Get tokens until no token is returned any more.
while (true)
{
// Prepare proocessing the next token
CToken token = PeekToken();
// Add any meta entity
std::list<CParser::SMetaToken> lstMeta = GetParserRef().GetAndRemoveMeta();
for (const CParser::SMetaToken& rsMeta : lstMeta)
AddChild(std::make_shared<CMetaEntity>(rsMeta.tokenMeta.GetContext(), shared_from_this(), rsMeta.tokenMeta,
rsMeta.lstComments));
// Process the acquired token
if (!token) break;
if (!IsRootEntity() && token == "}")
break;
// Determine whether the comments are preceding the token (either on the same line or the line before).
CTokenList lstPreComments = GetPreCommentTokenList();
// Check for prefixes
bool bPrefixConst = false;
bool bPrefixReadOnly = false;
bool bPrefixTypedef = false;
bool bPrefixLocal = false;
token = GetToken();
uint32_t uiLineBegin = token.GetLine();
uint32_t uiColBegin = token.GetCol();
if (token == "const") // This must be a const declaration
{
if (!Supports(EDefinitionSupport::support_const_variable))
throw CCompileException(token, "Unexpected keyword 'const'.");
bPrefixConst = true;
token = GetToken();
}
else if (token == "readonly") // This must be a readonly attribute
{
if (!Supports(EDefinitionSupport::support_attribute))
throw CCompileException(token, "Unexpected keyword 'readonly'.");
bPrefixReadOnly = true;
token = GetToken();
} else if (token == "typedef") // This must be a typedef declaration
{
if (!Supports(EDefinitionSupport::support_typedef))
throw CCompileException(token, "Unexpected keyword 'typedef'.");
bPrefixTypedef = true;
token = GetToken();
} else if (token == "local") // This must be a const declaration
{
if (!Supports(EDefinitionSupport::support_interface))
throw CCompileException(token, "Unexpected keyword 'local'.");
bPrefixLocal = true;
token = GetToken();
// The next token must be interface
if (token != "interface")
throw CCompileException(token, "Unexpected token. Only interfaces can be local.");
}
// For keywords that could be a definition as well as a declaration, find out whether the statement here is a
// - forward declaration
// - a definition
// - a definition as well as a declaration
// - a declaration
// Check for a definition (first three points).
auto fnIsDefinition = [&]() -> bool
{
// A declaration without definition has the construction
// <def type> <def identifier> <decl identifier>;
// e.g.
// struct STest sTest;
// The <def type> was retrieved already. The next token would be the identifier.
if (PeekToken(0).GetType() == ETokenType::token_identifier &&
PeekToken(1).GetType() == ETokenType::token_identifier) return false;
// All other situations indicate a definition (possibly followed by a declaration).
return true;
};
CEntityPtr ptrDefinitionEntity;
CToken tokenDefinitionType = token;
if (token == "module" && fnIsDefinition())
{
if (!Supports(EDefinitionSupport::support_module))
throw CCompileException(token, "Unexpected keyword 'module'.");
ptrDefinitionEntity = CreateChild<CModuleEntity>(token.GetContext(), this);
}
else if (token == "enum" && fnIsDefinition())
{
if (fnIsDefinition() && !Supports(EDefinitionSupport::support_enum))
throw CCompileException(token, "Unexpected keyword 'enum'.");
ptrDefinitionEntity = CreateChild<CEnumEntity>(token.GetContext(), this);
}
else if (token == "exception" && fnIsDefinition())
{
if (!Supports(EDefinitionSupport::support_exception))
throw CCompileException(token, "Unexpected keyword 'exception'.");
ptrDefinitionEntity = CreateChild<CExceptionEntity>(token.GetContext(), this);
}
else if (token == "struct" && fnIsDefinition())
{
if (!Supports(EDefinitionSupport::support_struct))
throw CCompileException(token, "Unexpected keyword 'struct'.");
ptrDefinitionEntity = CreateChild<CStructEntity>(token.GetContext(), this);
}
else if (token == "union" && fnIsDefinition())
{
if (!Supports(EDefinitionSupport::support_union))
throw CCompileException(token, "Unexpected keyword 'union'.");
ptrDefinitionEntity = CreateChild<CUnionEntity>(token.GetContext(), this);
}
else if (token == "interface" && fnIsDefinition())
{
if (!Supports(EDefinitionSupport::support_interface))
throw CCompileException(token, "Unexpected keyword 'interface'.");
ptrDefinitionEntity = CreateChild<CInterfaceEntity>(token.GetContext(), this, bPrefixLocal);
}
// Definition available?
if (ptrDefinitionEntity)
{
// Assign the preceding comments (only if not prefixed)
if (!bPrefixConst && !bPrefixReadOnly && !bPrefixTypedef && !lstPreComments.empty())
{
ptrDefinitionEntity->SetCommentTokens(lstPreComments);
lstPreComments.clear();
}
// Set the location in the source file
ptrDefinitionEntity->SetBeginPosition(uiLineBegin, uiColBegin);
// Process the definition
log << "Detected " << static_cast<std::string>(token) << " definition..." << std::endl;
ptrDefinitionEntity->Process();
token = GetToken();
// Assign any succeeding comments
ptrDefinitionEntity->ProcessPostCommentTokenList(token.GetLine());
}
// A struct allows the definition of types that require a declaration within the struct, but the declaration is anonymous
// (unnamed and not declared) so the members of the definition appear as if they are part of the struct.
bool bAnonymousDecl = false;
if (token == ";" && GetType() == sdv::idl::EEntityType::type_struct && ptrDefinitionEntity &&
ptrDefinitionEntity->Get<CDefinitionEntity>()->RequireDeclaration())
{
if (ptrDefinitionEntity->Get<CDefinitionEntity>()->AllowAutoTransparentDeclaration())
{
// Allow processing still
PrependToken(token);
// Create a dummy name
token = CToken(GetParserRef().GenerateAnonymousEntityName("var"));
bAnonymousDecl = true;
} else
throw CCompileException(token,
"The definition requires a declaration following the definition content or cannot find a variable within "
"current scope - unexpected token ';'.");
}
// Statement finished?
if (token == ";")
{
if (bPrefixConst || bPrefixReadOnly || bPrefixTypedef)
throw CCompileException(token, "Unexpected token ';'.");
if (ptrDefinitionEntity)
{
// Assign any succeeding comments
ptrDefinitionEntity->ProcessPostCommentTokenList(token.GetLine());
// Set the end position in the source file.
ptrDefinitionEntity->SetEndPosition(token.GetLine(), token.GetCol());
// Declaration needed?
if (ptrDefinitionEntity->Get<CDefinitionEntity>()->RequireDeclaration())
throw CCompileException(token,
"The definition requires a declaration following the definition content - unexpected token ';'.");
}
continue;
};
if (!token && !bPrefixConst && !bPrefixReadOnly && !bPrefixTypedef)
throw CCompileException(GetLastValidToken(), "Missing ';' following the token.");
// The declarative part can consist of the following types of declaration
// - an attribute - read-only prefix possible
// - a typedef
// - an operation
// - a variable - const prefix possible
CEntityPtr ptrDeclarationEntity;
if (bPrefixReadOnly && token != "attribute")
throw CCompileException(token, "Expecting 'attribute' keyword following 'readonly'.");
if (token == "attribute")
{
if (bPrefixConst || bPrefixTypedef || ptrDefinitionEntity || !Supports(EDefinitionSupport::support_attribute))
throw CCompileException(token, "Unexpected keyword 'attribute'.");
ptrDeclarationEntity = CreateChild<CAttributeEntity>(token.GetContext(), this, bPrefixReadOnly);
if (bPrefixReadOnly)
log << "Detected read-only attribute declaration..." << std::endl;
else
log << "Detected attribute declaration..." << std::endl;
}
else if (token == "case" || token == "default")
{
if (bPrefixReadOnly || bPrefixConst || bPrefixTypedef || ptrDefinitionEntity || !Supports(EDefinitionSupport::support_case_declaration))
throw CCompileException(token, "Unexpected keyword 'case'.");
ptrDeclarationEntity = CreateChild<CCaseEntry>(token.GetContext(), this, token == "default");
log << "Detected case entry declaration..." << std::endl;
} else
{
// Reinsert the token into the tokenlist
PrependToken(token);
// Check whether the declaration is a variable declaration or an operation.
// An operation can have the following structure:
// <keyword> <identifier>(); e.g. int32 Func()
// <keyword> <keyword> <identifier>(); e.g. long long Func()
// <keyword> <keyword> <keyword> <identifier>(); e.g. unsigned long long Func()
// <identifier> <identifier>() e.g. mytype Func()
// A variable declaration can have the following structure:
// <keyword> <identifier>; e.g. int32 iVar;
// <keyword> <keyword> <identifier>; e.g. long long llVar;
// <keyword> <keyword> <keyword> <identifier>; e.g. unsigned long long ullVar;
// <keyword> <identifier> = <expression>; e.g. int32 iVar = 10;
// <keyword> <keyword> <identifier> = <expression>; e.g. long long llVar = 10;
// <keyword> <keyword> <keyword> <identifier> = <expression>; e.g. unsigned long long ullVar = 10;
// Only variables can be declared with const prefix.
// A variable declaration without assignment can also be a typedef when declared with typedef prefix.
// Operations cannot be declared follwoing a definition.
// As type expecting up to three keywords or one scoped identifier (composition of identifier and scope operator).
// If there is a definition, then the declaration and definition are combined. The type is there then already.
size_t nIndex = 0;
bool bTypeFound = ptrDefinitionEntity ? true : false;
CToken tokenLocal;
bool bLongType = false;
bool bUnsignedType = false;
while ((tokenLocal = PeekToken(nIndex)).GetType() == ETokenType::token_keyword)
{
// Unsigned is allowed only as first keyword
if (tokenLocal == "unsigned")
{
if (nIndex) break;
bUnsignedType = true;
}
// Long should be followed by long or double.
if (bLongType && tokenLocal != "long" && tokenLocal != "double") break;
// Increase the token index...
nIndex++;
// Type found...
bTypeFound = true;
// After unsigned, at least one more keyword needs to follow
if (bUnsignedType && nIndex == 1) continue;
// After long, another type can follow, but only when this long didn't follow a previous long already.
if (tokenLocal == "long")
{
if (bLongType) break; // type was long long.
bLongType = true;
continue;
}
// The type can be a templated type (or even nested templated types are possible).
tokenLocal = PeekToken(nIndex);
CToken tokenLocalTemplate;
if (tokenLocal == "<")
{
size_t nDepth = 0;
tokenLocalTemplate = tokenLocal;
do
{
if (tokenLocal == "<") nDepth++;
if (tokenLocal == ">") nDepth--;
if (tokenLocal == ">>") nDepth-=2; // This actually is an operator
nIndex++;
tokenLocal = PeekToken(nIndex);
} while (tokenLocal && static_cast<bool>(nDepth));
}
// No more types are expected to follow
break;
}
while (!bTypeFound)
{
// Check for the scope parameter
tokenLocal = PeekToken(nIndex);
if (tokenLocal == "::")
{
nIndex++;
tokenLocal = PeekToken(nIndex);
}
// Check for the identifier
if (tokenLocal.GetType() == ETokenType::token_identifier)
{
nIndex++;
if (PeekToken(nIndex) != "::")
bTypeFound = true;
continue;
}
// Coming here means, there was no type
throw CCompileException(tokenLocal, "Invalid token '", static_cast<std::string>(tokenLocal),
"' found for type name.");
}
// The return value can be an array - but only in case of operations.
tokenLocal = PeekToken(nIndex);
CToken tokenLocalArray;
while (tokenLocal == "[")
{
if (!tokenLocalArray) tokenLocalArray = tokenLocal;
do
{
nIndex++;
tokenLocal = PeekToken(nIndex);
} while (tokenLocal && tokenLocal != "]");
nIndex++;
tokenLocal = PeekToken(nIndex);
}
// Expecting identfier representing the name
// If the extension is enabled, this could also be a keyword.
if (tokenLocal.GetType() != ETokenType::token_identifier &&
(!GetParserRef().GetEnvironment().ContextDependentNamesExtension() ||
tokenLocal.GetType() != ETokenType::token_keyword))
throw CCompileException(tokenLocal, "Invalid token '", static_cast<std::string>(tokenLocal),
"' found for type name (or missing semi-colon ';' ?).");
nIndex++;
// An operation has a left bracket
tokenLocal = PeekToken(nIndex);
if (tokenLocal == "(") // This indicates a operation
{
if (ptrDefinitionEntity || bPrefixConst || bPrefixTypedef || !Supports(EDefinitionSupport::support_operation))
throw CCompileException(tokenLocal, "Unexpected left bracket '('.");
ptrDeclarationEntity = CreateChild<COperationEntity>(token.GetContext(), this);
log << "Detected operation declaration..." << std::endl;
}
else // This could be a variable declaration or a typedef declaration
{
// An array is not allowed when not using an operation
if (tokenLocalArray)
throw CCompileException(tokenLocalArray, "Invalid token '[' found for type name.");
// If there is a definition, add the name of the definition
if (ptrDefinitionEntity)
{
CToken tokenName(ptrDefinitionEntity->GetName());
PrependToken(tokenName);
}
// Check for typedef declaration
if (bPrefixTypedef)
{
ptrDeclarationEntity = CreateChild<CTypedefEntity>(token.GetContext(), this);
log << "Detected typedef declaration..." << std::endl;
}
else // Variable declaration
{
if (!bPrefixConst && !Supports(EDefinitionSupport::support_variable))
throw CCompileException(token, "Variable declaration is not supported.");
ptrDeclarationEntity = CreateChild<CVariableEntity>(token.GetContext(), this, bPrefixConst, bAnonymousDecl);
if (bPrefixConst)
log << "Detected const variable declaration..." << std::endl;
else
log << "Detected variable declaration..." << std::endl;
}
}
}
// Process the entity declaration.
if (!ptrDeclarationEntity) throw CCompileException("Declaration expected.");
ptrDeclarationEntity->SetBeginPosition(uiLineBegin, uiColBegin);
ptrDeclarationEntity->Process();
if (!lstPreComments.empty())
ptrDeclarationEntity->SetCommentTokens(lstPreComments);
// Expect ';'
token = GetToken();
if (token != ";")
throw CCompileException(token, "Missing semicolon ';' following the declaration.");
}
log << "For definition '" << GetName() << "', processing value assignments within content..." << std::endl;
// If supported create the value node for the definition (this allows assignments of values to this entity).
CreateValueNode();
// If there is a value node (assignment is supported), add the inherited value sub-trees to the type as children. If there are
// inherited entities with value nodes of their own, of course.
if (ValueRef())
CreateInheritanceValueChildNodes();
// Go through all the type members and do post processing (building value chains, resolving arrays, etc.).
for (CEntityPtr ptrTypeEntity : m_lstTypeMembers)
{
CTypedefEntity* pTypedefEntity = ptrTypeEntity->Get<CTypedefEntity>();
if (pTypedefEntity)
{
log << "Post-processing typedef entity '" << pTypedefEntity->GetName() << "'..." << std::endl;
pTypedefEntity->PostProcess();
}
CUnionEntity* pUnionEntity = ptrTypeEntity->Get<CUnionEntity>();
if (pUnionEntity)
{
log << "Post-processing union entity '" << pUnionEntity->GetName() << "'..." << std::endl;
pUnionEntity->PostProcess();
}
}
// Go through all the typedef members and do post processing (building value chains, resolving arrays, variable assignment,
// etc.).
for (CEntityPtr ptrConstEntity : m_lstConstMembers)
{
CVariableEntity* pConstEntity = ptrConstEntity->Get<CVariableEntity>();
if (!pConstEntity)
throw CCompileException("Internal error: non-const entities in const entity list.");
else
{
log << "Post-processing const variable entity '" << pConstEntity->GetName() << "'..." << std::endl;
pConstEntity->PostProcess();
}
}
// Go through all the definition members and do post processing (resolving arrays, creating exception and parameter lists,
// etc.).
for (CEntityPtr ptrDefinitionEntity : m_lstAttributesOperation)
{
CAttributeEntity* pAttribute = ptrDefinitionEntity->Get<CAttributeEntity>();
COperationEntity* pOperation = ptrDefinitionEntity->Get<COperationEntity>();
if (!pAttribute && !pOperation)
throw CCompileException("Internal error: wrong entities in definition list.");
if (pAttribute)
{
log << "Postprocessing attribute entity '" << pAttribute->GetName() << "'..." << std::endl;
pAttribute->PostProcess();
}
if (pOperation)
{
log << "Postprocessing operation entity '" << pOperation->GetName() << "'..." << std::endl;
pOperation->PostProcess();
}
}
// Go through all the variable members and create the default values for all var members if the value node is a compound type
// value node.
for (CEntityPtr ptrDeclEntity : m_lstDeclMembers)
{
CVariableEntity *pDeclEntity = ptrDeclEntity->Get<CVariableEntity>();
if (!pDeclEntity)
throw CCompileException("Internal error: non-declaration entity in declaration entity list.");
else
{
log << "Postprocess variable entity '" << pDeclEntity->GetName() << "'..." << std::endl;
pDeclEntity->PostProcess();
}
}
}
void CDefinitionEntity::Process()
{
CLog log("Processing definition of entity...");
// Check for an identifier.
// If present, this is the name of the definition.
CToken token = GetToken();
std::string ssName;
m_bAnonymousDefinition = false;
if (token.GetType() == ETokenType::token_identifier)
{
ssName = static_cast<std::string>(token);
log << "Definition type name '" << ssName << "'..." << std::endl;
} else
if (SupportsAnonymous())
{
if (!GetParentEntity() || GetParentEntity()->IsRootEntity())
throw CCompileException(token, "Unnamed definitions are not supported at root level.");
std::string ssPrefix = "anonymous";
switch (GetType())
{
case sdv::idl::EEntityType::type_enum: ssPrefix = "enum"; break;
case sdv::idl::EEntityType::type_struct: ssPrefix = "struct"; break;
case sdv::idl::EEntityType::type_union: ssPrefix = "union"; break;
case sdv::idl::EEntityType::type_module: ssPrefix = "namespace"; break;
case sdv::idl::EEntityType::type_interface: ssPrefix = "interface"; break;
case sdv::idl::EEntityType::type_exception: ssPrefix = "except"; break;
case sdv::idl::EEntityType::type_typedef: ssPrefix = "typedef"; break;
default: break;
}
ssName = GetParserRef().GenerateAnonymousEntityName(ssPrefix);
log << "Unnamed definition was automatically assigned name '" << ssName << "'..." << std::endl;
m_bRequiresContent = true;
m_bAnonymousDefinition = true;
PrependToken(token);
} else
throw CCompileException(token, "Unnamed definition is not supported.");
// Process the definition addendum
ProcessDefinitionAddendum();
// Expecting curly bracket when for a
token = GetToken();
if (RequireContentDefinition() && token != "{")
throw CCompileException(token, "Expecting curly bracket '{'.");
// If there is no content, consider the statement as a (forward) declaration.
SetName(ssName, token != "{");
// If there is no content, the processing is done.
if (token != "{")
{
log << "Definition type was defined as forward declaration." << std::endl;
log << "Finished processing definition entity..." << std::endl;
PrependToken(token);
return;
}
// Definition content...
ProcessContent();
// Close the definition
token = GetToken();
if (token != "}")
throw CCompileException(token, "Expecting curly bracket '}'.");
log << "Finished processing definition entity..." << std::endl;
}
void CDefinitionEntity::ProcessDefinitionAddendum()
{
// Check for inheritance
CToken token = GetToken();
if (token != ":")
{
PrependToken(token);
return;
}
if (!SupportsInheritance()) throw CCompileException(token, "Inheritance is not supported.");
// When an inheritance list is provided, the content should also be provided.
m_bRequiresContent = true;
CLog log("Processing inheritance list...");
// Get the list of base entities
while (true)
{
// Find the base entity.
std::pair<std::string, CEntityPtr> prBase = ProcessScopedName();
if (prBase.first.empty() || !prBase.second)
throw CCompileException("Base not found.");
log << "Inherited from base entity: " << prBase.first << std::endl;
if (prBase.second->GetResolvedEntity()->GetType() != GetType())
throw CCompileException("Cannot inherit from different types.");
// Check whether the base entity is more than only a declaration.
if (prBase.second->ForwardDeclaration())
throw CCompileException("Base type found, but only declared; definition is missing.");
// TODO: Check whether the entity was already previously inherited directly or indirectly. Inheriting through a base
// prevents inheriting again.
// Add the base entity to the base entity list.
m_vecInheritance.push_back(prBase.second);
// Get the next base entity or the beginning of the definition.
token = GetToken();
if (token != ",")
{
PrependToken(token);
break;
}
}
}
void CDefinitionEntity::CreateInheritanceValueChildNodes()
{
CLog log("Creating values for inherited child nodes...");
if (!ValueRef()) throw CCompileException("Internal error: cannot create inheritance value child nodes.");
// For each base entity, copy the value tree
for (CEntityPtr ptrInheritedEntity : m_vecInheritance)
{
// Check for a valid value of the base entity.
if (!ptrInheritedEntity->GetResolvedEntity()->ValueRef())
throw CCompileException("Internal error: base entity wasn't processed for assignment yet.");
log << "Assigning values from base entity '" << ptrInheritedEntity->GetName() << "'." << std::endl;
// Create a copy of the tree and add as child to own tree.
ValueRef()->AddChild(ptrInheritedEntity->GetResolvedEntity()->ValueRef()->CreateCopy(shared_from_this(), ValueRef()));
}
}
sdv::idl::IEntityIterator* CDefinitionEntity::GetChildren()
{
if (SupportsChildren()) return &m_iteratorChildren;
return nullptr;
}
sdv::idl::IEntityIterator* CDefinitionEntity::GetInheritance()
{
if (SupportsInheritance() && !m_vecInheritance.empty()) return &m_iteratorInheritance;
return nullptr;
}
void CDefinitionEntity::CalcHash(CHashObject& rHash) const
{
// First calc the hash of the base entity.
CEntity::CalcHash(rHash);
// Add the hashes of all inherited entities
for (const CEntityPtr& ptrEntity : m_vecInheritance)
ptrEntity->CalcHash(rHash);
// Add the declarations
for (const CEntityPtr& ptrEntity : m_lstDeclMembers)
ptrEntity->CalcHash(rHash);
// Add the attributes and operations
for (const CEntityPtr& ptrEntity : m_lstAttributesOperation)
ptrEntity->CalcHash(rHash);
}
const CEntityList CDefinitionEntity::GetDeclMembers() const
{
CEntityList lstMembers;
// Add all declarations from the inherited members
for (const CEntityPtr& rptrInheritedEntity : m_vecInheritance)
{
const CDefinitionEntity* pDefinition = rptrInheritedEntity->GetResolvedEntity()->Get<CDefinitionEntity>();
if (pDefinition)
{
CEntityList lstInheritedEntities = pDefinition->GetDeclMembers();
for (const CEntityPtr& ptrInheritedMember : lstInheritedEntities)
lstMembers.push_back(ptrInheritedMember);
}
}
// Add own declarations
for (const CEntityPtr& rptrMember : m_lstDeclMembers)
lstMembers.push_back(rptrMember);
return lstMembers;
}
void CDefinitionEntity::AddChild(CEntityPtr ptrChild)
{
CLog log;
// Call base class first
CEntity::AddChild(ptrChild);
// Dependable on the type of entity, add the entity to dedicated lists as well.
if (ptrChild->Get<CTypedefEntity>())
{
m_lstTypeMembers.push_back(ptrChild);
log << "Added typedef declaration to type member list..." << std::endl;
}
else if (ptrChild->Get<CAttributeEntity>())
{
m_lstAttributesOperation.push_back(ptrChild);
log << "Added attribute to definition list..." << std::endl;
} else if (ptrChild->Get<COperationEntity>())
{
m_lstAttributesOperation.push_back(ptrChild);
log << "Added operation to definition list..." << std::endl;
}
else if (ptrChild->Get<CDeclarationEntity>())
{
if (ptrChild->Get<CDeclarationEntity>()->IsReadOnly())
{
m_lstConstMembers.push_back(ptrChild);
log << "Added const declaration to const member list..." << std::endl;
}
else
{
m_lstDeclMembers.push_back(ptrChild);
log << "Added declaration to variable member list..." << std::endl;
}
}
else if (ptrChild->Get<CDefinitionEntity>())
{
m_lstTypeMembers.push_back(ptrChild);
log << "Added definition to type member list..." << std::endl;
}
else if (ptrChild->Get<CMetaEntity>())
{
GetRootEntity()->Get<CRootEntity>()->AddMeta(ptrChild);
log << "Added meta data to root based meta list..." << std::endl;
}
}
std::pair<CEntityPtr, bool> CDefinitionEntity::FindLocal(const std::string& rssName, bool bDeclaration) const
{
// Call base class implementation first.
std::pair<CEntityPtr, bool> prEntity = CEntity::FindLocal(rssName, bDeclaration);
if (prEntity.first) return prEntity;
// Check through all inherited entities
for (const CEntityPtr& rptrBaseEntity : m_vecInheritance)
{
if (!rptrBaseEntity) continue;
CEntityPtr ptrResolvedBaseEntity = rptrBaseEntity->GetResolvedEntity();
if (!ptrResolvedBaseEntity->Get<CDefinitionEntity>()) continue;
prEntity = ptrResolvedBaseEntity->Get<CDefinitionEntity>()->FindLocal(rssName, bDeclaration);
if (prEntity.first)
{
// Set the inherited flag
prEntity.second = true;
return prEntity;
}
}
// No entity found.
return std::make_pair(CEntityPtr(), false);
}

View File

@@ -0,0 +1,249 @@
#ifndef DEFINITION_ENTITY_H
#define DEFINITION_ENTITY_H
#include "entity_base.h"
/**
* @brief Support flags for the content of a definition (the part between the curly brackets '{...}').
*/
enum class EDefinitionSupport : uint32_t
{
support_variable, ///< Support variable declarations.
support_const_variable, ///< Support const variable declarations.
support_case_declaration, ///< Support case declarations.
support_enum_entry, ///< Support enumerator entry.
support_module, ///< Support module definitions.
support_typedef, ///< Support typedef declarations.
support_interface, ///< Support interface definitions.
support_struct, ///< Support struct definitions.
support_union, ///< Support union definitions.
support_enum, ///< Support enum definitions.
support_exception, ///< Support exception definitions.
support_attribute, ///< Support attribute declarations.
support_operation, ///< Support operation declarations.
};
/**
* @brief The base for definition entity definitions within an IDL file (struct, union, exception, interface, enum).
* @details The definition entity definitions all have a similar setup with small differences in detail. Consider the following
* structures:
* @code
* struct <name | anonymous> : <inheritance list> { <member list> }
* union <name | anonymous> switch(<type>) { <case member list> }
* interface <name> : <inheritance list> { <member list> }
* exception <name> { <member list> }
* enum <name> : <type> { <item list> }
* @endcode
* The following generalized structure applies to all complex structures:
* @code
* keyword name
* prefix keyword name postfix { definition }
* @endcode
* The first statement is a forward declaration. The second represents the type definition.
* The prefix is used to provide a specific interpretation to the definition.
* The keyword defines the type of definition (can be struct, union, interface, exception, enum).
* The name is the defined name of the definition. For types that allow anonymous names, this part is optionally.
* The postfix allows the specification of additional information needed for the definition (inheritynce list, switch list).
* The definition defines the content of the type.
* Some declarations might start as a type definition (e.g. struct, union, enum) followed with a declaration. For example:
* @code
* struct <def_name> { <definition> } <decl_name>
* struct { <definition> } <decl_name>
* @endcode
* In the first statement, the struct is defined and declared in one statement. In the second statement, an anonymous struct is
* defined and declared in one statement.
*/
class CDefinitionEntity : public CEntity, public sdv::idl::IDefinitionEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CDefinitionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
protected:
/**
* @brief Root entity constructor (name is 'root' and no parent).
* @param[in] rParser Reference to the parser.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
*/
CDefinitionEntity(CParser& rParser, const CContextPtr& rptrContext);
public:
/**
* @brief Destructor
*/
virtual ~CDefinitionEntity() override = default;
/**
* @brief Get access to another interface. Overload of IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Process the content of the definition.
* @details Process the content of the definition. This function parses through the content until a closing curly bracket
* has been detected. First the function checks for prefixes. Then the function determines whether the statement is a
* declaration or a definition. It then creates the corresponding entity and let the entity process itself.
*/
virtual void ProcessContent();
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Process the definition addendum.
* @details Process the definition addendum following the definition statement before the content definition. The default
* implementation checks for an inheritance list.
*/
virtual void ProcessDefinitionAddendum();
/**
* @brief Create a values for inherited child nodes.
*/
void CreateInheritanceValueChildNodes();
/**
* \brief Does the entity have an Unnamed definition. Overload of IDefinitionEntity::Unnamed.
* @return Returns 'true' when the definition supports unnamed definition; 'false' otherwise.
*/
virtual bool IsUnnamed() const override { return m_bAnonymousDefinition; };
/**
* @brief Request whether the definition supports the content. This function must be implemented by the derived entity.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const = 0;
/**
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
* @details Complex types support children per default.
* @return Returns whether the entity supports children (which is the case).
*/
virtual bool SupportsChildren() const override { return true; }
/**
* @brief Does the entity support inheritance?
* @details The default implementation is that inheritance is not supported.
* @return Returns whether the entity supports inheritance (which is not the case).
*/
virtual bool SupportsInheritance() const { return false; }
/**
* @brief Does the entity support anonymous naming?
* @details The default implementation is that anonymous naming is not supported.
* @return Returns whether the entity supports inheritance (which is not the case).
*/
virtual bool SupportsAnonymous() const { return false; }
/**
* @brief Does the complex entity support attributes in its content?
* @details The default implementation doesn't support attributes (they are specific to interfaces).
* @return Returns whether the entity supports attributes (which is not the case).
*/
virtual bool SupportContentAttributes() const { return false; }
/**
* @brief Does the complex entity support operations in its content?
* @details The default implementation doesn't support operations (they are specific to interfaces).
* @return Returns whether the entity supports operations (which is not the case).
*/
virtual bool SupportContentOperations() const { return false; }
/**
* @brief Does the definition entity require a content definition?
* @details In certain cases, it is required that the content definition is following the definition statement. For example,
* when an inheritance list is provided. The default implementation checks the m_bRequiresContent variable.
* @return Returns whether the content definition should be defined following the definition statement.
*/
virtual bool RequireContentDefinition() const { return m_bRequiresContent; }
/**
* @brief Does the definition require a declaration?
* @details In certain cases, it is required that the definition is followed by a declaration. For example,
* when the definition was made anonymously or when the definition is dependent on a variable within the same struct (e.g. with
* unions).
* @return Returns whether the definition requires a declaration.
*/
virtual bool RequireDeclaration() const { return IsUnnamed(); }
/**
* @brief Does the definition allow automatic transparent declaration if not present?
* @details When set an automatic transparent declaration is allowed without an explicit variable declaration. Currently this
* is only the case with unions with a variable based switch type.
* @return Returns whether the definition allows an automatic transparent declaration.
*/
virtual bool AllowAutoTransparentDeclaration() const { return false; }
/**
* @brief Get child entity iterator if children are available and supported by the definition. Overload of
* sdv::idl::IDefinitionEntity::GetChildren.
* @return Returns a pointer to the child entity iterator or NULL when not available.
*/
virtual sdv::idl::IEntityIterator* GetChildren() override;
/**
* @brief Get inheritance entity iterator if the definition was inheriting from other entities. Overload of
* sdv::idl::IDefinitionEntity::GetInheritance.
* @return Returns a pointer to the inheritance entity iterator or NULL when not available.
*/
virtual sdv::idl::IEntityIterator* GetInheritance() override;
/**
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
* @param[in, out] rHash Hash object to be filled with data.
*/
virtual void CalcHash(CHashObject& rHash) const override;
/**
* @brief Get the declaration members.
* @return List of declaration members.
*/
const CEntityList GetDeclMembers() const;
protected:
/**
* @brief Add the child to the children list. Called by CreateChild function. Overload of CEntity::AddChild.
* @param[in] ptrChild Pointer to the child entity to add.
*/
virtual void AddChild(CEntityPtr ptrChild) override;
/**
* @brief Find the entity locally by looking in the entity children map and the entity children maps of all the chained
* entities. The search is done case-insensitive. Overload of CEntity::FindLocal.
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
* the reuse of names between declarations and definitions.
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
* boolean that indicates that the entity was from an inherited entity.
*/
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
/**
* @brief Create the content value node. Overridable when supporting content values.
* @details When supporting value assignments, create the value node and assign the value node to the ValueRef() reference. For
* definitions that do not support value assignments, do nothing (default).
*/
virtual void CreateValueNode() {};
protected:
CEntityVector m_vecInheritance; ///< List of base entities in the order of appearance.
CEntityList m_lstTypeMembers; ///< List of typedef member declarations and type definitions.
CEntityList m_lstConstMembers; ///< List of const member declarations.
CEntityList m_lstDeclMembers; ///< List of variable member declarations.
CEntityList m_lstAttributesOperation; ///< List with attributes and operations.
bool m_bRequiresContent = false; ///< When set, the definition statement requires content to follow.
bool m_bAnonymousDefinition = false; ///< When set, the entity has an anonymous generated name.
CEntityIterator m_iteratorChildren; ///< Children iterator
CEntityIterator m_iteratorInheritance; ///< Inheritance iterator
};
#endif // !defined(DEFINITION_ENTITY_H)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,803 @@
#include "entity_value.h"
#include "../exception.h"
#include "variable_entity.h"
#include "definition_entity.h"
#include "../constvariant.inl"
#include "../support.h"
#include "../parser.h"
CEntityValueNode::CEntityValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
m_ptrEntity(ptrEntity), m_ptrParent(ptrParent)
{
if (!ptrEntity) throw CCompileException("Internal error: expected a valid entity.");
CLog log;
if (!ptrParent)
log << "The value node of '" << ptrEntity->GetName() << "' has no parent node..." << std::endl;
else
log << "The value node of '" << ptrEntity->GetName() << "' has a parent node..." << std::endl;
}
CEntityValueNode::CEntityValueNode(const CEntityValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
m_ptrEntity(ptrEntity), m_ptrParent(ptrParent), m_vecChildren(rValueNode.m_vecChildren)
{
if (!ptrEntity) throw CCompileException("Internal error: expected a valid entity.");
CLog log;
if (!ptrParent)
log << "The value node of '" << ptrEntity->GetName() << "' has no parent node..." << std::endl;
else
log << "The value node of '" << ptrEntity->GetName() << "' has a parent node..." << std::endl;
}
void CEntityValueNode::ProcessChildNodes(const CTokenList& rlstExpression)
{
CLog log;
log << "Processing " << m_vecChildren.size() << " child nodes..." << std::endl;
bool bInitial = true;
for (CValueNodePtr& rptrValue : m_vecChildren)
{
// Check for a comma separator.
if (!bInitial)
{
if (rlstExpression.Current() != ",")
throw CCompileException(rlstExpression.LastValid(), "Missing comma ',' for value separation.");
++rlstExpression;
}
bInitial = false;
log << "Processing child node..." << std::endl;
rptrValue->ProcessValueAssignment(rlstExpression);
}
}
void CEntityValueNode::AddChild(CValueNodePtr ptrChild)
{
CLog log;
log << "Adding child node..." << std::endl;
if (!ptrChild)
throw CCompileException("Internal error: cannot add an empty child node.");
m_vecChildren.push_back(ptrChild);
}
std::string CEntityValueNode::GetDeclTypeStr(bool bResolveTypedef) const
{
return GetDeclEntity()->GetDeclTypeStr(bResolveTypedef);
}
bool CEntityValueNode::IsConst() const
{
// Default implementation
// - In case the entity is a const entity, return 'true'.
// - Otherwise check whether the parent value is available and ask the parent if the declaration entity is a const entity.
// - If no parent is available, this entity must be a declaration entity and is therefore not a const entity.
if (m_ptrEntity->Get<CVariableEntity>() && m_ptrEntity->Get<CVariableEntity>()->IsReadOnly()) return true;
if (m_ptrParent) return m_ptrParent->IsConst();
return false;
}
bool CEntityValueNode::IsDeclaration() const
{
// Default implementation
return m_ptrEntity->Get<CVariableEntity>();
}
CSimpleTypeValueNode::CSimpleTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(ptrEntity, ptrParent)
{}
CSimpleTypeValueNode::CSimpleTypeValueNode(const CSimpleTypeValueNode& rValueNode, CEntityPtr ptrEntity,
const CValueNodePtr ptrParent) :
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_varValue(rValueNode.m_varValue),
m_lstExpression(rValueNode.m_lstExpression), m_eValueDef(rValueNode.m_eValueDef)
{}
CValueNodePtr CSimpleTypeValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
{
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
}
void CSimpleTypeValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
{
CLog log("Processing declaration value assignment...");
if (!m_ptrEntity) throw CCompileException("Internal error: no entity assigned to the value node.");
const CDeclarationEntity* pSystemTypeEntity = m_ptrEntity->Get<CDeclarationEntity>();
if (!pSystemTypeEntity)
throw CCompileException("Internal error: type mismatch between value node and entity type.");
// Process the assignment expression and convert the result in the target type.
std::pair<CConstVariant, bool> prValue{0, false};
switch (pSystemTypeEntity->GetBaseType())
{
case sdv::idl::EDeclType::decltype_short:
log << "Processing system type value node of type 'int16/short'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<int16_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_long:
log << "Processing system type value node of type 'int32/long'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<int32_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_long_long:
log << "Processing system type value node of type 'int64/long long'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<int64_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_unsigned_short:
log << "Processing system type value node of type 'uint16/unsigned short'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint16_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_unsigned_long:
log << "Processing system type value node of type 'uint32/unsigned long'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint32_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_unsigned_long_long:
log << "Processing system type value node of type 'uint64/unsigned long long'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint64_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_char:
log << "Processing system type value node of type 'int8/UTF-8 or ASCII char'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<int8_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<int64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_char16:
log << "Processing system type value node of type 'UTF-16 char'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint16_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_char32:
log << "Processing system type value node of type 'UTF-32 char'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint32_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_wchar:
log << "Processing system type value node of type 'wchar'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
if (sizeof(wchar_t) == 2)
prValue.first.Convert<uint16_t>();
else
prValue.first.Convert<uint32_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_float:
log << "Processing system type value node of type 'float'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<float>();
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_double:
log << "Processing system type value node of type 'double'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<double>();
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_long_double:
log << "Processing system type value node of type 'long double'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<long double>();
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_fixed:
log << "Processing system type value node of type 'fixed'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<fixed>();
log << "Simple type value node has calculated value " << prValue.first.Get<long double>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_boolean:
log << "Processing system type value node of type 'boolean'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<bool>();
log << "Simple type value node has calculated value " << (prValue.first.Get<bool>() ? "'true'" : "'false'") << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_native:
log << "Processing system type value node of type 'native'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<size_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<size_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_octet:
log << "Processing system type value node of type 'uint8/octet'..." << std::endl;
prValue = pSystemTypeEntity->ProcessNumericExpression(rlstExpression);
prValue.first.Convert<uint8_t>();
log << "Simple type value node has calculated value " << prValue.first.Get<uint64_t>() << "..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_string:
log << "Processing system type value node of type 'ASCII string'..." << std::endl;
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
prValue.first.Convert<std::string>();
log << "Simple type value node has constructed string \"" << prValue.first.Get<std::string>() << "\"..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_u8string:
log << "Processing system type value node of type 'UTF-8 string'..." << std::endl;
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
prValue.first.Convert<std::string>();
log << "Simple type value node has constructed string \"" << prValue.first.Get<std::string>() << "\"..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_u16string:
log << "Processing system type value node of type 'UTF-16 string'..." << std::endl;
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
prValue.first.Convert<std::u16string>();
log << "Simple type value node has constructed string..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_u32string:
log << "Processing system type value node of type 'UTF-32 string'..." << std::endl;
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
prValue.first.Convert<std::u32string>();
log << "Simple type value node has constructed string..." << std::endl;
break;
case sdv::idl::EDeclType::decltype_wstring:
log << "Processing system type value node of type 'wstring'..." << std::endl;
prValue = pSystemTypeEntity->ProcessStringExpression(rlstExpression);
prValue.first.Convert<std::wstring>();
log << "Simple type value node has constructed string..." << std::endl;
break;
default:
log << "Processing system type value node of unknown type..." << std::endl;
throw CCompileException("Internal error: expression build error.");
}
// Check for a dynamic result
if (prValue.second)
SetDynamicValue(rlstExpression);
else
SetFixedValue(prValue.first, rlstExpression);
}
void CSimpleTypeValueNode::SetFixedValue(const CConstVariant& rvarValue, const CTokenList& rlstExpression)
{
CLog log;
switch (m_eValueDef)
{
case EValueDef::dynamic:
log << "The value was re-assigned; the previous value was a dynamic value..." << std::endl;
break;
case EValueDef::fixed:
log << "The value was re-assigned; the previous value was a fixed value of " <<
m_varValue.GetAsString() << "..." << std::endl;
break;
default:
break;
}
m_eValueDef = EValueDef::fixed;
log << "The system type value node was set to a fixed value of " << rvarValue.GetAsString() << "..." << std::endl;
m_varValue = rvarValue;
m_lstExpression = rlstExpression;
}
void CSimpleTypeValueNode::SetDynamicValue(const CTokenList& rlstExpression)
{
CLog log;
switch (m_eValueDef)
{
case EValueDef::dynamic:
log << "The value was re-assigned; the previous value was a dynamic value..." << std::endl;
break;
case EValueDef::fixed:
log << "The value was re-assigned; the previous value was a fixed value of " <<
m_varValue.GetAsString() << "..." << std::endl;
break;
default:
break;
}
m_eValueDef = EValueDef::dynamic;
log << "The system type value node was set to a dynamic value..." << std::endl;
m_lstExpression = rlstExpression;
}
CArrayValueNode::CArrayValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(ptrEntity, ptrParent)
{}
CArrayValueNode::CArrayValueNode(const CArrayValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_lstArraySizeExpression(rValueNode.m_lstArraySizeExpression),
m_eSizeDef(rValueNode.m_eSizeDef)
{
m_vecChildren = rValueNode.m_vecChildren;
}
CValueNodePtr CArrayValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
{
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
}
void CArrayValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
{
CLog log("Process array value node...");
if (rlstExpression.End())
throw CCompileException(rlstExpression.LastValid(), "Expecting left curly bracket '{'");
// The array assignment is placed between brackets.
// In case the type is a character, the array might also be defined as a string literal
// Or identified as a value sequence.
if (rlstExpression.Current() == "{")
{
// Skip the bracket
++rlstExpression;
// Process the child nodes
ProcessChildNodes(rlstExpression);
// Expecting '}'
if (rlstExpression.End() || rlstExpression.Current() != "}")
throw CCompileException(rlstExpression.LastValid(), "Expecting right curly bracket '}'");
++rlstExpression;
}
else if (rlstExpression.Current().GetType() == ETokenType::token_literal && rlstExpression.Current().IsString())
{
// Process the string node
ProcessStringNode(rlstExpression.Current());
++rlstExpression;
}
else
throw CCompileException(rlstExpression.LastValid(), "Expecting left curly bracket '{'");
}
void CArrayValueNode::ProcessChildNodes(const CTokenList& rlstExpression)
{
CLog log;
CValueNodePtr ptrValueTemplateUnbound;
if (IsUnbound())
{
// The array should have one node. This is a template for all the nodes.
if (m_vecChildren.size() != 1)
throw CCompileException(rlstExpression.LastValid(), "Internal error: the size of the array value nodes is not as expected for the"
" unbound array.");
ptrValueTemplateUnbound = std::move(m_vecChildren[0]);
log << "Processing ubound element nodes..." << std::endl;
}
else
log << "Processing " << m_vecChildren.size() << " element nodes..." << std::endl;
size_t nIndex = 0;
while (!rlstExpression.End() && rlstExpression.Current() != "}")
{
// Check for a comma separator.
if (nIndex)
{
if (rlstExpression.Current() != ",")
throw CCompileException(rlstExpression.LastValid(), "Missing comma ',' for value separation.");
++rlstExpression;
}
// Extend the array for unbound
if (IsUnbound())
{
m_vecChildren.resize(nIndex + 1);
m_vecChildren[nIndex] = ptrValueTemplateUnbound->CreateCopy(m_ptrEntity, shared_from_this());
}
// Does the size fit?
if (nIndex >= m_vecChildren.size())
throw CCompileException(rlstExpression.LastValid(), "The assignment doesn't fit the amount of elements.");
log << "Processing element node #" << nIndex << std::endl;
m_vecChildren[nIndex]->ProcessValueAssignment(rlstExpression);
// Next node
nIndex++;
}
// Check whether the index corresponds to the size of the aray.
if (nIndex != m_vecChildren.size())
throw CCompileException(rlstExpression.LastValid(), "Missing elements for array assignment.");
}
void CArrayValueNode::ProcessStringNode(const CToken& rToken)
{
CLog log;
if (!rToken.IsString())
throw CCompileException(rToken, "Internal error: token is expected to be a string literal.");
// Check for unbound arrays.
CValueNodePtr ptrValueTemplateUnbound;
if (IsUnbound())
{
// The array should have one node. This is a template for all the nodes.
if (m_vecChildren.size() != 1)
throw CCompileException(rToken, "Internal error: the size of the array value nodes is not as expected for the"
" unbound array.");
ptrValueTemplateUnbound = std::move(m_vecChildren[0]);
log << "Processing ubound element nodes..." << std::endl;
}
else
log << "Processing " << m_vecChildren.size() << " element nodes..." << std::endl;
// Determine the start position of the string
const std::string ssValue = static_cast<std::string>(rToken);
size_t nStart = ssValue.find('"');
if (nStart == std::string::npos)
throw CCompileException(rToken, "Internal error: invalid string token.");
nStart++;
// For raw string, determine the delimiter
std::string ssDelimiter = "\"";
bool bRaw = false;
if (rToken.IsRawString())
{
bRaw = true;
size_t nStart2 = ssValue.find('(', nStart);
if (nStart2 == std::string::npos)
throw CCompileException(rToken, "Internal error: invalid raw string token.");
ssDelimiter = ")" + ssValue.substr(nStart, nStart2 - nStart) + "\"";
nStart = nStart2;
}
// Check whether the base type corresponds to the string and count the characters.
bool bError = true;
uint32_t uiByteCnt = 0;
std::vector<CConstVariant> lstValues;
switch (GetDeclEntity()->GetBaseType())
{
case sdv::idl::EDeclType::decltype_char:
{
if (!rToken.IsAscii() && !rToken.IsUtf8()) break;
bError = false;
std::string ssText;
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw, rToken.IsAscii());
for (char c : ssText)
lstValues.push_back(c);
break;
}
case sdv::idl::EDeclType::decltype_wchar:
{
if (!rToken.IsWide()) break;
bError = false;
std::wstring ssText;
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
for (wchar_t c : ssText)
lstValues.push_back(c);
break;
}
case sdv::idl::EDeclType::decltype_char16:
{
if (!rToken.IsUtf16()) break;
bError = false;
std::u16string ssText;
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
for (char16_t c : ssText)
lstValues.push_back(c);
break;
}
case sdv::idl::EDeclType::decltype_char32:
{
if (!rToken.IsUtf32()) break;
bError = false;
std::u32string ssText;
InterpretCText(ssValue.c_str() + nStart, ssDelimiter.c_str(), ssText, uiByteCnt, bRaw);
for (char32_t c : ssText)
lstValues.push_back(c);
break;
}
default:
throw CCompileException(rToken, "Expecting left curly bracket '{'");
break;
}
if (bError)
throw CCompileException(rToken, "Invalid string type for the assignment");
// Add the terminateing zero
lstValues.push_back(0);
// Extend the array for unbound
if (IsUnbound())
{
m_vecChildren.resize(lstValues.size());
for (size_t nIndex = 0; nIndex < lstValues.size(); nIndex++)
m_vecChildren[nIndex] = ptrValueTemplateUnbound->CreateCopy(m_ptrEntity, shared_from_this());
}
// Does the size fit?
if (lstValues.size() != m_vecChildren.size())
throw CCompileException(rToken, "The assignment doesn't fit the amount of elements.");
// Assign the values
for (size_t nIndex = 0; nIndex < m_vecChildren.size(); nIndex++)
{
log << "Processing element node #" << nIndex << std::endl;
CSimpleTypeValueNode* pValueNode = m_vecChildren[nIndex]->Get<CSimpleTypeValueNode>();
if (!pValueNode)
throw CCompileException(rToken, "Internal error: the array element is not of type simple value node.");
CTokenList lstExpression;
lstExpression.push_back(rToken);
pValueNode->SetFixedValue(lstValues[0], lstExpression);
}
}
void CArrayValueNode::SetFixedSize(size_t nSize, const CTokenList& rlstExpression)
{
CLog log;
if constexpr (std::is_signed_v<size_t>)
{
if (static_cast<int64_t>(nSize) < 0)
throw CCompileException("Internal error: array index is negative.");
}
if (m_eSizeDef != ESizeDef::not_defined)
throw CCompileException("Internal error: size of the value array was defined more than once.");
m_eSizeDef = ESizeDef::fixed;
// Allocate the array with empty value pointers.
m_vecChildren.resize(nSize);
log << "Array set to a fixed size of " << nSize << "..." << std::endl;
// Copy the token list resulting in the size.
m_lstArraySizeExpression = rlstExpression;
}
void CArrayValueNode::SetDynamicSize(size_t nSize, const CTokenList& rlstExpression)
{
if (IsConst()) throw CCompileException("Cannot use a value of a variable declaration as size within a const declaration.");
CLog log;
if (m_eSizeDef != ESizeDef::not_defined)
throw CCompileException("Internal error: size of the value array was defined more than once.");
m_eSizeDef = ESizeDef::dynamic;
// Allocate the array with one element.
m_vecChildren.resize(nSize);
log << "Array set to a dynamic size based on a variable of " << nSize << "..." << std::endl;
// Copy the token list resulting in the size.
m_lstArraySizeExpression = rlstExpression;
}
void CArrayValueNode::SetFixedSizeUnbound()
{
CLog log;
if (m_eSizeDef != ESizeDef::not_defined)
throw CCompileException("Internal error: size of the value array was defined more than once.");
m_eSizeDef = ESizeDef::fixed_unbound;
// Allocate the array with one element.
m_vecChildren.resize(1);
log << "Array set to be unbound..." << std::endl;
}
const CValueNodePtr& CArrayValueNode::operator[](size_t nIndex) const
{
if (m_eSizeDef == ESizeDef::not_defined)
throw CCompileException("Internal error: accessing the array can only take place after the size has been defined.");
if constexpr (std::is_signed_v<size_t>)
{
if (static_cast<int64_t>(nIndex) < 0)
throw CCompileException("Internal error: array index is negative.");
}
return m_vecChildren[nIndex];
}
CValueNodePtr& CArrayValueNode::operator[](size_t nIndex)
{
if (m_eSizeDef == ESizeDef::not_defined)
throw CCompileException("Internal error: accessing the array can only take place after the size has been defined.");
if constexpr (std::is_signed_v<size_t>)
{
if (static_cast<int64_t>(nIndex) < 0)
throw CCompileException("Internal error: array index is negative.");
}
return m_vecChildren[nIndex];
}
size_t CArrayValueNode::GetSize() const
{
return m_vecChildren.size();
}
bool CArrayValueNode::IsArray() const
{
return true;
}
bool CArrayValueNode::IsUnbound() const
{
return m_eSizeDef == ESizeDef::fixed_unbound;
}
std::string CArrayValueNode::GetSizeExpression() const
{
if (IsUnbound()) return std::string();
std::string ss;
for (const CToken& rtoken : m_lstArraySizeExpression)
ss += static_cast<std::string>(rtoken);
return ss;
}
std::string CArrayValueNode::GetDeclTypeStr(bool bResolveTypedef) const
{
if (!GetSize()) return "[]"; // Not resolved yet...
CValueNodePtr ptrValue = (*this)[0];
if (!ptrValue) return std::string("[" + std::to_string(GetSize()) + "]"); // Not resolved yet...
return ptrValue->GetDeclTypeStr(bResolveTypedef) + "[" + std::to_string(GetSize()) + "]";
}
CCompoundTypeValueNode::CCompoundTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(ptrEntity, ptrParent)
{}
CCompoundTypeValueNode::CCompoundTypeValueNode(const CCompoundTypeValueNode& rValueNode, CEntityPtr ptrEntity,
const CValueNodePtr ptrParent) : CEntityValueNode(rValueNode, ptrEntity, ptrParent)
{}
CValueNodePtr CCompoundTypeValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
{
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
}
void CCompoundTypeValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
{
CLog log("Processing struct value node...");
if (rlstExpression.End())
throw CCompileException(rlstExpression.LastValid(), "Missing assignment");
if (!m_ptrEntity)
throw CCompileException(rlstExpression.LastValid(), "Internal error: a value node should be assigned to an entity.");
// There are two options: either a scoped name representing a type (or typedef) being of the same type (identical name), or a
// compound value (between curly brackets '{...}').
if (rlstExpression.Current() != "{") // Type value assignment
{
CValueNodePtr ptrValue = m_ptrEntity->FindValue(rlstExpression);
// Check if the original type of the assginee and the assigned are identical. For this both entities must be declarations.
if (!GetDeclEntity()->Get<CDeclarationEntity>())
throw CCompileException(rlstExpression.LastValid(), "Internal error: the assignee entity must be a declaration entity.");
// Assignment can only work if the types are identical. This is regardless of the typedefs that have been made from the
// type.
if (GetDeclTypeStr(true) != ptrValue->GetDeclTypeStr(true))
throw CCompileException(rlstExpression.LastValid(), "For '", GetDeclEntity()->GetName(), "', cannot assign '",
ptrValue->GetDeclTypeStr(true), "' to '", ptrValue->GetDeclTypeStr(true), "'; base types are different.");
// Replace the value by the value chain of the assigned to the assignee.
m_ptrEntity->ValueRef() = ptrValue->CreateCopy(m_ptrEntity, m_ptrParent);
} else // Compound value assignment
{
++rlstExpression; // Skip left bracket
// Process the child nodes
ProcessChildNodes(rlstExpression);
// Expecting '}'
if (rlstExpression.End() || rlstExpression.Current() != "}")
throw CCompileException(rlstExpression.LastValid(), "Expecting right curly bracket '}'");
++rlstExpression; // Skip right bracket
}
}
CInterfaceValueNode::CInterfaceValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(ptrEntity, ptrParent)
{}
CInterfaceValueNode::CInterfaceValueNode(const CInterfaceValueNode& rValueNode, CEntityPtr ptrEntity,
const CValueNodePtr ptrParent) :
CEntityValueNode(rValueNode, ptrEntity, ptrParent)
{}
CValueNodePtr CInterfaceValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
{
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
}
void CInterfaceValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
{
CLog log("Processing declaration value assignment...");
if (!m_ptrEntity) throw CCompileException("Internal error: no entity assigned to the value node.");
const CDeclarationEntity* pSystemTypeEntity = m_ptrEntity->Get<CDeclarationEntity>();
if (!pSystemTypeEntity)
throw CCompileException("Internal error: type mismatch between value node and entity type.");
// Only "null" and "0" are allowed.
if ((!m_ptrEntity->GetParserRef().GetEnvironment().InterfaceTypeExtension() || rlstExpression.Current() != "null") &&
rlstExpression.Current() != "0")
throw CCompileException(rlstExpression.Current(),
"Error: assignment of interface values is only possible with the value \"null\".");
// Skip the value.
++rlstExpression;
}
CValueNodePtr CCompoundTypeValueNode::Member(const std::string& rssName) const
{
// Check the entity names of the child value nodes.
// ATTENTION: The child value nodes are copies of the original definition. They still contain the link to the declarations
// that were part of the definition. The entity belonging to a declaration of a compound type does not have any children (the
// entity itself is just the declaration and not the definition):
for (const CValueNodePtr& rptrValue : m_vecChildren)
if (rptrValue->GetDeclEntity()->GetName() == rssName) return rptrValue;
return nullptr; // Value not found.
}
CEnumValueNode::CEnumValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) :
CEntityValueNode(ptrEntity, ptrParent)
{}
CEnumValueNode::CEnumValueNode(const CEnumValueNode& rValueNode, CEntityPtr ptrEntity,
const CValueNodePtr ptrParent) :
CEntityValueNode(rValueNode, ptrEntity, ptrParent), m_ptrEntryVal(rValueNode.m_ptrEntryVal),
m_lstExpression(rValueNode.m_lstExpression)
{}
CValueNodePtr CEnumValueNode::CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const
{
return std::make_shared<std::decay_t<std::remove_pointer_t<decltype(this)>>>(*this, ptrEntity, ptrParent);
}
void CEnumValueNode::ProcessValueAssignment(const CTokenList& rlstExpression)
{
CLog log("Processing enum value assignment...");
// The assignment is done using the enum entry type. Find the scoped name. This could be the enum value. Check the type first.
CTokenList rlstExpressionTemp = rlstExpression;
std::pair<std::string, CEntityPtr> prEntity = GetDeclEntity()->GetTypeEntity()->ProcessScopedName(rlstExpression, true);
// If not an enum value from the type, use as scope the parent of the current enum to search for other declarations.
if (!prEntity.second) prEntity = GetDeclEntity()->GetParentEntity()->ProcessScopedName(rlstExpressionTemp, true);
if (!prEntity.second) throw CCompileException(rlstExpression.LastValid(), "Expecting an enum value.");
// This could either be an assignment of an enum to another enum or an enum entry to an enum.
log << "The to be assigned type is '" << prEntity.second->GetDeclTypeStr(true) << "'..." << std::endl;
log << "The assignee type is '" << GetDeclEntity()->GetDeclTypeStr(true) << "'..." << std::endl;
if (prEntity.second->GetDeclTypeStr(true) == GetDeclEntity()->GetDeclTypeStr(true))
{
if (!prEntity.second->ValueRef())
throw CCompileException(rlstExpression.LastValid(), "Internal error: the enum doesn't have an assigned value.");
if (!prEntity.second->ValueRef()->Get<CEnumValueNode>())
throw CCompileException(rlstExpression.LastValid(), "Internal error: the enum doesn't have an assigned enum value.");
m_ptrEntryVal = prEntity.second->ValueRef()->Get<CEnumValueNode>()->m_ptrEntryVal;
} else if (prEntity.second->GetParentEntity()->GetDeclTypeStr(true) == GetDeclEntity()->GetDeclTypeStr(true))
{
log << "Assigning enum entry..." << std::endl;
m_ptrEntryVal = prEntity.second;
} else
throw CCompileException(rlstExpression.LastValid(), "Invalid enum value; enum types are not identical.");
log << "Enum entity was assigned value '" << m_ptrEntryVal->GetParentEntity()->GetName() << "::" <<
m_ptrEntryVal->GetName() << "'..." << std::endl;
}
const CConstVariant& CEnumValueNode::Variant() const
{
static CConstVariant temp;
if (!m_ptrEntryVal) return temp;
if (!m_ptrEntryVal->ValueRef()) return temp;
const CSimpleTypeValueNode* pValueNode = m_ptrEntryVal->ValueRef()->Get<CSimpleTypeValueNode>();
if (!pValueNode) return temp;
return pValueNode->Variant();
}
std::string CEnumValueNode::String() const
{
if (!m_ptrEntryVal) return std::string();
return m_ptrEntryVal->GetParentEntity()->GetScopedName() + "::" + m_ptrEntryVal->GetName();
}

View File

@@ -0,0 +1,584 @@
#ifndef ENTITIY_VALUE_H
#define ENTITIY_VALUE_H
#include "entity_base.h"
#include "../constvariant.h"
#include "../token.h"
#include "../tokenlist.h"
#include <vector>
#include <memory>
// Forward declarations
class CDeclarationEntity;
/**
* @brief The entity value node base class.
* @details Entity values form a value tree made of all the values that are part of one assignment. Each value has its special
* value grammar when used in a assignment. All entities have their own personal linked list, which can be formed from other
* entities when they are defined as type of a declaration. Variable declarations can also be part of a larger linked list. Arrays
* form their own links within the linked list
* Examples:
* @code
* // Value tree for i: CSimpleTypeValueNode assigning the value 10.
* int32 i = 10;
*
* // Value tree for S1: CCompoundTypeValueNode with child CSimpleTypeValueNode assigning the value 20.
* struct S1
* {
* const int32 m_i1 = 10; // Value node for m_i1: CSimpleTypeValueNode assigning the value 10.
* int32 m_i2 = 20; // Part of the value tree of S1.
* };
*
* // Value tree for s1: sub-tree of S1 assigning the value 200 to m_i2.
* S1 s1 = {200};
*
* // Value tree for S2: CCompoundTypeValueNode with children sub-tree of S1 and CSimpleTypeValueNode assigning the value 5.
* struct S2 : S1
* {
* int32 m_i3 = 5; // Part of value tree of S2.
* };
*
* // Value tree for s2: sub-tree of S2 assigning the value 150 to S1 and 100 to m_i3.
* s2 = {{150}, 100};
*
* // Value tree for rgi: CArrayValueNode having two children assigning the value 10 and 20.
* int32 rgi[2] = {10, 20};
*
* // Value tree for rgs3: CarrayValueNode having two children S1 assigning the values 1000 and 2000.
* S1 rgs3[2] = {{1000}, {2000}};
* @endcode
*/
class CEntityValueNode : public std::enable_shared_from_this<CEntityValueNode>
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for const and declaration entities or when
* creating a value node for a definition which will be copied in a larger declaration at a later stage.
*/
CEntityValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CEntityValueNode(const CEntityValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CEntityValueNode() = default;
/**
* @brief Create a copy of the value. Prototype to be implemented from derived class.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const = 0;
/**
* @brief Process the assignment. Prototype, to be implemented by derived value class.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) = 0;
/**
* @brief Process the child nodes.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessChildNodes(const CTokenList& rlstExpression);
/**
* @{
* @brief Get the derived value class.
* @tparam TValue The value class to request a pointer for.
* @return Returns a pointer to the derived class or NULL when the requested class didn't derive from this value.
*/
template <class TValue>
TValue* Get();
template <class TValue>
const TValue* Get() const;
/**
* @}
*/
/**
* @brief Add a child node
* @param[in] ptrChild Pointer to the child value node.
*/
void AddChild(CValueNodePtr ptrChild);
/**
* @brief Get the parent node.
* @return Returns a reference to the smart pointer of the parent node (if assigned).
*/
const CValueNodePtr& GetParentNode() const { return m_ptrParent; }
/**
* @{
* @brief Get the attached declaration entity.
* @return Returns the smart pointer to the entity.
*/
const CDeclarationEntity* GetDeclEntity() const { return m_ptrEntity->Get<CDeclarationEntity>(); }
CDeclarationEntity* GetDeclEntity() { return m_ptrEntity->Get<CDeclarationEntity>(); }
/**
* @}
*/
/**
* @brief Get the declaration type build from the value chain.
* @details The declaration type consists of "<base type> <type identifier> <arrays>".
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with entity type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const;
/**
* @{
* @brief Information functions.
* @details Each function is implemented by an entity value class. The IsConst function traverses through the parents to find
* out whether or not a value is a const value (this is the case when the entity holding the top most value is a const
* entity.)
* @return Returns the information.
*/
virtual bool IsArray() const { return false; }
virtual bool IsUnbound() const { return false; }
virtual bool IsConst() const;
virtual bool IsDeclaration() const;
virtual bool IsDynamic() const { return false; }
virtual bool IsLiteral() const { return false; }
virtual bool IsComplex() const { return false; }
virtual bool HasParent() const{ return m_ptrParent ? true : false; }
virtual bool HasChildren() const{ return !m_vecChildren.empty(); }
/**
* @}
*/
protected:
CEntityPtr m_ptrEntity; ///< The entity implementing the value type.
const CValueNodePtr m_ptrParent; ///< Parent value node - can be nullptr for root node.
std::vector<CValueNodePtr> m_vecChildren; ///< Child nodes.
};
/**
* @brief Entity declaration value (used as const variable assignment as well as default declaration assignment).
*/
class CSimpleTypeValueNode : public CEntityValueNode
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
*/
CSimpleTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CSimpleTypeValueNode(const CSimpleTypeValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CSimpleTypeValueNode() override = default;
/**
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
/**
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
/**
* @brief Set to a fixed value.
* @remarks In case the entity is not a const entity, the value is considered to be a default value.
* @param[in] rvarValue Reference to the fixed value.
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
*/
void SetFixedValue(const CConstVariant& rvarValue, const CTokenList& rlstExpression);
/**
* @brief Set to a dynamic value
* @remarks This function can only be called when the entity of any of the parent entities is not a const entity.
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
*/
void SetDynamicValue(const CTokenList& rlstExpression);
/**
* @brief Is the value defined?
* @return Returns 'true' when the value is defined; 'false' otherwise.
*/
virtual bool IsDefined() const { return m_eValueDef != EValueDef::not_defined; }
/**
* @brief Is this value dynamic (will it be defined through a non-const variable definition)?
* @return Returns 'true' when the value is dynamic; 'false' otherwise.
*/
virtual bool IsDynamic() const override { return m_eValueDef != EValueDef::dynamic; }
/**
* @brief Get access to the underlying const variant.
* @return The const variant storing the calculated value.
*/
const CConstVariant &Variant() const { return m_varValue; }
private:
/**
* @brief The definition of the size is either fixed or not fixed. When it is fixed, it could be derived from assigning its
* values.
*/
enum class EValueDef
{
not_defined, ///< Currently not defined yet.
fixed, ///< The value is fixed; could be used for const and declaration entities.
dynamic, ///< The value is dependable on a variable declaration. Only to be used with a declaration entity.
};
CConstVariant m_varValue; ///< The calculated value.
CTokenList m_lstExpression; ///< List of tokens holding the value expression.
EValueDef m_eValueDef = EValueDef::not_defined; ///< Dynamic value based on variables.
};
/**
* @brief Entity array value (containing an array of value pointers).
* @remarks When the array contains non-allocated value pointers, the array has been declared, but the values haven't been
* assigned.
*/
class CArrayValueNode : public CEntityValueNode
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CArrayValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CArrayValueNode(const CArrayValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CArrayValueNode() override = default;
/**
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
/**
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
/**
* @brief Process the child nodes. Overload of CEntityValueNode::ProcessChildNodes.
* @param[in] rlstExpression Reference to the expression token list.
*/
void ProcessChildNodes(const CTokenList& rlstExpression) override;
/**
* @brief Process the string nodes. This is an array processing function based on a string as character array.
* @param[in] rToken Reference to the string literal token.
*/
void ProcessStringNode(const CToken& rToken);
/**
* @brief Set the fixed size of the array when available during declaration.
* @attention Must not be called after the value has been set to dynamic or set to a delayed fixed size.
* @param[in] nSize The calculated size of the array.
* @param[in] rlstExpression Reference to the expression list used to calculate the value.
*/
void SetFixedSize(size_t nSize, const CTokenList& rlstExpression);
/**
* @brief Set the array to a dynamic size based on a variable declaration. This is only allowed for entities that are not
* declared as const entity (where all the parent values are not defined as const).
* @attention Must not be called after the value has been set to a fixed size (delayed or not).
* @param[in] nSize The calculated size of the array.
* @param[in] rlstExpression Reference to the expression list used to calculate the size.
*/
void SetDynamicSize(size_t nSize, const CTokenList& rlstExpression);
/**
* @brief Set the array to a fixed size through its value assignment. This is only allowed for entities that are declared as
* const entity (where one of the parents was defined as const).
* @attention Must not be called after the value has been set to a fixed size (not delayed) or a dynamic size.
*/
void SetFixedSizeUnbound();
/**
* @{
* @brief Element access of the array.
* @param[in] nIndex The index of the element. For dynamic arrays, only an index of 0 is allowed.
* @return Returns a reference to the element.
*/
const CValueNodePtr& operator[](size_t nIndex) const;
CValueNodePtr& operator[](size_t nIndex);
/**
* @}
*/
/**
* @brief Get the size of the array.
* @return The size of the array.
*/
size_t GetSize() const;
/**
* @brief This is an array entity.
* @return Returns 'true'.
*/
virtual bool IsArray() const override;
/**
* @brief Is the size of the array defined through the assignment?
* @return Returns 'true' when the size of the array has to be defined through the assignment.
*/
virtual bool IsUnbound() const override;
/**
* @brief Get the size expression.
* @return The size expression string.
*/
std::string GetSizeExpression() const;
/**
* @brief Get the declaration type build from the value chain. Overload of CEntityValueNode::GetDeclTypeStr.
* @details The declaration type consists of "<base type> <type identifier> <arrays>".
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with entity type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
private:
/**
* @brief The definition of the size is either fixed or not fixed. When it is fixed, it could be derived from assigning its
* values.
*/
enum class ESizeDef
{
not_defined, ///< Currently not defined yet.
fixed, ///< The size is fixed; could be used for const and declaration entities.
dynamic, ///< The size is dependable on a variable declaration. Only to be used with a declaration entity.
fixed_unbound, ///< The size is fixed, but gets defined during value assignment. Only to be used with a const
///< entity.
};
CTokenList m_lstArraySizeExpression; ///< List of tokens holding the array size expression.
ESizeDef m_eSizeDef = ESizeDef::not_defined; ///< The size definition.
};
/**
* @brief Entity struct value containing two arrays of value pointers, one array for the member const declarations and one array
* for the member variable declarations.
*/
class CCompoundTypeValueNode : public CEntityValueNode
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr when creating a value node for a definition
* which will be copied in a larger declaration at a later stage.
*/
CCompoundTypeValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CCompoundTypeValueNode(const CCompoundTypeValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CCompoundTypeValueNode() override = default;
/**
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
/**
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
/**
* @brief Return the value for the supplied member.
* @param[in] rssName Name Reference to the string object containing the name of the member.
* @return Returns the value node smart pointer of the requested member, or nullptr when member doesn't have a value or
* doesn't exist.
*/
CValueNodePtr Member(const std::string& rssName) const;
};
/**
* @brief Interface value node.
* @note The only assignable values of an interface are "null" and "0". No variable is allowed to be assigned and an interface
* cannot be const.
*/
class CInterfaceValueNode : public CEntityValueNode
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
*/
CInterfaceValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CInterfaceValueNode(const CInterfaceValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CInterfaceValueNode() override = default;
/**
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
/**
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
/**
* @brief Is this value dynamic (will it be defined through a non-const variable definition)? This is always the case.
* @return Returns 'true' when the value is dynamic; 'false' otherwise.
*/
virtual bool IsDynamic() const override { return true; }
};
/**
* @brief Enum entity declaration value.
*/
class CEnumValueNode : public CEntityValueNode
{
public:
/**
* @brief Constructor
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Can only be nullptr for upper most value level.
*/
CEnumValueNode(CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Copy constructor with new parent and entity.
* @param[in] rValueNode Reference to the value node to copy from.
* @param[in] ptrEntity Smart pointer to the entity implementing the type. Cannot be nullptr.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
*/
CEnumValueNode(const CEnumValueNode& rValueNode, CEntityPtr ptrEntity, const CValueNodePtr ptrParent);
/**
* @brief Default destructor
* @remarks This constructor needs to be virtual to allow derived classes to be destroyed correctly.
*
*/
virtual ~CEnumValueNode() override = default;
/**
* @brief Create a copy of the value. Overload of CEntityValueNode::CreateCopy.
* @param[in] ptrEntity Smart pointer to the entity receiving the copy of the value node.
* @param[in] ptrParent Smart pointer to the parent value. Cannot be nullptr.
* @return Returns a smart pointer of the copy of the value.
*/
virtual CValueNodePtr CreateCopy(CEntityPtr ptrEntity, const CValueNodePtr ptrParent) const override;
/**
* @brief Process the assignment. Overload of CEntityValueNode::ProcessValueAssignment.
* @param[in] rlstExpression Reference to the expression token list.
*/
virtual void ProcessValueAssignment(const CTokenList& rlstExpression) override;
/**
* @brief Is the value defined?
* @return Returns 'true' when the value is defined; 'false' otherwise.
*/
virtual bool IsDefined() const { return m_ptrEntryVal ? true : false; }
/**
* @brief Get access to the assigned const variant of the enum entry.
* @return The const variant storing the value.
*/
const CConstVariant& Variant() const;
/**
* @brief Get access to the assigned name string of the enum entry.
* @return The name string of the enum entry.
*/
std::string String() const;
private:
CEntityPtr m_ptrEntryVal; ///< The enum entry value when assigned.
CTokenList m_lstExpression; ///< List of tokens holding the value expression.
};
template <class TValue>
TValue* CEntityValueNode::Get()
{
return dynamic_cast<TValue*>(this);
}
template <class TValue>
const TValue* CEntityValueNode::Get() const
{
return dynamic_cast<const TValue*>(this);
}
#endif // !define(ENTITY_VALUE_H)

View File

@@ -0,0 +1,213 @@
#include "enum_entity.h"
#include "entity_value.h"
#include "typedef_entity.h"
#include "../exception.h"
#include <set>
CEnumEntry::CEnumEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDeclarationEntity(rptrContext, ptrParent)
{}
std::string CEnumEntry::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return GetScopedName();
}
void CEnumEntry::Process()
{
// Get the base type of the enum entity and insert it in front of the declaration.
const CEnumEntity* pEnumEntity = GetParentEntity()->Get<CEnumEntity>();
if (!pEnumEntity) throw CCompileException("Internal error: expected an enum entity as parent.");
CToken token(DeclTypeToString(pEnumEntity->GetEnumType()));
PrependToken(token);
// Process as if normal declaration
CDeclarationEntity::Process();
}
CEnumEntity::CEnumEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDefinitionEntity(rptrContext, ptrParent)
{
m_typedecl.SetBaseType(sdv::idl::EDeclType::decltype_long);
}
sdv::interface_t CEnumEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IEnumEntity>())
return static_cast<sdv::idl::IEnumEntity*>(this);
return CDefinitionEntity::GetInterface(idInterface);
}
std::string CEnumEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return std::string("enum ") + GetScopedName();
}
void CEnumEntity::GetBaseType(sdv::idl::EDeclType& reType, sdv::IInterfaceAccess*& rpType) const
{
reType = m_typedecl.GetBaseType();
rpType = m_typedecl.GetTypeDefinition();
}
void CEnumEntity::Process()
{
// The definition and declaration can be defined:
// enum <enum_identifier>; --> forward declaration
// enum <enum_identifier> {...}; --> enum definition
// <enum_identifier> <decl_identifier>; --> enum variable declaration
// <enum_identifier> <decl_identifier> = <enum_value>; --> enum variable declaration and assignment
// enum <enum_identifier> <decl_identifier>; --> enum variable declaration
// enum <enum_identifier> <decl_identifier> = <enum_value>; --> enum variable declaration and assignment
// enum <enum_identifier> {...} <decl_identifier>; --> enum definition and variable declaration
// enum <enum_identifier> {...} <decl_identifier> = <enum_value>; --> enum definition, variable declaration and assignment
// enum {...} <decl_identifier>; --> anonymous enum definition and variable declaration
// enum {...} <decl_identifier> = <enum_value>; --> anonymous enum definition, variable declaration and assignment
// const enum <enum_identifier> <decl_identifier> = <enum_value>;
// const <enum_identifier> <decl_identifier> = <enum_value>;
// const enum {...} <decl_identifier> = <enum_value>;
// typedef <enum_identifier> <type_identifier>;
// typedef enum <enum_identifier> {...} <type_identifier>;
// typedef <enum_identifier> <type_identifier>;
// typedef enum <enum_identifier> {...} <type_identifier>;
// typedef enum {...} <type_identifier>;
CDefinitionEntity::Process();
// If supported create the value node for the definition (this allows assignments of values to this entity).
CreateValueNode();
}
void CEnumEntity::ProcessDefinitionAddendum()
{
// Check for inheritance
CToken token = GetToken();
if (token != ":")
{
PrependToken(token);
return;
}
CLog log("Processing inheritance type...");
// Process the type
m_typedecl = ProcessType();
// The base type must be an integral type and not an enum.
if (!IsIntegralDeclType(m_typedecl.GetBaseType()) && m_typedecl.GetBaseType() != sdv::idl::EDeclType::decltype_enum)
throw CCompileException("Expecting an integral type to inherit from.");
}
void CEnumEntity::ProcessContent()
{
CLog log("Processing definition content...");
// An enum definition consists of one declaration statement with entries separated by a comma.
CToken token = PeekToken();
if (!token) return;
if (token == "}") return;
// Expecting an enum entry
CEntityPtr ptrEntry = CreateChild<CEnumEntry>(token.GetContext(), this);
if (!ptrEntry) throw CCompileException("Internal error: could not create enum entry.");
ptrEntry->Process();
// The entries should reside in the const members list
// Check the values and create values where none is declared.
// Separate between signed and unsigned.
int64_t iSignedNext = 0;
std::set<int64_t> setSigned;
uint64_t uiUnsignedNext = 0;
std::set<uint64_t> setUnsigned;
for (CEntityPtr ptrMember : m_lstConstMembers)
{
CEnumEntry* pEntry = ptrMember->Get<CEnumEntry>();
if (!pEntry) throw CCompileException("Internal error: expected only enum entries in an enumeration.");
// Do post processing
pEntry->PostProcess();
// Get the value from the entity; if one was assigned.
CSimpleTypeValueNode* pValue = pEntry->ValueRef() ? pEntry->ValueRef()->Get<CSimpleTypeValueNode>() : nullptr;
if (!pValue)
throw CCompileException("The value for '", ptrEntry->GetName(), "' must be a system type value.");
// Deal with signed and unsigned values
if (IsSignedDeclType(m_typedecl.GetBaseType()))
{
// Is a value assigned?
if (pValue->IsDefined())
{
// Check whether the value is already in use.
int64_t iValue = pValue->Variant().Get<int64_t>();
if (setSigned.find(iValue) != setSigned.end())
throw CCompileException("The value for '", ptrEntry->GetName(), "' is already defined for another entry.");
// Store the value
setSigned.insert(iValue);
iSignedNext = iValue + 1;
}
else
{
// Get the next available value
while (setSigned.find(iSignedNext) != setSigned.end())
iSignedNext++;
// Create a value assignment
CTokenList lstValueTokens;
lstValueTokens.push_back(CToken(std::to_string(iSignedNext), ETokenLiteralType::token_literal_dec_integer));
pValue->SetFixedValue(iSignedNext, lstValueTokens);
// Store the value
setSigned.insert(iSignedNext);
iSignedNext++;
}
}
else
{
// Is a value assigned?
if (pValue->IsDefined())
{
// Check whether the value is already in use.
uint64_t uiValue = pValue->Variant().Get<uint64_t>();
if (setUnsigned.find(uiValue) != setUnsigned.end())
throw CCompileException("The value for '", ptrEntry->GetName(), "' is already defined for another entry.");
// Store the value
setUnsigned.insert(uiValue);
uiUnsignedNext = uiValue + 1;
}
else
{
// Get the next available value
while (setUnsigned.find(uiUnsignedNext) != setUnsigned.end())
uiUnsignedNext++;
// Create a value assignment
CTokenList lstValueTokens;
lstValueTokens.push_back(CToken(std::to_string(uiUnsignedNext), ETokenLiteralType::token_literal_dec_integer));
pValue->SetFixedValue(uiUnsignedNext, lstValueTokens);
// Store the value
setUnsigned.insert(uiUnsignedNext);
iSignedNext++;
}
}
}
}
bool CEnumEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_enum_entry: return true;
default: return false;
}
}
void CEnumEntity::CreateValueNode()
{
// Create a simple type value node for this definition.
ValueRef() = std::make_shared<CEnumValueNode>(shared_from_this(), nullptr);
}

View File

@@ -0,0 +1,178 @@
#ifndef ENUM_ENTITY_H
#define ENUM_ENTITY_H
#include "definition_entity.h"
#include "declaration_entity.h"
#include "variable_entity.h"
/**
* @brief The enum entry declaration.
*/
class CEnumEntry : public CDeclarationEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CEnumEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~CEnumEntry() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns enum entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_enum_entry; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with enum type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Does the entity support assignments? Overload of CDeclarationEntity::SupportAssignments.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportAssignments() const override { return true; }
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override { return true; }
/**
* @brief Does the entity support multiple declarations on one line of code? Overload of
* CDeclarationEntity::SupportMultipleDeclarations.
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
*/
virtual bool SupportMultipleDeclarations() const override { return true; }
/**
* @brief Do not enforce next declaration after comma (enums do)? Overload of
* CDeclarationEntity::DoNotEnfoceNextDeclarationAfterComma.
* @return Returns 'true' when not enforcing the next declaration; 'false' otherwise.
*/
virtual bool DoNotEnfoceNextDeclarationAfterComma() const override { return true; }
};
/**
* @brief The enum definition of an IDL file.
* @details The enum section of the IDL file contains a list of enum value entries
*/
class CEnumEntity : public CDefinitionEntity, public sdv::idl::IEnumEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CEnumEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~CEnumEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns enum entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_enum; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with enum type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
/**
* @brief Get the enumerator base type. Overload of sdv::idl::IEnumEntity.
* @param[out] reType Reference to the declaration type. The type if EEntityType::type_unknown if not available.
* @param[out] rpType Reference to the interface pointer if the type is a complex type. Otherwise is NULL.
*/
virtual void GetBaseType(sdv::idl::EDeclType& reType, sdv::IInterfaceAccess*& rpType) const override;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Process the content of the definition.
*/
virtual void ProcessContent() override;
/**
* @brief Process the definition addendum (following the definition statement before the content definition).
*/
virtual void ProcessDefinitionAddendum() override;
/**
* @brief Get the enum type.
* @return Returns the underlying enum type.
*/
sdv::idl::EDeclType GetEnumType() const { return m_typedecl.GetBaseType(); }
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
/**
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
* @details The struct supports children.
* @return Returns whether the entity supports children (which is supported).
*/
virtual bool SupportsChildren() const override { return true; }
/**
* @brief Does the entity support anonymous naming?
* @details The default implementation is that anonymous naming is not supported.
* @return Returns whether the entity supports inheritance (which is supported).
*/
virtual bool SupportsAnonymous() const override { return true; }
/**
* @brief Does the entity support inheritance?
* @details The default implementation is that inheritance is not supported.
* @return Returns whether the entity supports inheritance (which is supported).
*/
virtual bool SupportsInheritance() const override { return true; }
/**
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
* @details Create the value node and assign the value node to the ValueRef() reference..
*/
virtual void CreateValueNode() override;
private:
CTypeDeclaration m_typedecl; ///< The base type of the enum.
};
#endif // !defined(ENUM_ENTITY_H)

View File

@@ -0,0 +1,40 @@
#include "exception_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include <iostream>
CExceptionEntity::CExceptionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CStructEntity(rptrContext, ptrParent)
{}
std::string CExceptionEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return std::string("exception ") + GetScopedName();
}
void CExceptionEntity::Process()
{
CStructEntity::Process();
}
bool CExceptionEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_variable: return true;
case EDefinitionSupport::support_const_variable: return true;
case EDefinitionSupport::support_typedef: return true;
case EDefinitionSupport::support_struct: return true;
case EDefinitionSupport::support_union: return true;
case EDefinitionSupport::support_enum: return true;
default: return false;
}
}
void CExceptionEntity::CreateValueNode()
{
// Create a compound type value node for this definition.
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
}

View File

@@ -0,0 +1,62 @@
#ifndef EXCEPTION_ENTITY_H
#define EXCEPTION_ENTITY_H
#include "definition_entity.h"
#include "struct_entity.h"
/**
* @brief The struct definition of an IDL file.
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
* and unions.
*/
class CExceptionEntity : public CStructEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CExceptionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~CExceptionEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return the exception entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_exception; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with exception type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
/**
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
* @details Create the value node and assign the value node to the ValueRef() reference..
*/
virtual void CreateValueNode() override;
};
#endif // !defined(EXCEPTION_ENTITY_H)

View File

@@ -0,0 +1,39 @@
#include "hash_calc.h"
CHashObject::CHashObject()
{
// Create a xxHash state
m_state = XXH64_createState();
/* Initialize state with selected seed */
XXH64_hash_t seed = 0; /* or any other value */
if (XXH64_reset(m_state, seed) == XXH_ERROR)
{
XXH64_freeState(m_state);
m_state = nullptr;
}
}
CHashObject::~CHashObject()
{
if (m_state) XXH64_freeState(m_state);
}
CHashObject& CHashObject::operator<<(const std::string& rssString)
{
if (!m_state) return *this;
if (rssString.empty()) return *this;
if (XXH64_update(m_state, rssString.c_str(), rssString.size()) == XXH_ERROR)
{
XXH64_freeState(m_state);
m_state = nullptr;
}
return *this;
}
uint64_t CHashObject::GetHash() const
{
if (!m_state) return 0;
XXH64_hash_t hash = XXH64_digest(m_state);
return hash;
}

View File

@@ -0,0 +1,52 @@
#ifndef HASH_CALC_H
#define HASH_CALC_H
#ifdef _MSC_VER
// Prevent warnings for XXHash during static code analysis.
#pragma warning(push)
#pragma warning(disable : 26812 26451)
#endif
#define XXH_INLINE_ALL
#include <xxhash.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <string>
/**
* @brief Calculate a hash value
*/
class CHashObject
{
public:
/**
* @brief Constructor
*/
CHashObject();
/**
* @brief Destructor
*/
~CHashObject();
/**
* @brief Shift operator adding a string to the hash.
* @param[in] rssString Reference to the string.
* @return
*/
CHashObject& operator<<(const std::string& rssString);
/**
* @brief Get the current hash value.
* @return The hash value.
*/
uint64_t GetHash() const;
private:
XXH64_state_t* m_state = nullptr; ///< Hash state
};
#endif // !defined(HASH_CALC_H)

View File

@@ -0,0 +1,85 @@
#include "interface_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include <iostream>
CInterfaceEntity::CInterfaceEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bIsLocal) :
CDefinitionEntity(rptrContext, ptrParent), m_bIsLocal(bIsLocal)
{}
sdv::interface_t CInterfaceEntity::GetInterface(sdv::interface_id idInterface)
{
// Expose interfaces
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::idl::IInterfaceEntity*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IInterfaceEntity>())
return static_cast<sdv::idl::IInterfaceEntity*>(this);
return CDefinitionEntity::GetInterface(idInterface);
}
std::string CInterfaceEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return std::string("interface ") + GetScopedName();
}
void CInterfaceEntity::Process()
{
// The definition and declaration can be defined:
// struct <struct_identifier>; --> forward declaration
// struct <struct_identifier> {...}; --> struct definition
// struct <struct_identifier> : <base_struct,...> {...}; --> struct definition with inheritance
// <struct_identifier> <decl_identifier>; --> struct variable declaration
// <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
// struct <struct_identifier> <decl_identifier>; --> struct variable declaration
// struct <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
// struct <struct_identifier> {...} <decl_identifier>; --> struct definition and variable declaration
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier>; --> struct definition with inheritance and variable declaration
// struct <struct_identifier> {...} <decl_identifier> = {...}; --> struct definition, variable declaration and assignment
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier> = {...}; --> struct definition with inheritance, variable declaration and assignment
// struct {...} <decl_identifier>; --> anonymous struct definition and variable declaration
// struct : <base_struct,...> {...} <decl_identifier>; --> anonymous struct definition with inheritance and variable declaration
// struct {...} <decl_identifier> = {...}; --> anonymous struct definition, variable declaration and assignment
// struct : <base_struct,...> {...} <decl_identifier> = {...}; --> anonymous struct definition with inheritance, variable declaration and assignment
// typedef <struct_identifier> <type_identifier>;
// typedef struct <struct_identifier> { ... } <type_identifier>;
// typedef <struct_identifier> <type_identifier>;
// typedef struct <struct_identifier> { ... } <type_identifier>;
// typedef struct { ... } <type_identifier>;
// const struct <struct_identifier> <decl_identifier> = {...};
// const <struct_identifier> <decl_identifier> = {...};
// const struct {...} <decl_identifier> = {...};
// The declaration is as follows:
// <struct_identifier> <decl_identifier>;
// struct <struct_identifier> <decl_identifier>;
// struct <struct_identifier> { ... } <decl_identifier>;
// TODO Enforce inheritance from sdv::IInterfaceAccess unless the interface is sdv::IInterfaceAccess.
CDefinitionEntity::Process();
}
bool CInterfaceEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_const_variable: return true;
case EDefinitionSupport::support_typedef: return true;
case EDefinitionSupport::support_struct: return true;
case EDefinitionSupport::support_union: return true;
case EDefinitionSupport::support_enum: return true;
case EDefinitionSupport::support_attribute: return true;
case EDefinitionSupport::support_operation: return true;
default: return false;
}
}
void CInterfaceEntity::CreateValueNode()
{
// Create a compound type value node for this definition.
ValueRef() = std::make_shared<CInterfaceValueNode>(shared_from_this(), nullptr);
}

View File

@@ -0,0 +1,96 @@
#ifndef INTERFACE_ENTITY_H
#define INTERFACE_ENTITY_H
#include "definition_entity.h"
/**
* @brief The interface definition of an IDL file.
* @details The interface section of the IDL file contains multiple declarations of attributes and operations, as well as the
* definitions of enums, structs and unions.
*/
class CInterfaceEntity : public CDefinitionEntity, public sdv::idl::IInterfaceEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] bIsLocal When set, the interface is defined as a local interface not intended to be marshalled.
*/
CInterfaceEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bIsLocal);
/**
* @brief Destructor
*/
virtual ~CInterfaceEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Is this interface local? Overload of sdv::idl::IInterfaceEntity::IsLocal.
* @return Returns whether the interface is defined as local.
*/
virtual bool IsLocal() const override { return m_bIsLocal; }
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the interface entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_interface; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with interface type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
* @details Create the value node and assign the value node to the ValueRef() reference..
*/
virtual void CreateValueNode() override;
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
/**
* @brief Does the entity support inheritance? Overload of CDefinitionEntity::SupportsInheritance.
* @details Returns whether the entity supports inheritance.
* @return Returns whether inheritance is supported (which is the case).
*/
virtual bool SupportsInheritance() const override { return true; }
/**
* @brief Does the complex entity support attributes in its content? Overload of CDefinitionEntity::SupportContentAttributes.
* @details The default implementation doesn't support attributes (they are specific to interfaces).
* @return Returns whether the entity supports attributes (which is the case).
*/
virtual bool SupportContentAttributes() const override { return true; }
/**
* @brief Does the complex entity support operations in its content? Overload of CDefinitionEntity::SupportContentOperations.
* @details The default implementation doesn't support operations (they are specific to interfaces).
* @return Returns whether the entity supports operations (which is the case).
*/
virtual bool SupportContentOperations() const override { return true; }
private:
bool m_bIsLocal = false; ///< Flag indicating that the interface is local and not intended to be marshalled.
};
#endif // !defined(INTERFACE_ENTITY_H)

View File

@@ -0,0 +1,65 @@
#include "meta_entity.h"
CMetaEntity::CMetaEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CToken& rtokenMeta,
const CTokenList lstComments) :
CEntity(rptrContext, ptrParent)
{
std::string ssContent = rtokenMeta;
// Skip initial whitespace and store the content if not verbatim text.
size_t nSkip = 0;
if (rtokenMeta.GetMetaType() != ETokenMetaType::token_meta_verbatim)
{
while (nSkip < ssContent.size() && std::isspace(ssContent[nSkip]))
++nSkip;
}
m_ssContent = ssContent.substr(nSkip);
// Store the type
switch (rtokenMeta.GetMetaType())
{
case ETokenMetaType::token_meta_include_local:
m_eType = sdv::idl::IMetaEntity::EType::include_local;
break;
case ETokenMetaType::token_meta_include_global:
m_eType = sdv::idl::IMetaEntity::EType::include_global;
break;
case ETokenMetaType::token_meta_define:
m_eType = sdv::idl::IMetaEntity::EType::define;
break;
case ETokenMetaType::token_meta_undef:
m_eType = sdv::idl::IMetaEntity::EType::undef;
break;
case ETokenMetaType::token_meta_verbatim:
m_eType = sdv::idl::IMetaEntity::EType::verbatim;
break;
default:
throw CCompileException("Internal error: incomplete meta token received.");
break;
}
// Store comments
SetCommentTokens(lstComments, true);
// Set the position in the source file
SetBeginPosition(rtokenMeta.GetLine(), rtokenMeta.GetCol());
}
sdv::interface_t CMetaEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IMetaEntity>())
return static_cast<sdv::idl::IMetaEntity*>(this);
return CEntity::GetInterface(idInterface);
}
sdv::idl::IMetaEntity::EType CMetaEntity::GetMetaType() const
{
return m_eType;
}
sdv::u8string CMetaEntity::GetContent() const
{
return m_ssContent;
}

View File

@@ -0,0 +1,68 @@
#ifndef META_ENTITY_H
#define META_ENTITY_H
#include "entity_base.h"
/**
* @brief The meta data inserted into the code.
*/
class CMetaEntity : public CEntity, public sdv::idl::IMetaEntity
{
public:
/**
* @brief Constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] rtokenMeta The meta data content
* @param[in] lstComments Any preceding comments
*/
CMetaEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CToken& rtokenMeta,
const CTokenList lstComments);
/**
* @brief Destructor
*/
virtual ~CMetaEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the meta entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_meta; }
/**
* @brief Get the name of the entity. Overload of CEntity::GetName.
* @return The entity name.
*/
virtual sdv::u8string GetName() const override { return "meta"; }
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get the meta data type.
* @return Returns meta entity type.
*/
virtual sdv::idl::IMetaEntity::EType GetMetaType() const override;
/**
* @brief Get the meta data content.
* @return Returns a string object.
*/
virtual sdv::u8string GetContent() const override;
/**
* @brief Process the code. Since there is none... nothing to do. Overload of CEntity::Process.
*/
virtual void Process() override {};
private:
sdv::idl::IMetaEntity::EType m_eType; ///< Type of meta data
std::string m_ssContent; ///< The meta data string
};
#endif ///defined(META_ENTITY_H)

View File

@@ -0,0 +1,49 @@
#include "module_entity.h"
#include "typedef_entity.h"
#include "struct_entity.h"
#include "union_entity.h"
#include "interface_entity.h"
#include "exception_entity.h"
#include "../exception.h"
#include "../token.h"
CModuleEntity::CModuleEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDefinitionEntity(rptrContext, ptrParent)
{}
CModuleEntity::CModuleEntity(CParser& rParser, const CContextPtr& rptrContext) :
CDefinitionEntity(rParser, rptrContext)
{}
void CModuleEntity::Process()
{
CDefinitionEntity::Process();
}
bool CModuleEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_module: return true;
case EDefinitionSupport::support_const_variable: return true;
case EDefinitionSupport::support_typedef: return true;
case EDefinitionSupport::support_struct: return true;
case EDefinitionSupport::support_union: return true;
case EDefinitionSupport::support_enum: return true;
case EDefinitionSupport::support_interface: return true;
case EDefinitionSupport::support_exception: return true;
default: return false;
}
}
bool CModuleEntity::IsExtendable() const
{
// Allow extending the module.
return true;
}
bool CModuleEntity::SupportsChildren() const
{
// Allow the support of children.
return true;
}

View File

@@ -0,0 +1,86 @@
#ifndef MODULE_ENTITY_H
#define MODULE_ENTITY_H
#include "definition_entity.h"
#include <map>
#include "../constvariant.h"
/**
* @brief The module definition of an IDL file.
* @details The module section of the IDL file contains multiple definitions of nested modules, const definitions and type
* definitions.
*/
class CModuleEntity : public CDefinitionEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CModuleEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
protected:
/**
* @brief Root entity constructor (name is 'root' and no parent).
* @param[in] rParser Reference to the parser.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
*/
CModuleEntity(CParser& rParser, const CContextPtr& rptrContext);
public:
/**
* @brief Destructor
*/
virtual ~CModuleEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the module entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_module; }
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
// Suppress warning of cppcheck of a useless override. The function implementation improves readability.
// cppcheck-suppress uselessOverride
/**
* @brief Is this definition a root entity? Overload of CDefinitionEntity::IsRootEntity.
* @details The root entity is not expecting curly brackets '{...}'.
* @return Returns whether this is a root entity (which is not the case).
*/
virtual bool IsRootEntity() const override { return false; }
/**
* @brief Is the entity extendable? Overload of CEntity::IsExtendable.
* @details Allow extendability of the module entity.
* @return Returns whether the entity is extendable.
*/
virtual bool IsExtendable() const override;
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Does the entity support children? Overload of CEntity::SupportsChildren.
* @details The module supports children.
* @return Return whether the entity support children.
*/
virtual bool SupportsChildren() const override;
private:
};
#endif // !defined(MODULE_ENTITY_H)

View File

@@ -0,0 +1,47 @@
#include "operation_entity.h"
#include "interface_entity.h"
COperationEntity::COperationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDeclarationEntity(rptrContext, ptrParent), m_iteratorParameters(GetParamVector()),
m_iteratorExceptions(GetExceptionVector())
{}
sdv::interface_t COperationEntity::GetInterface(sdv::interface_id idInterface)
{
// Expose interfaces
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IOperationEntity>())
return static_cast<sdv::idl::IOperationEntity*>(this);
return CDeclarationEntity::GetInterface(idInterface);
}
sdv::idl::IEntityIterator* COperationEntity::GetParameters()
{
if (!GetParamVector().empty()) return &m_iteratorParameters;
return nullptr;
}
sdv::idl::IEntityIterator* COperationEntity::GetExceptions()
{
if (!GetExceptionVector().empty()) return &m_iteratorExceptions;
return nullptr;
}
std::pair<CEntityPtr, bool> COperationEntity::FindLocal(const std::string& rssName, bool /*bDeclaration*/) const
{
const CEntityVector& rvecParams = GetParamVector();
for (const CEntityPtr& rptrEntity : rvecParams)
{
if (rptrEntity->GetName() == rssName)
return std::make_pair(rptrEntity, false);
}
return std::make_pair(nullptr, false);
}
bool COperationEntity::RequiresAssignment() const
{
const CInterfaceEntity* pInterface = GetParentEntity() ? GetParentEntity()->Get<CInterfaceEntity>() : nullptr;
if (pInterface && pInterface->IsLocal()) return false;
return CDeclarationEntity::RequiresAssignment();
}

View File

@@ -0,0 +1,128 @@
#ifndef OPERATION_ENTITY_H
#define OPERATION_ENTITY_H
#include "declaration_entity.h"
/**
* @brief The operation definition of an IDL file.
* @details The operation section of the IDL file defines operations.
*/
class COperationEntity : public CDeclarationEntity, public sdv::idl::IOperationEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
COperationEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~COperationEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get parameter entity iterator if the definition has any parameters. Overload of
* sdv::idl::IOperationEntity::GetParameters.
* @return Returns a pointer to the parameter entity iterator or NULL when not available.
*/
virtual sdv::idl::IEntityIterator* GetParameters() override;
/**
* @brief Get the list of possible exceptions that might be fired for this operation. Overload of
* sdv::idl::IOperationEntity::GetExceptions.
* @return Interface pointer to the exception iterator.
*/
virtual sdv::idl::IEntityIterator* GetExceptions() override;
/**
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of IDeclarationEntity::IsReadOnly.
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
* 'true'.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override { return m_bOperationIsConst; }
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the operation type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_operation; }
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override { CDeclarationEntity::Process(); }
protected:
/**
* @brief Does the entity support raising exceptions? Overload of CDeclarationEntity::SupportRaiseExceptions.
* @return Returns 'true' when the entity defined as attribute; 'false' otherwise.
*/
virtual bool SupportRaiseExceptions() const override { return true; }
/**
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const override { return true; }
/**
* @brief Does the entity support an interface as base type? Overload of CDeclarationEntity::SupportVoid.
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
*/
virtual bool SupportInterface() const override { return true; }
/**
* @brief Does the entity support 'void' as base type? Overload of CDeclarationEntity::SupportVoid.
* @details Returns whether the entity supports the 'void' base type. Default value is 'false'.
* @return Returns 'true' when the entity supports void as base type; 'false' otherwise.
*/
virtual bool SupportVoid() const override { return true; }
/**
* @brief Does the entity support parameters? Overload of CDeclarationEntity::RequiresParameters.
* @details Returns whether the entity supports parameters. Default value is 'false'.
* @return Returns 'true' when the entity requires parameters; 'false' otherwise.
*/
virtual bool RequiresParameters() const override { return true; }
/**
* @brief Set operation as const. Overload of CDeclarationEntity::SetOperationAsConst.
*/
virtual void SetOperationAsConst() override { m_bOperationIsConst = true; }
/**
* @brief Find the entity locally by looking in the parameter list. Overload of CEntity::FindLocal.
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
* the reuse of names between declarations and definitions.
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
* boolean that indicates that the entity was from an inherited entity.
*/
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
/**
* @brief Does the entity require an assignment (const declarations do)? Overload of CDeclarationEntity::RequiresAssignment.
* @details Default processing is done by the declaration function (checking for unbound arrays). Exception: when the
* parent interface is defined as local, assignment is not required.
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
*/
virtual bool RequiresAssignment() const override;
private:
bool m_bOperationIsConst = false; ///< When set, the operation is defined as 'const' operation.
CEntityIterator m_iteratorParameters; ///< Parameters iterator
CEntityIterator m_iteratorExceptions; ///< Exceptions iterator
};
#endif // !defined(OPERATION_ENTITY_H)

View File

@@ -0,0 +1,66 @@
#include "parameter_entity.h"
#include "interface_entity.h"
#include "operation_entity.h"
#include "../exception.h"
CParameterEntity::CParameterEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
const CTokenList& rlstTokenList, bool bEnforceDirection /*= true*/) :
CDeclarationEntity(rptrContext, ptrParent, rlstTokenList), m_bEnforceDirection(bEnforceDirection)
{}
sdv::interface_t CParameterEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::idl::IParameterEntity>())
return static_cast<sdv::idl::IParameterEntity*>(this);
return CDeclarationEntity::GetInterface(idInterface);
}
void CParameterEntity::Process()
{
// Check for direction indicators.
CToken token = GetToken();
if (token == "in") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::input;
else if (token == "out") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::output;
else if (token == "inout") m_eDirection = sdv::idl::IParameterEntity::EParameterDirection::in_out;
else
{
PrependToken(token);
// Enforce the direction?
if (m_bEnforceDirection) throw CCompileException(token, "Missing direction indicator.");
}
// Let the basic type entity process further
CDeclarationEntity::Process();
}
bool CParameterEntity::RequiresAssignment() const
{
COperationEntity* pOperation = GetParentEntity() ? GetParentEntity()->Get<COperationEntity>() : nullptr;
const CInterfaceEntity* pInterface = pOperation && pOperation->GetParentEntity() ? pOperation->GetParentEntity()->Get<CInterfaceEntity>() : nullptr;
if (pInterface && pInterface->IsLocal()) return false;
return CDeclarationEntity::RequiresAssignment();
}
void CParameterEntity::CalcHash(CHashObject& rHash) const
{
// Call base class
CDeclarationEntity::CalcHash(rHash);
// Add the direction
switch (m_eDirection)
{
case sdv::idl::IParameterEntity::EParameterDirection::input:
rHash << "in";
break;
case sdv::idl::IParameterEntity::EParameterDirection::output:
rHash << "out";
break;
case sdv::idl::IParameterEntity::EParameterDirection::in_out:
rHash << "inout";
break;
default:
break;
}
}

View File

@@ -0,0 +1,92 @@
#ifndef PARAMETER_ENTITY_H
#define PARAMETER_ENTITY_H
#include "declaration_entity.h"
/**
* @brief The parameter definition of an operation and value type.
* @details The parameter section contains the definition of the parameter for operations and value types.
*/
class CParameterEntity : public CDeclarationEntity, public sdv::idl::IParameterEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
* @param[in] bEnforceDirection Enforce parameter direction.
*/
CParameterEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList,
bool bEnforceDirection = true);
/**
* @brief Destructor
*/
virtual ~CParameterEntity() override = default;
/**
* @brief Get access to another interface. Overload of IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the parameter type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_parameter; }
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const override { return true; }
/**
* @brief Does the entity support an interface as base type? Overload of CDeclarationEntity::SupportVoid.
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
*/
virtual bool SupportInterface() const override { return true; }
/**
* @brief Get the parameter direction. Overload of sdv::idl::IParameterEntity::GetDirection.
* @return Parameter direction.
*/
virtual sdv::idl::IParameterEntity::EParameterDirection GetDirection() const override { return m_eDirection; }
/**
* @brief Does the entity require an assignment (const declarations do)? Overload of CDeclarationEntity::RequiresAssignment.
* @details Default processing is done by the declaration function (checking for unbound arrays). Exception: when the
* parent interface is defined as local, assignment is not required.
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
*/
virtual bool RequiresAssignment() const override;
/**
* @brief Is the entity readonly (variable declarations and writable attributes aren't)? Overload of IDeclarationEntity::IsReadOnly.
* @details Returns whether the entity is readonly by design or whether it is defined readonly by the code. Default value is
* 'true'.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override { return false; }
/**
* @brief Calculate the hash of this entity and all encapsulated entities. Overload of CBaseEntity::CalcHash.
* @param[in, out] rHash Hash object to be filled with data.
*/
virtual void CalcHash(CHashObject& rHash) const override;
private:
bool m_bEnforceDirection; ///< When set, the parameter enforces the direction indicator when processing.
sdv::idl::IParameterEntity::EParameterDirection m_eDirection =
sdv::idl::IParameterEntity::EParameterDirection::unknown; ///< The direction type of the parameter.
};
#endif // !defined(PARAMETER_ENTITY_H)

View File

@@ -0,0 +1,30 @@
#include "root_entity.h"
#include "module_entity.h"
#include "../exception.h"
#include "../token.h"
CRootEntity::CRootEntity(CParser& rParser, const CContextPtr& rptrContext) :
CModuleEntity(rParser, rptrContext)
{}
void CRootEntity::Process()
{
// Skip the definition and process the content directly.
ProcessContent();
}
bool CRootEntity::IsExtendable() const
{
return false;
}
void CRootEntity::AddMeta(const CEntityPtr& ptrMeta)
{
m_lstMetaEntities.push_back(ptrMeta);
}
const CEntityList& CRootEntity::GetMeta() const
{
return m_lstMetaEntities;
}

View File

@@ -0,0 +1,57 @@
#ifndef ROOT_ENTITY_H
#define ROOT_ENTITY_H
#include "module_entity.h"
#include "meta_entity.h"
/**
* @brief The root definition of an IDL file.
* @details The root section of the IDL file contains multiple definitions of modules, constants and types.
*/
class CRootEntity : public CModuleEntity
{
public:
/**
* @brief Default constructor
* @param[in] rParser Reference to the parser used to parse the code.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
*/
CRootEntity(CParser& rParser, const CContextPtr& rptrContext);
/**
* @brief Process the code. Overload of CModuleEntity::Process.
*/
virtual void Process() override;
/**
* @brief Is this definition a root entity? Overload of CDefinitionEntity::IsRootEntity.
* @details The root entity is not expecting curly brackets '{...}'.
* @return Returns whether this entity is the root entity.
*/
virtual bool IsRootEntity() const override { return true; }
/**
* @brief Is the entity extendable? Overload of CEntity::IsExtendable.
* @details Prevents extending the root entity.
* @return Returns whether the entity is extendable.
*/
virtual bool IsExtendable() const override;
/**
* @brief Add meta data entity.
* @param[in] ptrMeta Shared pointer to the meta data entity.
*/
void AddMeta(const CEntityPtr& ptrMeta);
/**
* @brief Get the meta data entity list.
* @return Reference to the meta data entity list.
*/
const CEntityList& GetMeta() const;
private:
CEntityList m_lstMetaEntities; ///< List of meta entities.
};
#endif // !defined(ROOT_ENTITY_H)

View File

@@ -0,0 +1,71 @@
#include "struct_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include <iostream>
CStructEntity::CStructEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDefinitionEntity(rptrContext, ptrParent)
{}
std::string CStructEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return std::string("struct ") + GetScopedName();
}
void CStructEntity::Process()
{
// The definition and declaration can be defined:
// struct <struct_identifier>; --> forward declaration
// struct <struct_identifier> {...}; --> struct definition
// struct <struct_identifier> : <base_struct,...> {...}; --> struct definition with inheritance
// <struct_identifier> <decl_identifier>; --> struct variable declaration
// <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
// struct <struct_identifier> <decl_identifier>; --> struct variable declaration
// struct <struct_identifier> <decl_identifier> = {...}; --> struct variable declaration and assignment
// struct <struct_identifier> {...} <decl_identifier>; --> struct definition and variable declaration
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier>; --> struct definition with inheritance and variable declaration
// struct <struct_identifier> {...} <decl_identifier> = {...}; --> struct definition, variable declaration and assignment
// struct <struct_identifier> : <base_struct,...> {...} <decl_identifier> = {...}; --> struct definition with inheritance, variable declaration and assignment
// struct {...} <decl_identifier>; --> anonymous struct definition and variable declaration
// struct : <base_struct,...> {...} <decl_identifier>; --> anonymous struct definition with inheritance and variable declaration
// struct {...} <decl_identifier> = {...}; --> anonymous struct definition, variable declaration and assignment
// struct : <base_struct,...> {...} <decl_identifier> = {...}; --> anonymous struct definition with inheritance, variable declaration and assignment
// typedef <struct_identifier> <type_identifier>;
// typedef struct <struct_identifier> { ... } <type_identifier>;
// typedef <struct_identifier> <type_identifier>;
// typedef struct <struct_identifier> { ... } <type_identifier>;
// typedef struct { ... } <type_identifier>;
// const struct <struct_identifier> <decl_identifier> = {...};
// const <struct_identifier> <decl_identifier> = {...};
// const struct {...} <decl_identifier> = {...};
// The declaration is as follows:
// <struct_identifier> <decl_identifier>;
// struct <struct_identifier> <decl_identifier>;
// struct <struct_identifier> { ... } <decl_identifier>;
CDefinitionEntity::Process();
}
bool CStructEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_variable: return true;
case EDefinitionSupport::support_const_variable: return true;
case EDefinitionSupport::support_typedef: return true;
case EDefinitionSupport::support_struct: return true;
case EDefinitionSupport::support_union: return true;
case EDefinitionSupport::support_enum: return true;
default: return false;
}
}
void CStructEntity::CreateValueNode()
{
// Create a compound type value node for this definition.
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
}

View File

@@ -0,0 +1,75 @@
#ifndef STRUCT_ENTITY_H
#define STRUCT_ENTITY_H
#include "definition_entity.h"
/**
* @brief The struct definition of an IDL file.
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
* and unions.
*/
class CStructEntity : public CDefinitionEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CStructEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~CStructEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the struct type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_struct; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with struct type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
/**
* @brief Does the entity support inheritance? Overload of CDefinitionEntity::SupportsInheritance.
* @return Returns whether the entity supports inheritance.
*/
virtual bool SupportsInheritance() const override { return true; }
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Does the entity declaration support anonymous naming? Overload of CDefinitionEntity::SupportsAnonymous.
* @remarks C11 supports anonymous structs. C++ not! Therefore, IDL does not support anonymous structs.
* @return Returns whether the entity supports inheritance.
*/
virtual bool SupportsAnonymous() const override { return false; }
/**
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
* @details Create the value node and assign the value node to the ValueRef() reference..
*/
virtual void CreateValueNode() override;
};
#endif // !defined(STRUCT_ENTITY_H)

View File

@@ -0,0 +1,44 @@
#include "typedef_entity.h"
#include "../exception.h"
CTypedefEntity::CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CDeclarationEntity(rptrContext, ptrParent)
{
}
CTypedefEntity::CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent,
const std::string& rssName) :
CDeclarationEntity(rptrContext, ptrParent)
{
if (rssName.empty()) throw CCompileException("Internal error: trying to create a named type entity without valid name.");
SetName(rssName, true, true);
}
std::string CTypedefEntity::GetDeclTypeStr(bool bResolveTypedef) const
{
// When not resolving the typedef, return the default implementation ("typedef <name>").
if (!bResolveTypedef) return std::string("typedef ") + GetScopedName();
// Otherwise resolve the typedef by taking the base type.
if (GetTypeEntity())
return GetTypeEntity()->GetDeclTypeStr(bResolveTypedef);
else
return DeclTypeToString(GetBaseType());
}
void CTypedefEntity::Process()
{
CDeclarationEntity::Process();
}
std::pair<CEntityPtr, bool> CTypedefEntity::FindLocal(const std::string& rssName, bool bDeclaration) const
{
// Call the find local function on the original type.
if (!GetTypeEntity()) return std::pair<CEntityPtr, bool>();
return GetTypeEntity()->FindLocal(rssName, bDeclaration);
}

View File

@@ -0,0 +1,79 @@
#ifndef TYPEDEF_ENTITY_H
#define TYPEDEF_ENTITY_H
#include "declaration_entity.h"
/**
* @brief The const definition of an IDL file.
* @details The const section of the IDL file defines const values.
*/
class CTypedefEntity : public CDeclarationEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Constructor for a local named type entity without parsing.
* @attention This type entity is not attached as a child.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] rssName Reference to the name.
*/
CTypedefEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const std::string& rssName);
/**
* @brief Destructor
*/
virtual ~CTypedefEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return The typedef entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_typedef; }
/**
* @brief Get the qualified type of the entity. Overload of CEntity::GetDeclTypeStr.
* @attention To get the qualified type including array sizes, use the GetDeclTypeStr of the CEntityValueNode class.
* @details The qualified type consists of "<base type> <type identifier>".
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return String with the typedef entity type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const override { return true; }
/**
* @brief Does the entity require an assignment? Overload of CDeclarationEntity::RequiresAssignment.
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
*/
virtual bool RequiresAssignment() const override { return false; }
/**
* @brief Find the entity locally. Overload of CEntity::FindLocal.
* @param[in] rssName Reference to the string object containing the name of the entity to search for.
* @param[in] bDeclaration When set, the name belongs to a declaration; otherwise it belongs to a definition. Needed to allow
* the reuse of names between declarations and definitions.
* @return Returns a pair object containing an entity pointer if the entity exists or a NULL pointer if not as well as a
* boolean that indicates that the entity was from an inherited entity.
*/
virtual std::pair<CEntityPtr, bool> FindLocal(const std::string& rssName, bool bDeclaration) const override;
};
#endif // !defined(TYPEDEF_ENTITY_H)

View File

@@ -0,0 +1,434 @@
#include "union_entity.h"
#include "../exception.h"
#include "../logger.h"
#include "../parser.h"
#include "typedef_entity.h"
#include "variable_entity.h"
#include <iostream>
#include <set>
CCaseEntry::CCaseEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bDefault) :
CVariableEntity(rptrContext, ptrParent, false, false), m_bDefault(bDefault)
{}
std::string CCaseEntry::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return GetScopedName();
}
sdv::interface_t CCaseEntry::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::ICaseEntity>())
return static_cast<sdv::idl::ICaseEntity*>(this);
return CVariableEntity::GetInterface(idInterface);
}
sdv::u8string CCaseEntry::GetLabel() const
{
// The default case entry doesn#t have a label.
if (m_bDefault) return sdv::u8string();
// Get the label string from the value of the case label entity.
CVariableEntity* pLabelVariableEntity = m_ptrLabel->Get<CVariableEntity>();
if (!pLabelVariableEntity)
throw CCompileException("Internal error: expected a variable entity as case label.");
if (!pLabelVariableEntity->ValueRef())
throw CCompileException("Internal error: expected a value for the variable entity case label.");
// Enum value node?
const CEnumValueNode* pEnumValueNode = pLabelVariableEntity->ValueRef()->Get<CEnumValueNode>();
if (pEnumValueNode) return pEnumValueNode->String();
// Simple value node?
const CSimpleTypeValueNode* pSimpleTypeValueNode = pLabelVariableEntity->ValueRef()->Get<CSimpleTypeValueNode>();
if (pSimpleTypeValueNode) return pSimpleTypeValueNode->Variant().GetAsString();
// Otherwise error...
throw CCompileException("Internal error: expected a value for the variable entity case label.");
}
const CToken& CCaseEntry::GetLabelToken() const
{
return m_tokenLabel;
}
void CCaseEntry::Process()
{
CLog log("Processing case label...");
// Peek for the label token (used for reporting parsing errors).
m_tokenLabel = PeekToken();
// Processing of the case label value is done in post processing since the switch type might not be known yet.
CToken token;
std::string ssCaseLabel;
while ((token = GetToken()) != ":")
{
if (!ssCaseLabel.empty())
ssCaseLabel += ' ';
ssCaseLabel += static_cast<std::string>(token);
m_lstCaseValue.push_back(token);
}
log << "Case label name '" << ssCaseLabel << "'" << std::endl;
// Only unnamed nested struct and union definitions are not allowed. Furthermore, anonymous structs and unions (without
// explicit declaration cannot be supported (also not part of the C++ standard). Varable based switch type unions are
// also not supported since the variable for the switch needs to be part of the parent switch case and thus needs a struct to
// hold it.
token = PeekToken();
if ((token == "struct" && (PeekToken(1) == "{" || PeekToken(2) == "{")) ||
(token == "union" && (PeekToken(1) == "switch" || PeekToken(2) == "switch")))
{
// Get the struct/union from the code
token = GetToken();
throw CCompileException(token, "Cannot make a definition inside an union.");
}
// Stop processing if the case doesn't have any declaration (is followed by another case or a closing curled bracket).
if (token == "case" || token == "}")
{
// Determine whether the comments are preceding the token (either on the same line or the line before).
CTokenList lstPreComments = GetPreCommentTokenList();
if (!lstPreComments.empty()) SetCommentTokens(lstPreComments);
// Assign any succeeding comments
ProcessPostCommentTokenList(token.GetLine());
// Insert a semi-colon to identify that the statement is finished.
CToken tokenSep(";", ETokenType::token_separator);
PrependToken(tokenSep);
SetName(GetParserRef().GenerateAnonymousEntityName("case"));
return;
}
// Now let the variable process the declaration
CVariableEntity::Process();
}
void CCaseEntry::PostProcess()
{
CLog log("Post processing case label...");
// Get the base type of the enum entity and insert it in front of the declaration.
CUnionEntity* pUnionEntity = GetParentEntity()->Get<CUnionEntity>();
if (!pUnionEntity) throw CCompileException("Internal error: expected an union entity as parent.");
// Separate between case statement and default
if (m_bDefault)
{
if (!m_lstCaseValue.empty())
throw CCompileException("Default case label cannot have a value.");
log << "Default case label" << std::endl;
} else
{
// Get the switch case type
sdv::idl::EDeclType eSwitchCaseType = sdv::idl::EDeclType::decltype_unknown;
CEntityPtr ptrSwitchCaseType;
CValueNodePtr ptrSwitchCaseValue;
pUnionEntity->GetSwitchCaseType(eSwitchCaseType, ptrSwitchCaseType, ptrSwitchCaseValue);
// Insert the switch type specific assignment to the token list
m_lstCaseValue.push_front(CToken("="));
m_lstCaseValue.push_front(CToken("label"));
if (!ptrSwitchCaseType)
{
switch (eSwitchCaseType)
{
case sdv::idl::EDeclType::decltype_short: m_lstCaseValue.push_front(CToken("short")); break;
case sdv::idl::EDeclType::decltype_long: m_lstCaseValue.push_front(CToken("long")); break;
case sdv::idl::EDeclType::decltype_long_long: m_lstCaseValue.push_front(CToken("long long")); break;
case sdv::idl::EDeclType::decltype_unsigned_short: m_lstCaseValue.push_front(CToken("unsigned short")); break;
case sdv::idl::EDeclType::decltype_unsigned_long: m_lstCaseValue.push_front(CToken("unsigned long")); break;
case sdv::idl::EDeclType::decltype_unsigned_long_long: m_lstCaseValue.push_front(CToken("unsigned long long")); break;
case sdv::idl::EDeclType::decltype_octet: m_lstCaseValue.push_front(CToken("octet")); break;
case sdv::idl::EDeclType::decltype_char: m_lstCaseValue.push_front(CToken("char")); break;
case sdv::idl::EDeclType::decltype_char16: m_lstCaseValue.push_front(CToken("char16")); break;
case sdv::idl::EDeclType::decltype_char32: m_lstCaseValue.push_front(CToken("char32")); break;
case sdv::idl::EDeclType::decltype_wchar: m_lstCaseValue.push_front(CToken("wchar")); break;
case sdv::idl::EDeclType::decltype_boolean: m_lstCaseValue.push_front(CToken("boolean")); break;
case sdv::idl::EDeclType::decltype_native: m_lstCaseValue.push_front(CToken("native")); break;
default: throw CCompileException(m_tokenLabel, "Internal error: invalid switch case data type.");
}
}
else
m_lstCaseValue.push_front(CToken(ptrSwitchCaseType->GetScopedName()));
m_lstCaseValue.push_back(CToken(";", ETokenType::token_separator));
// Create the label value.
m_ptrLabel = std::make_shared<CVariableEntity>(GetContext(), shared_from_this(), m_lstCaseValue, true, false);
// Process the label variable (this will resolve any assigned value and constant).
m_ptrLabel->Process();
CVariableEntity* pLabelVariableEntity = m_ptrLabel->Get<CVariableEntity>();
if (!pLabelVariableEntity)
throw CCompileException("Internal error: expected a variable entity as case label.");
pLabelVariableEntity->PostProcess();
log << "Case label is: " << GetLabel() << std::endl;
}
// Post process the assignment
CVariableEntity::PostProcess();
}
CUnionEntity::CUnionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent) :
CStructEntity(rptrContext, ptrParent)
{}
sdv::interface_t CUnionEntity::GetInterface(sdv::interface_id idInterface)
{
if (idInterface == sdv::GetInterfaceId<sdv::IInterfaceAccess>())
return static_cast<sdv::IInterfaceAccess*>(this);
if (idInterface == sdv::GetInterfaceId<sdv::idl::IUnionEntity>())
return static_cast<sdv::idl::IUnionEntity*>(this);
return CStructEntity::GetInterface(idInterface);
}
sdv::idl::IUnionEntity::ESwitchInterpret CUnionEntity::GetSwitchInterpretation() const
{
return m_eSwitchInterpret;
}
void CUnionEntity::GetSwitchType(/*out*/ sdv::idl::EDeclType& reType, /*out*/ sdv::IInterfaceAccess*& rpType) const
{
reType = m_typedeclSwitch.GetBaseType();
rpType = m_typedeclSwitch.GetTypeDefinition();
}
void CUnionEntity::GetSwitchVar(/*out*/ sdv::u8string& rssVarStr, /*out*/ sdv::IInterfaceAccess*& rpVarEntity,
/*out*/ sdv::IInterfaceAccess*& rpVarContainer) const
{
rssVarStr.clear();
rpVarEntity = nullptr;
rpVarContainer = nullptr;
if (m_eSwitchInterpret == sdv::idl::IUnionEntity::ESwitchInterpret::switch_type) return;
rssVarStr = m_ssValueNode;
rpVarEntity = m_ptrSwitchValueNode ? m_ptrSwitchValueNode->GetDeclEntity()->Get<sdv::IInterfaceAccess>() : nullptr;
rpVarContainer = m_ptrContainer ? m_ptrContainer->Get<sdv::IInterfaceAccess>() : nullptr;
}
std::string CUnionEntity::GetDeclTypeStr(bool /*bResolveTypedef*/) const
{
return std::string("union ") + GetScopedName();
}
void CUnionEntity::Process()
{
// The definition and declaration can be defined:
// union <union_identifier>; --> forward declaration
// union <union_identifier> switch(<type>) {...}; --> union definition with type
// struct { <type> <var>; union <union_identifier> switch(<var>) {...};}; --> union definition with varaiable
// <union_identifier> <decl_identifier>; --> union variable declaration
// <union_identifier> <decl_identifier> = {...}; --> union variable declaration and assignment
// union <union_identifier> <decl_identifier>; --> union variable declaration
// union <union_identifier> <decl_identifier> = {...}; --> union variable declaration and assignment
// union <union_identifier> {...} <decl_identifier>; --> union definition and variable declaration
// union <union_identifier> {...} <decl_identifier> = {...}; --> union definition, variable declaration and assignment
// union {...} <decl_identifier>; --> anonymous union definition and variable declaration
// union {...} <decl_identifier> = {...}; --> anonymous union definition, variable declaration and assignment
// typedef <union_identifier> <type_identifier>;
// typedef union <union_identifier> { ... } <type_identifier>;
// typedef <union_identifier> <type_identifier>;
// typedef union <union_identifier> { ... } <type_identifier>;
// typedef union { ... } <type_identifier>;
// const union <union_identifier> <decl_identifier> = {...};
// const <union_identifier> <decl_identifier> = {...};
// const union {...} <decl_identifier> = {...};
// The declaration is as follows:
// <union_identifier> <decl_identifier>;
// union <union_identifier> <decl_identifier>;
// union <union_identifier> { ... } <decl_identifier>;
CStructEntity::Process();
}
void CUnionEntity::ProcessDefinitionAddendum()
{
//unions are defined as :
//union <union_identifier> switch (<type>)-- > type is a integral or enum type or a typedef of this
//{
//case <value>: <type> <var_identifier> -- > case values need to be unique
// ...
//};
//struct
//{
// <type> <var>;
// union <union_identifier> switch (<var>)-- > var is an integral or enum value, which is part of the struct
// {
// case <value>: <type> <var_identifier> -- > case values need to be unique
// ...
// };
//};
if (PeekToken() == ";") return; // Forward declaration
CToken token = GetToken();
if (token != "switch") throw CCompileException(token, "Expecting a switch statement following the union identifier.");
token = GetToken();
if (token != "(") throw CCompileException(token, "Expecting a left bracket '('.");
size_t nIndex = 0;
while (true)
{
token = PeekToken(nIndex++);
if (!token || token == ")") break;
m_ssSwitchVar += static_cast<std::string>(token);
}
m_typedeclSwitch = ProcessType(true);
token = GetToken();
while (token && token != ")")
{
m_ssValueNode += static_cast<std::string>(token);
token = GetToken();
}
if (token != ")") throw CCompileException(token, "Expecting a right bracket ')'.");
// Was it possible to resolve the type for the switch case. If not, the switch case is a variable?
if (m_typedeclSwitch.GetBaseType() == sdv::idl::EDeclType::decltype_unknown)
m_eSwitchInterpret = sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable;
}
void CUnionEntity::PostProcess()
{
if (ForwardDeclaration()) return;
// Was the switch case type/variable found before? If not, check for a variable.
if (m_eSwitchInterpret == sdv::idl::IUnionEntity::ESwitchInterpret::switch_variable)
{
// Get the switch type object
CEntityPtr ptrSwitchVarBase = Find(m_typedeclSwitch.GetTypeString());
if (!ptrSwitchVarBase)
throw CCompileException(m_ssSwitchVar,
"The switch case must be determined by a predefined type or a member variable.");
// Proper relative name (without global scope)
std::string ssSwitchFullName = ptrSwitchVarBase->GetName() + m_ssValueNode;
m_ssValueNode = ssSwitchFullName;
// The type must be a variable type
CVariableEntity* pVarEntityBase = ptrSwitchVarBase->Get<CVariableEntity>();
if (!pVarEntityBase)
throw CCompileException(m_ssSwitchVar,
"The switch case is not determined by a member variable nor a predefined type.");
// The parent of the base is the common parent of both the switch var and the union.
m_ptrContainer = ptrSwitchVarBase->GetParentEntity();
if (!m_ptrContainer)
throw CCompileException(m_ssSwitchVar,
"The switch case variable and the union do not share a common parent.");
// Find the value node of the switch variable (in case it is a child some layers deep).
CValueNodePtr ptrSwitchValueNode;
if (!m_ssValueNode.empty())
m_ptrSwitchValueNode = pVarEntityBase->FindValue(m_ssValueNode);
else
m_ptrSwitchValueNode = pVarEntityBase->ValueRef();
if (!m_ptrSwitchValueNode)
throw CCompileException(m_ssSwitchVar, "Could not find the switch variable.");
// Change the variable type entity to a switch variable.
m_ptrSwitchValueNode->GetDeclEntity()->Get<CVariableEntity>()->UseAsSwitchVariable();
// Assign the type of the variable.
m_typedeclSwitch.SetTypeDefinitionEntityPtr(m_ptrSwitchValueNode->GetDeclEntity()->GetTypeEntity());
m_typedeclSwitch.SetBaseType(m_ptrSwitchValueNode->GetDeclEntity()->GetBaseType());
if (!IsIntegralDeclType(m_typedeclSwitch.GetBaseType()) &&
m_typedeclSwitch.GetBaseType() != sdv::idl::EDeclType::decltype_enum)
throw CCompileException(m_ssSwitchVar, "Expecting an integral or enum identifier type or variable.");
// Check whether one of the parents is a struct or a union and the variable is a struct member.
CEntityPtr ptrParent = GetParentEntity();
if (!ptrParent ||
((ptrParent->GetType() != sdv::idl::EEntityType::type_struct) &&
(ptrParent->GetType() != sdv::idl::EEntityType::type_exception)))
throw CCompileException(m_ssSwitchVar,
"The union needs to be part of a struct or an exception when used with a variable based switch case.");
while (ptrSwitchVarBase)
{
if (!ptrParent ||
((ptrParent->GetType() != sdv::idl::EEntityType::type_struct) &&
(ptrParent->GetType() != sdv::idl::EEntityType::type_exception)))
throw CCompileException(m_ssSwitchVar,
"The variable used in the switch case must be a member of the same or parent struct or exception the union "
"is declared in.");
if (ptrParent->GetType() == sdv::idl::EEntityType::type_struct &&
ptrParent == ptrSwitchVarBase->GetParentEntity())
break;
ptrParent = ptrParent->GetParentEntity();
}
}
// Post process all the case statements
std::set<std::string> setValues;
bool bDefaultFound = false;
for (CEntityPtr ptrEntity : m_lstDeclMembers)
{
CCaseEntry* pCaseEntry = ptrEntity->Get<CCaseEntry>();
if (!pCaseEntry) throw CCompileException("Internal error: unexpected entity stored at union.");
pCaseEntry->PostProcess();
// Differentiate between default and standard case label...
if (pCaseEntry->IsDefault())
{
if (bDefaultFound)
throw CCompileException(pCaseEntry->GetLabelToken(), "Duplicate default switch found.");
bDefaultFound = true;
} else
{
// Check for the existence of the label.
std::string ssLabel = pCaseEntry->GetLabel();
if (m_setValues.find(ssLabel) != m_setValues.end())
throw CCompileException(pCaseEntry->GetLabelToken(), "Duplicate switch case label found.");
m_setValues.insert(ssLabel);
}
}
// If supported create the value node for the definition (this allows assignments of values to this entity).
CreateValueNode();
}
bool CUnionEntity::Supports(EDefinitionSupport eSupport) const
{
switch (eSupport)
{
case EDefinitionSupport::support_case_declaration: return true;
case EDefinitionSupport::support_variable: return false;
case EDefinitionSupport::support_const_variable: return false;
case EDefinitionSupport::support_typedef: return false;
case EDefinitionSupport::support_struct: return false;
case EDefinitionSupport::support_union: return false;
case EDefinitionSupport::support_enum: return false;
default: return false;
}
}
void CUnionEntity::CreateValueNode()
{
// Create a compound type value node for this definition.
ValueRef() = std::make_shared<CCompoundTypeValueNode>(shared_from_this(), nullptr);
}
bool CUnionEntity::RequireDeclaration() const
{
// Require a declaration when unnamed union.
return !ForwardDeclaration() && IsUnnamed();
}
bool CUnionEntity::AllowAutoTransparentDeclaration() const
{
return !ForwardDeclaration() && IsUnnamed();
}
void CUnionEntity::GetSwitchCaseType(sdv::idl::EDeclType& reType, CEntityPtr& rptrType, CValueNodePtr& rptrValue)
{
reType = m_typedeclSwitch.GetBaseType();
rptrType = m_typedeclSwitch.GetTypeDefinitionEntityPtr();
if (m_ptrSwitchValueNode) rptrValue = m_ptrSwitchValueNode;
}

View File

@@ -0,0 +1,233 @@
#ifndef UNION_ENTITY_H
#define UNION_ENTITY_H
#include "definition_entity.h"
#include "struct_entity.h"
#include "variable_entity.h"
#include "entity_value.h"
#include <set>
/**
* @brief The enum entry declaration.
*/
class CCaseEntry : public CVariableEntity, public sdv::idl::ICaseEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] bDefault When set, the entry is the default case entry.
*/
CCaseEntry(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bDefault);
/**
* @brief Destructor
*/
virtual ~CCaseEntry() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Get the case label string. Overload of sdv::idl::ICaseEntity::GetLabel.
* @return The label string.
*/
virtual sdv::u8string GetLabel() const override;
/**
* @brief Is the case a default cae entry. Overload of sdv::idl::ICaseEntity::IsDefault.
* @return Returns whether this is the default case entry.
*/
virtual bool IsDefault() const override { return m_bDefault; }
/**
* @brief Get the label token (used for error reporting).
* @return Returns a reference to the variable containing the label token.
*/
const CToken& GetLabelToken() const;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the union entity type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_case_entry; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns a string with union type.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Post process the case entry.
*/
void PostProcess();
/**
* @brief The entity doesn't support assignments. Overload of CDeclarationEntity::SupportAssignments.
* @return Returns whether assignments are supported (which is not the case).
*/
virtual bool SupportAssignments() const override { return false; }
private:
bool m_bDefault = false; ///< When set, the case entry is the default case entry.
CToken m_tokenLabel; ///< Label token.
CEntityPtr m_ptrLabel; ///< The case label entity.
CTokenList m_lstCaseValue; ///< Case value token list parsed during post processing.
};
/**
* @brief The struct definition of an IDL file.
* @details The struct section of the IDL file contains multiple declarations of members, as well as the definitions of structs
* and unions.
*/
class CUnionEntity : public CStructEntity, public sdv::idl::IUnionEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
*/
CUnionEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent);
/**
* @brief Destructor
*/
virtual ~CUnionEntity() override = default;
/**
* @brief Get access to another interface. Overload of sdv::IInterfaceAccess::GetInterface.
* @param[in] idInterface The interface id to get access to.
* @return Returns a pointer to the interface or NULL when the interface is not supported.
*/
virtual sdv::interface_t GetInterface(sdv::interface_id idInterface) override;
/**
* @brief Return the switch interpretation. Overload of sdv::idl::IUnionEntity::GetSwitchInterpretation.
* @return The interpretation of the switch case of this union.
*/
virtual sdv::idl::IUnionEntity::ESwitchInterpret GetSwitchInterpretation() const override;
/**
* @brief Return type information for the switch case. If the switch case is type base, this is the type information
* that is used to select. If the switch case is variable based, this is the type of the variable. Overload of
* sdv::idl::IUnionEntity::GetSwitchType.
* @param[out] reType Reference to the declaration type (either enum or an integral type).
* @param[out] rpType Reference to the type entity if existing.
*/
virtual void GetSwitchType(/*out*/ sdv::idl::EDeclType& reType, /*out*/ sdv::IInterfaceAccess*& rpType) const;
/**
* @brief Get the switch variable information if the switch case is variable based. Will be empty/NULL when the switch
* case is type based. Overload of sdv::idl::IUnionEntity::GetSwitchVar.
* @param[out] rssVarStr Reference to the string receiving the exact scoped declaration name of the switch variable if
* the interpretation is variable based. The variable name uses the scope separator '::' to define the common parent
* definition and the member separator '.' to define the variable declaration as member from the common parent.
* @param[out] rpVarEntity Reference to the variable entity if the interpretation is variable based.
* @param[out] rpVarContainer Reference to the variable entity of the container of both the switch variable and the
* union.
*/
virtual void GetSwitchVar(/*out*/ sdv::u8string& rssVarStr, /*out*/ sdv::IInterfaceAccess*& rpVarEntity,
/*out*/ sdv::IInterfaceAccess*& rpVarContainer) const;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the union type.
*/
virtual sdv::idl::EEntityType GetType() const override { return sdv::idl::EEntityType::type_union; }
/**
* @brief Get the declaration type of the entity as string. Overload of CEntity::GetDeclTypeStr.
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns the declaration type string.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Process the definition addendum.
* @details Process the definition addendum following the definition statement before the content definition. The default
* implementation checks for an inheritance list.
*/
virtual void ProcessDefinitionAddendum() override;
/**
* @brief Postprocess the switch/case assignments.
*/
void PostProcess();
/**
* @brief Request whether the definition supports the content. Overload of CDefintionEntity::Supports.
* @param[in] eSupport The type of support that is requested.
* @return Returns 'true' when the definition supports the content; 'false' otherwise.
*/
virtual bool Supports(EDefinitionSupport eSupport) const override;
/**
* @brief Does the entity support anonymous naming?
* @details The default implementation is that anonymous naming is not supported.
* @details Returns whether the entity supports inheritance.
* @return Returns whether anonymous naming is supported.
*/
virtual bool SupportsAnonymous() const override { return true; }
/**
* @brief Create the content value node. Overload of CDefinitionEntity::CreateValueNode.
* @details Create the value node and assign the value node to the ValueRef() reference..
*/
virtual void CreateValueNode() override;
/**
* @brief Does the definition require a declaration? Overload of CDefinitionEntity::RequireDeclaration.
* @return Returns whether a declaration is required.
*/
virtual bool RequireDeclaration() const override;
/**
* @brief Does the definition allow automatic transparent declaration if not present? Overload of
* CDefinitionEntity::AllowAutoTransparentDeclaration.
* @details When set an automatic transparent declaration is allowed without an explicit variable declaration. Currently this
* is only the case with unions with a variable based switch type.
* @return Returns whether the definition allows an automatic transparent declaration.
*/
virtual bool AllowAutoTransparentDeclaration() const override;
/**
* @brief Get switch case type.
* @param[out] reType Reference to the base type of the switch variable.
* @param[out] rptrType Reference to the type definition of the switch variable. Can be null if the switch uses a basic type.
* @param[out] rptrValue Reference to the value node of the switch variable. Can be null if the switch is determined by a type.
*/
void GetSwitchCaseType(sdv::idl::EDeclType& reType, CEntityPtr& rptrType, CValueNodePtr& rptrValue);
private:
/// Switch case interpretation.
sdv::idl::IUnionEntity::ESwitchInterpret m_eSwitchInterpret = sdv::idl::IUnionEntity::ESwitchInterpret::switch_type;
std::string m_ssSwitchVar; ///< Switch name
CTypeDeclaration m_typedeclSwitch; ///< The identifier within the switch case.
std::string m_ssValueNode; ///< Value node of the variable. If not existing the switch could either be
///< a type or a variable entity.
CEntityPtr m_ptrContainer; ///< The common container of both the switch variable and the union if the
///< switch case is variable based.
std::set<std::string> m_setValues; ///< Case entry values.
CValueNodePtr m_ptrSwitchValueNode; ///< Value node of the switch entity of a variable based switch.
};
#endif // !defined(UNION_ENTITY_H)

View File

@@ -0,0 +1,31 @@
#include "variable_entity.h"
#include "typedef_entity.h"
#include "../exception.h"
CVariableEntity::CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bConst, bool bAnonymous) :
CDeclarationEntity(rptrContext, ptrParent), m_bConst(bConst), m_bAnonymous(bAnonymous)
{}
CVariableEntity::CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList,
bool bConst, bool bAnonymous) :
CDeclarationEntity(rptrContext, ptrParent, rlstTokenList), m_bConst(bConst), m_bAnonymous(bAnonymous)
{}
std::string CVariableEntity::GetDeclTypeStr(bool bResolveTypedef) const
{
if (GetTypeEntity())
return GetTypeEntity()->GetDeclTypeStr(bResolveTypedef);
else
return DeclTypeToString(GetBaseType());
}
void CVariableEntity::Process()
{
CDeclarationEntity::Process();
// TODO: Const variables cannot contain:
// - dynamic arrays when no assignment is there
// - interfaces
// - structure or unions with unassigned dynamic arrays or interfaces
}

View File

@@ -0,0 +1,135 @@
#ifndef DECLARATOR_ENTITY_H
#define DECLARATOR_ENTITY_H
#include "declaration_entity.h"
/**
* @brief The variable declaration.
*/
class CVariableEntity : public CDeclarationEntity
{
public:
/**
* @brief Default constructor
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] bConst When set, the variable is defined as const.
* @param[in] bAnonymous When set, the variable is part of a struct and anonymous (unnamed and not declared) so its members are
* seen as members of the struct. For example, used with unions.
*/
CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, bool bConst, bool bAnonymous);
/**
* @brief Constructor using the provided token-list to process the code.
* @param[in] rptrContext Reference to the smart pointer holding the parse context. Must not be NULL.
* @param[in] ptrParent Pointer to the parent class holding this entity. This must not be NULL.
* @param[in] rlstTokenList Reference to the token list holding the tokens to process.
* @param[in] bConst When set, the variable is defined as const.
* @param[in] bAnonymous When set, the variable is part of a struct and anonymous (unnamed and not declared) so its members are
* seen as members of the struct. For example, used with unions.
*/
CVariableEntity(const CContextPtr& rptrContext, CEntityPtr ptrParent, const CTokenList& rlstTokenList, bool bConst,
bool bAnonymous);
/**
* @brief Destructor
*/
virtual ~CVariableEntity() override = default;
/**
* @brief Get the type of the entity. Overload of CEntity::GetType.
* @return Returns the entity type.
*/
virtual sdv::idl::EEntityType GetType() const override
{
return m_bPartOfSwitch ? sdv::idl::EEntityType::type_switch_variable : sdv::idl::EEntityType::type_variable;
}
/**
* @brief Get the qualified type of the entity. Overload of CEntity::GetDeclTypeStr.
* @attention To get the qualified type including array sizes, use the GetDeclTypeStr of the CEntityValueNode class.
* @details The qualified type consists of "<base type> <type identifier>".
* @param[in] bResolveTypedef When set, resolve the typedef type into the base type.
* @return Returns the type string.
*/
virtual std::string GetDeclTypeStr(bool bResolveTypedef) const override;
// Suppress cppcheck warning of a useless override. The function is here for better understanding.
// cppcheck-suppress uselessOverride
/**
* @brief Process the code. Overload of CEntity::Process.
*/
virtual void Process() override;
/**
* @brief Does the entity support assignments? Overload of CDeclarationEntity::SupportAssignments.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportAssignments() const override { return true; }
/**
* @brief Can the entity be used for assignments of complex types? Overload of
* CDeclarationEntity::CanSupportComplexTypeAssignments.
* @return Returns 'true' when the entity defined as declaration; 'false' otherwise.
*/
virtual bool CanSupportComplexTypeAssignments() const override { return true; }
/**
* @brief Does the entity support arrays? Overload of CDeclarationEntity::SupportArrays.
* @return Returns 'true' when the entity supports assignments; 'false' otherwise.
*/
virtual bool SupportArrays() const override { return true; }
/**
* @brief Is the entity readonly? Overload of IEntityInfo::IsReadOnly.
* @return Returns 'true' when the entity defined as readonly; 'false' otherwise.
*/
virtual bool IsReadOnly() const override { return m_bConst; }
/**
* @brief Does the entity require an assignment? Overload of CDeclarationEntity::RequiresAssignment.
* @return Returns 'true' when the entity requires an assignment; 'false' otherwise.
*/
virtual bool RequiresAssignment() const override { return m_bConst; }
/**
* @brief Does the entity support multiple declarations on one line of code? Overload of
* CDeclarationEntity::SupportMultipleDeclarations.
* @return Returns 'true' when the entity supports multiple declarations; 'false' otherwise.
*/
virtual bool SupportMultipleDeclarations() const override { return true; }
/**
* @brief Is the entity anonymous when used in a struct/union (unnamed and not declared)? Overload of
* IDeclarationEntity::IsAnonymous.
* @return Returns 'true' when the entity is anonymous; 'false' otherwise.
*/
virtual bool IsAnonymous() const override { return m_bAnonymous; }
/**
* @brief Enable the variable to be used in a union switch.
*/
void UseAsSwitchVariable() { m_bPartOfSwitch = true; }
protected:
/**
* @brief Set the variable as anonymous variable (unnamed and not declared).
*/
void SetAnonymous() { m_bAnonymous = true; }
/**
* @brief Does the entity support an interface as base type (non-const variables, operations and parameters do)?
* @details Returns whether the entity supports the an interface as base type base type. Default value is 'false'.
* @return Returns 'true' when the entity supports interfaces as base type; 'false' otherwise.
*/
virtual bool SupportInterface() const override { return !m_bConst; }
private:
bool m_bConst = false; ///< When set, the variable is defined as const.
bool m_bAnonymous = false; ///< When set, the variable declared anonymous (unnamed and not declared) so its members
///< are directly part of the parent struct.
bool m_bPartOfSwitch = false; ///< When set, the variable is used in a union switch.
};
#endif // !defined(DECLARATOR_ENTITY_H)