mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-07-02 05:35:11 +00:00
499
sdv_executables/sdv_idl_compiler/generator/context.cpp
Normal file
499
sdv_executables/sdv_idl_compiler/generator/context.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
#include "context.h"
|
||||
#include "../exception.h"
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
CGenContext::CGenContext(sdv::IInterfaceAccess* pParser) : m_pParser(pParser)
|
||||
{
|
||||
if (!m_pParser) throw CCompileException("Internal error: no valid parser pointer supplied to generator.");
|
||||
m_pCompilerInfo = m_pParser->GetInterface<sdv::idl::ICompilerInfo>();
|
||||
if (!m_pCompilerInfo) throw CCompileException("Internal error: compiler info is not available.");
|
||||
m_pOption = m_pParser->GetInterface<sdv::idl::ICompilerOption>();
|
||||
if (!m_pOption) throw CCompileException("Internal error: cannot access options interface.");
|
||||
|
||||
}
|
||||
|
||||
CGenContext::~CGenContext()
|
||||
{}
|
||||
|
||||
std::filesystem::path CGenContext::GetSource() const
|
||||
{
|
||||
if (!m_pCompilerInfo) return std::filesystem::path();
|
||||
std::filesystem::path pathSource = static_cast<std::string>(m_pCompilerInfo->GetFilePath());
|
||||
if (pathSource.empty()) throw CCompileException("Internal error: file path is not available.");
|
||||
return pathSource;
|
||||
}
|
||||
|
||||
std::filesystem::path CGenContext::GetOutputDir() const
|
||||
{
|
||||
if (!m_pCompilerInfo) return std::filesystem::path();
|
||||
std::filesystem::path pathOutputDir = static_cast<std::string>(m_pCompilerInfo->GetOutputDir());
|
||||
if (pathOutputDir.empty())
|
||||
pathOutputDir = GetSource().parent_path();
|
||||
return pathOutputDir;
|
||||
}
|
||||
|
||||
std::string CGenContext::Header(const std::filesystem::path& rpathFile,
|
||||
const std::string& rssDescription /*= std::string()*/) const
|
||||
{
|
||||
std::stringstream sstream;
|
||||
|
||||
// Add file header
|
||||
sstream << "/**" << std::endl;
|
||||
sstream << " * @file " << rpathFile.filename().generic_u8string() << std::endl;
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
sstream << " * @date " << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X") << std::endl;
|
||||
sstream << " * This file was generated by the SDV IDL compiler from '" << GetSource().filename().generic_u8string() << "'" <<
|
||||
std::endl;
|
||||
if (!rssDescription.empty())
|
||||
{
|
||||
// Insert the JavaDoc marks before each line
|
||||
size_t nPos = 0;
|
||||
while (nPos < rssDescription.size())
|
||||
{
|
||||
size_t nEnd = rssDescription.find_first_of("\r\n", nPos);
|
||||
sstream << " * " << rssDescription.substr(nPos, nEnd == std::string::npos ? nEnd : nEnd - nPos) << std::endl;
|
||||
nPos = nEnd;
|
||||
if (nPos < rssDescription.size() && rssDescription[nPos] == '\r')
|
||||
nPos++;
|
||||
if (nPos < rssDescription.size() && rssDescription[nPos] == '\n')
|
||||
nPos++;
|
||||
}
|
||||
}
|
||||
sstream << " */" << std::endl;
|
||||
sstream << std::endl;
|
||||
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CGenContext::Safeguard(const std::filesystem::path& rpathFile, bool bInitial)
|
||||
{
|
||||
// Safeguards start with "__IDL_GENERATED__", add the file name, add the date and time and end with "__"
|
||||
std::stringstream sstreamSafeguard;
|
||||
sstreamSafeguard << "__IDL_GENERATED__";
|
||||
std::string ssFile = rpathFile.filename().generic_u8string();
|
||||
for (char c : ssFile)
|
||||
{
|
||||
if ((c < '0' || c > '9') &&
|
||||
(c < 'a' || c > 'z') &&
|
||||
(c < 'A' || c > 'Z'))
|
||||
sstreamSafeguard << '_';
|
||||
else
|
||||
sstreamSafeguard << static_cast<char>(std::toupper(c));
|
||||
}
|
||||
sstreamSafeguard << "__";
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
sstreamSafeguard << std::put_time(std::localtime(&in_time_t), "%Y%m%d_%H%M%S") << "_";
|
||||
sstreamSafeguard << std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() % 1000;
|
||||
|
||||
sstreamSafeguard << "__";
|
||||
// Return the safeguard code
|
||||
std::stringstream sstream;
|
||||
if (bInitial)
|
||||
sstream << "#ifndef " << sstreamSafeguard.str() << std::endl << "#define " << sstreamSafeguard.str() << std::endl << std::endl;
|
||||
else
|
||||
sstream << std::endl << "#endif // !defined(" << sstreamSafeguard.str() << ")" << std::endl;
|
||||
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CGenContext::SmartIndent(const std::string& rssStr, const std::string& rssIndent)
|
||||
{
|
||||
// Determine the amount of whitespace at the beginning of the string and replace this whitespace by the current indent. Do
|
||||
// this for every line.
|
||||
// Use four spaces for every tab (to allow mixed tab and space usage).
|
||||
size_t nDetectedIndentation = 0;
|
||||
size_t nPos = 0;
|
||||
enum class EState {init, skip_indent, code} eState = EState::init;
|
||||
while (eState == EState::init && nPos < rssStr.size())
|
||||
{
|
||||
switch (rssStr[nPos])
|
||||
{
|
||||
case ' ':
|
||||
nDetectedIndentation++;
|
||||
nPos++;
|
||||
break;
|
||||
case '\t':
|
||||
nDetectedIndentation += 4;
|
||||
nPos++;
|
||||
break;
|
||||
default:
|
||||
eState = EState::code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream sstream;
|
||||
while (nPos < rssStr.size())
|
||||
{
|
||||
// Skip indentation
|
||||
size_t nSkip = 0;
|
||||
while (eState == EState::skip_indent && nSkip < nDetectedIndentation)
|
||||
{
|
||||
switch (rssStr[nPos])
|
||||
{
|
||||
case ' ':
|
||||
nSkip++;
|
||||
nPos++;
|
||||
break;
|
||||
case '\t':
|
||||
nSkip +=4;
|
||||
nPos++;
|
||||
break;
|
||||
default:
|
||||
eState = EState::code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eState = EState::code;
|
||||
|
||||
// Find the next newline
|
||||
size_t nEnd = rssStr.find_first_of("\r\n", nPos);
|
||||
std::string ssSubstr = rssStr.substr(nPos, nEnd == std::string::npos ? nEnd : nEnd - nPos);
|
||||
|
||||
// If the string didn't start with a number character, remove the line concatinating character if it's there.
|
||||
if (rssStr[0] != '#' && !ssSubstr.empty() && *ssSubstr.rbegin() == '\\')
|
||||
ssSubstr.resize(ssSubstr.size() - 1);
|
||||
|
||||
// Remove whitespace at the end of the string
|
||||
while (!ssSubstr.empty() && std::isspace(*ssSubstr.rbegin()))
|
||||
ssSubstr.resize(ssSubstr.size() - 1);
|
||||
|
||||
// Stream the sub-string with indentation if the string didn't start with a number character.
|
||||
sstream << (rssStr[0] != '#' ? rssIndent : "") << ssSubstr;
|
||||
|
||||
// Stream and skip newline
|
||||
nPos = nEnd;
|
||||
if (nPos < rssStr.size())
|
||||
{
|
||||
if (rssStr[nPos] == '\r')
|
||||
nPos++;
|
||||
if (rssStr[nPos] == '\n')
|
||||
nPos++;
|
||||
eState = EState::skip_indent;
|
||||
}
|
||||
sstream << std::endl;
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CGenContext::QualifyName(const std::string& rssName)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
size_t nPos = 0;
|
||||
while (nPos < rssName.size())
|
||||
{
|
||||
size_t nSeparator = rssName.find_first_of(":.[]", nPos);
|
||||
sstream << rssName.substr(nPos, nSeparator == std::string::npos ? nSeparator : nSeparator - nPos);
|
||||
nPos = nSeparator;
|
||||
if (nPos != std::string::npos)
|
||||
{
|
||||
if (rssName[nPos] != ']')
|
||||
sstream << "_";
|
||||
nPos++;
|
||||
}
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CGenContext::ReplaceKeywords(const std::string& rssStr, const CKeywordMap& rmapKeywords, char cMarker /*= '%'*/)
|
||||
{
|
||||
std::stringstream sstream;
|
||||
size_t nPos = 0;
|
||||
while (nPos < rssStr.size())
|
||||
{
|
||||
// Find the initial separator
|
||||
size_t nSeparator = rssStr.find(cMarker, nPos);
|
||||
sstream << rssStr.substr(nPos, nSeparator == std::string::npos ? nSeparator : nSeparator - nPos);
|
||||
nPos = nSeparator;
|
||||
if (nSeparator == std::string::npos) continue;
|
||||
nPos++;
|
||||
|
||||
// Find the next separator.
|
||||
nSeparator = rssStr.find(cMarker, nPos);
|
||||
if (nSeparator == std::string::npos)
|
||||
throw CCompileException("Internal error: missing second separator during code generation.");
|
||||
|
||||
// Find the keyword in the keyword map (between the separator and the position).
|
||||
CKeywordMap::const_iterator itKeyword = rmapKeywords.find(rssStr.substr(nPos, nSeparator - nPos));
|
||||
if (itKeyword == rmapKeywords.end())
|
||||
{
|
||||
std::stringstream sstreamError;
|
||||
sstreamError << "Internal error: invalid keyword \"" << rssStr.substr(nPos, nSeparator - nPos) <<
|
||||
"\" during code generation.";
|
||||
throw CCompileException(sstreamError.str().c_str());
|
||||
} else
|
||||
sstream << itKeyword->second;
|
||||
nPos = nSeparator + 1;
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
std::string CGenContext::GetIndentChars()
|
||||
{
|
||||
// Default indentation is 4 spaces
|
||||
return " ";
|
||||
}
|
||||
|
||||
CGenContext::SCDeclInfo CGenContext::GetCDeclTypeStr(sdv::IInterfaceAccess* pDeclTypeObj, const std::string& rssScope /*= std::string()*/, bool bScopedName /*= false*/) const
|
||||
{
|
||||
std::function<void(sdv::IInterfaceAccess*, CGenContext::SCDeclInfo&)> fnInterpretType =
|
||||
[&, this](sdv::IInterfaceAccess* pTypeObj, CGenContext::SCDeclInfo& rsCDeclInfo)
|
||||
{
|
||||
if (!pTypeObj) throw CCompileException("Internal error: expecting a declaration type.");
|
||||
const sdv::idl::IDeclarationType* pDeclType = pTypeObj->GetInterface<sdv::idl::IDeclarationType>();
|
||||
if (!pDeclType) throw CCompileException("Internal error: expecting a declaration type.");
|
||||
rsCDeclInfo.eBaseType = pDeclType->GetBaseType();
|
||||
|
||||
// Separate between system type and defined type.
|
||||
if (pDeclType->GetTypeDefinition())
|
||||
{
|
||||
// Deal with anonymous definitions
|
||||
const sdv::idl::IEntityInfo* pTypeInfo = GetInterface<sdv::idl::IEntityInfo>(pDeclType->GetTypeDefinition());
|
||||
if (!pTypeInfo) throw CCompileException("Internal error: the entity doesn't expose information.");
|
||||
rsCDeclInfo.ssDeclType = bScopedName ?
|
||||
GetRelativeScopedName(pTypeInfo->GetScopedName(), rssScope) :
|
||||
static_cast<std::string>(pTypeInfo->GetName());
|
||||
if (rsCDeclInfo.ssDeclType.empty()) throw CCompileException("Internal error: the intity doesn't have a name.");
|
||||
}
|
||||
else
|
||||
rsCDeclInfo.ssDeclType = MapDeclType2CType(rsCDeclInfo.eBaseType);
|
||||
|
||||
// If the type is an interface, add a pointer to the type
|
||||
// TODO: Check for derived type...
|
||||
switch (rsCDeclInfo.eBaseType)
|
||||
{
|
||||
case sdv::idl::EDeclType::decltype_interface:
|
||||
rsCDeclInfo.ssDeclType += "*";
|
||||
rsCDeclInfo.bIsInterface = true;
|
||||
rsCDeclInfo.bIsPointer = true;
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_string:
|
||||
case sdv::idl::EDeclType::decltype_u8string:
|
||||
case sdv::idl::EDeclType::decltype_u16string:
|
||||
case sdv::idl::EDeclType::decltype_u32string:
|
||||
case sdv::idl::EDeclType::decltype_wstring:
|
||||
rsCDeclInfo.bIsString = true;
|
||||
rsCDeclInfo.bIsComplex = true;
|
||||
if (pDeclType->GetFixedLength())
|
||||
{
|
||||
// Insert fixed after sdv:: and before the string name
|
||||
rsCDeclInfo.ssDeclType.insert(5, "fixed_");
|
||||
rsCDeclInfo.ssDeclType += "<" + std::to_string(pDeclType->GetFixedLength()) + ">";
|
||||
rsCDeclInfo.bTemplated = true;
|
||||
}
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_sequence:
|
||||
rsCDeclInfo.bIsComplex = true;
|
||||
if (!pDeclType->GetValueType())
|
||||
throw CCompileException("Internal error: expecting value type for template parameter.");
|
||||
else
|
||||
{
|
||||
CGenContext::SCDeclInfo sCDeclInfoValueType;
|
||||
fnInterpretType(pDeclType->GetValueType(), sCDeclInfoValueType);
|
||||
rsCDeclInfo.ssDeclType += "<" + sCDeclInfoValueType.ssDeclType;
|
||||
if (pDeclType->GetFixedLength())
|
||||
rsCDeclInfo.ssDeclType += ", " + std::to_string(pDeclType->GetFixedLength());
|
||||
rsCDeclInfo.ssDeclType += ">";
|
||||
rsCDeclInfo.bTemplated = true;
|
||||
}
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_pointer:
|
||||
rsCDeclInfo.bIsComplex = true;
|
||||
if (!pDeclType->GetValueType())
|
||||
throw CCompileException("Internal error: expecting value type for template parameter.");
|
||||
else
|
||||
{
|
||||
CGenContext::SCDeclInfo sCDeclInfoValueType;
|
||||
fnInterpretType(pDeclType->GetValueType(), sCDeclInfoValueType);
|
||||
rsCDeclInfo.ssDeclType += "<" + sCDeclInfoValueType.ssDeclType;
|
||||
if (pDeclType->GetFixedLength())
|
||||
rsCDeclInfo.ssDeclType += ", " + std::to_string(pDeclType->GetFixedLength());
|
||||
rsCDeclInfo.ssDeclType += ">";
|
||||
rsCDeclInfo.bTemplated = true;
|
||||
}
|
||||
break;
|
||||
case sdv::idl::EDeclType::decltype_struct:
|
||||
case sdv::idl::EDeclType::decltype_union:
|
||||
rsCDeclInfo.bIsComplex = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Fill the C++ type structure
|
||||
CGenContext::SCDeclInfo sCDeclInfo;
|
||||
if (!pDeclTypeObj) return sCDeclInfo;
|
||||
fnInterpretType(pDeclTypeObj, sCDeclInfo);
|
||||
|
||||
// Exclude void as valid type
|
||||
if (sCDeclInfo.ssDeclType != "void")
|
||||
sCDeclInfo.bValidType = true;
|
||||
|
||||
return sCDeclInfo;
|
||||
}
|
||||
|
||||
std::string CGenContext::MapEntityType2CType(sdv::idl::EEntityType eEntityType)
|
||||
{
|
||||
switch (eEntityType)
|
||||
{
|
||||
case sdv::idl::EEntityType::type_enum: return "enum class";
|
||||
case sdv::idl::EEntityType::type_struct: return "struct";
|
||||
case sdv::idl::EEntityType::type_union: return "union";
|
||||
case sdv::idl::EEntityType::type_module: return "namespace";
|
||||
case sdv::idl::EEntityType::type_interface: return "interface";
|
||||
case sdv::idl::EEntityType::type_exception: return "except";
|
||||
case sdv::idl::EEntityType::type_typedef: return "typedef";
|
||||
case sdv::idl::EEntityType::type_attribute: return "";
|
||||
case sdv::idl::EEntityType::type_operation: return "";
|
||||
case sdv::idl::EEntityType::type_parameter: return "";
|
||||
case sdv::idl::EEntityType::type_enum_entry: return "";
|
||||
case sdv::idl::EEntityType::type_case_entry: return "";
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
std::string CGenContext::MapDeclType2CType(sdv::idl::EDeclType eDeclType)
|
||||
{
|
||||
switch (eDeclType)
|
||||
{
|
||||
case sdv::idl::EDeclType::decltype_short: return "int16_t";
|
||||
case sdv::idl::EDeclType::decltype_long: return "int32_t";
|
||||
case sdv::idl::EDeclType::decltype_long_long: return "int64_t";
|
||||
case sdv::idl::EDeclType::decltype_unsigned_short: return "uint16_t";
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long: return "uint32_t";
|
||||
case sdv::idl::EDeclType::decltype_unsigned_long_long: return "uint64_t";
|
||||
case sdv::idl::EDeclType::decltype_float: return "float";
|
||||
case sdv::idl::EDeclType::decltype_double: return "double";
|
||||
case sdv::idl::EDeclType::decltype_long_double: return "long double";
|
||||
case sdv::idl::EDeclType::decltype_fixed: return "uint32_t"; // TODO: Not implemented!
|
||||
case sdv::idl::EDeclType::decltype_char: return "char";
|
||||
case sdv::idl::EDeclType::decltype_char16: return "char16_t";
|
||||
case sdv::idl::EDeclType::decltype_char32: return "char32_t";
|
||||
case sdv::idl::EDeclType::decltype_wchar: return "wchar_t";
|
||||
case sdv::idl::EDeclType::decltype_boolean: return "bool";
|
||||
case sdv::idl::EDeclType::decltype_native: return "size_t";
|
||||
case sdv::idl::EDeclType::decltype_octet: return "uint8_t";
|
||||
case sdv::idl::EDeclType::decltype_string: return "sdv::string";
|
||||
case sdv::idl::EDeclType::decltype_u8string: return "sdv::u8string";
|
||||
case sdv::idl::EDeclType::decltype_u16string: return "sdv::u16string";
|
||||
case sdv::idl::EDeclType::decltype_u32string: return "sdv::u32string";
|
||||
case sdv::idl::EDeclType::decltype_wstring: return "sdv::wstring";
|
||||
case sdv::idl::EDeclType::decltype_enum: return "enum class";
|
||||
case sdv::idl::EDeclType::decltype_struct: return "struct";
|
||||
case sdv::idl::EDeclType::decltype_union: return "union";
|
||||
case sdv::idl::EDeclType::decltype_module: return "namespace";
|
||||
case sdv::idl::EDeclType::decltype_interface: return "interface";
|
||||
case sdv::idl::EDeclType::decltype_exception: return "struct";
|
||||
case sdv::idl::EDeclType::decltype_attribute: return "";
|
||||
case sdv::idl::EDeclType::decltype_operation: return "";
|
||||
case sdv::idl::EDeclType::decltype_parameter: return "";
|
||||
case sdv::idl::EDeclType::decltype_enum_entry: return "";
|
||||
case sdv::idl::EDeclType::decltype_case_entry: return "";
|
||||
case sdv::idl::EDeclType::decltype_typedef: return "typedef";
|
||||
case sdv::idl::EDeclType::decltype_sequence: return "sdv::sequence";
|
||||
case sdv::idl::EDeclType::decltype_pointer: return "sdv::pointer";
|
||||
case sdv::idl::EDeclType::decltype_map: return "uint32_t"; // TODO: Not implemented!
|
||||
case sdv::idl::EDeclType::decltype_bitset: return "uint32_t"; // TODO: Not implemented!
|
||||
case sdv::idl::EDeclType::decltype_bitfield: return "uint32_t"; // TODO: Not implemented!
|
||||
case sdv::idl::EDeclType::decltype_bitmask: return "uint32_t"; // TODO: Not implemented!
|
||||
case sdv::idl::EDeclType::decltype_any: return "sdv::any_t";
|
||||
case sdv::idl::EDeclType::decltype_interface_id: return "sdv::interface_id";
|
||||
case sdv::idl::EDeclType::decltype_interface_type: return "sdv::interface_t";
|
||||
case sdv::idl::EDeclType::decltype_exception_id: return "sdv::exception_id";
|
||||
case sdv::idl::EDeclType::decltype_void: return "void";
|
||||
case sdv::idl::EDeclType::decltype_unknown:
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
std::string CGenContext::GetRelativeScopedName(const std::string& ssScopedName, const std::string& rssScope)
|
||||
{
|
||||
if (rssScope.empty()) return ssScopedName;
|
||||
|
||||
// Splitting function
|
||||
using CScopeVector = std::vector<std::string>;
|
||||
auto fnSplitScopedName = [](const std::string& rssName) -> CScopeVector
|
||||
{
|
||||
CScopeVector vecSplittedName;
|
||||
size_t nPos = 0;
|
||||
while (nPos != std::string::npos)
|
||||
{
|
||||
size_t nStart = nPos;
|
||||
nPos = rssName.find("::", nStart);
|
||||
vecSplittedName.push_back(rssName.substr(nStart, nPos - nStart));
|
||||
if (nPos != std::string::npos)
|
||||
nPos += 2;
|
||||
}
|
||||
return vecSplittedName;
|
||||
};
|
||||
|
||||
// Split the scoped name
|
||||
CScopeVector vecScopedName = fnSplitScopedName(ssScopedName);
|
||||
if (vecScopedName.empty()) return ssScopedName;
|
||||
|
||||
// Split the scope
|
||||
CScopeVector vecScope = fnSplitScopedName(rssScope);
|
||||
if (vecScope.empty()) return ssScopedName;
|
||||
|
||||
// Reverse find the starting point
|
||||
auto itScope = vecScope.end();
|
||||
auto itScopedName = vecScopedName.begin();
|
||||
while (itScope != vecScope.begin())
|
||||
{
|
||||
itScope--;
|
||||
if (*itScope == *itScopedName) break;
|
||||
}
|
||||
|
||||
// As long as both iterators have identical scope names, increase the iterators.
|
||||
auto itSavedScopedName = itScopedName;
|
||||
while (itScope != vecScope.end() && itScopedName != vecScopedName.end() && *itScope == *itScopedName)
|
||||
{
|
||||
itScope++;
|
||||
itSavedScopedName = itScopedName;
|
||||
itScopedName++;
|
||||
}
|
||||
|
||||
// If the next name scope is anywhere in the rest of the scope, use the save scope name instead. For example:
|
||||
// Name = a::b::c::d
|
||||
// Scope = a::b::x::c
|
||||
// The iterator is pointing to:
|
||||
// Name iterator = c::d
|
||||
// Scope iterator = x::c
|
||||
// If returning the relative name (which is "c::d") it will be relative to the scope (which is "a::b::x::c") and will then be
|
||||
// a scoped name "a::b::x::c::d", which might not even exist. To solve this, insert the last scoped name part to the returned
|
||||
// name if the name is used in the rest of the scope as well (so insert "b" to the name which leads to a relative name of
|
||||
// "b::c::d").
|
||||
while (itScope != vecScope.end())
|
||||
{
|
||||
if (*itScope == *itScopedName)
|
||||
{
|
||||
itScopedName = itSavedScopedName;
|
||||
break;
|
||||
}
|
||||
itScope++;
|
||||
}
|
||||
|
||||
// Create a new scoped name from the left over scope names in the scoped name vector.
|
||||
std::string ssScopedNameNew;
|
||||
while (itScopedName != vecScopedName.end())
|
||||
{
|
||||
if (!ssScopedNameNew.empty()) ssScopedNameNew += "::";
|
||||
ssScopedNameNew += *itScopedName;
|
||||
itScopedName++;
|
||||
}
|
||||
|
||||
return ssScopedNameNew;
|
||||
}
|
||||
Reference in New Issue
Block a user