2026-03-27 14:12:49 +01:00
|
|
|
/********************************************************************************
|
|
|
|
|
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
|
|
|
|
*
|
|
|
|
|
* This program and the accompanying materials are made available under the
|
|
|
|
|
* terms of the Apache License Version 2.0 which is available at
|
|
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
|
|
|
|
* Contributors:
|
|
|
|
|
* Erik Verhoeven - initial API and implementation
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
2025-11-04 13:28:06 +01:00
|
|
|
#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;
|
|
|
|
|
}
|