Files
openvehicle-api/sdv_executables/sdv_idl_compiler/token.cpp
tompzf 6ed4b1534e Precommit (#1)
* first commit

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

980 lines
29 KiB
C++

#include "token.h"
#include "support.h"
#include "constvariant.inl"
#include "parsecontext.h"
CToken::CToken(const std::string& rssText, ETokenType eType /*= ETokenType::token_identifier*/) :
m_eType(eType), m_ssCache(rssText)
{}
CToken::CToken(const std::string& rssText, ETokenLiteralType eLiteralType) :
m_eType(ETokenType::token_literal), m_eLiteralType(eLiteralType), m_ssCache(rssText)
{}
CToken::CToken(const std::string& rssText, ETokenMetaType eMetaType) :
m_eType(ETokenType::token_meta), m_eMetaType(eMetaType), m_ssCache(rssText)
{}
void CToken::MoveStart(int32_t iOffset)
{
// Correct boundaries and set the new position
int32_t iLocalOffset = iOffset;
if (iOffset < 0)
{
// Not before the beginning
if (m_uiCol < static_cast<uint32_t>(-iOffset))
iLocalOffset = -static_cast<int32_t>(m_uiCol);
// Adjust the position and length
m_uiCol -= static_cast<uint32_t>(-iLocalOffset);
if (m_uiLen != 0xffffffff)
m_uiLen += static_cast<uint32_t>(-iLocalOffset);
} else
{
// Not past the end
if (static_cast<uint32_t>(iOffset) > m_uiLen)
iLocalOffset = static_cast<int32_t>(m_uiLen);
// Check for any new lines occurring and adjust the position
for (int32_t iIdx = 0; iIdx < iLocalOffset; iIdx++)
{
if (m_szCode[iIdx] == '\n')
{
m_uiLine++;
m_uiCol = 1;
}
else
m_uiCol++;
}
// Adjust the length
if (m_uiLen != 0xffffffff)
m_uiLen -= static_cast<uint32_t>(iLocalOffset);
}
// Set the new code token
m_szCode += iLocalOffset;
// Clear the cache
m_ssCache.clear();
}
void CToken::MoveEnd(int32_t iOffset)
{
// Only works when there is a fixed length
if (m_uiLen == 0xffffffff) return;
// Correct boundaries and set new length
if (iOffset < 0)
{
if (static_cast<uint32_t>(-iOffset) > m_uiLen)
m_uiLen = 0;
else
m_uiLen -= static_cast<uint32_t>(-iOffset);
} else
m_uiLen += static_cast<uint32_t>(iOffset);
// Clear the cache
m_ssCache.clear();
}
bool CToken::operator==(const CToken& rtoken) const
{
return rtoken.m_szCode == m_szCode;
}
bool CToken::operator!=(const CToken& rtoken) const
{
return rtoken.m_szCode != m_szCode;
}
uint32_t CToken::GetLine() const
{
return m_uiLine;
}
uint32_t CToken::GetCol() const
{
return m_uiCol;
}
uint32_t CToken::GetEndLine() const
{
uint32_t uiEndLine = m_uiLine;
for (uint32_t uiIndex = 0; m_uiLen != 0xffffffff && uiIndex < m_uiLen; uiIndex++)
{
if (m_szCode[uiIndex] == '\n')
{
// Only increase the line count when this is not the last character of the snippet.
if (uiIndex < m_uiLen - 1) uiEndLine++;
}
}
return uiEndLine;
}
uint32_t CToken::GetEndCol() const
{
uint32_t uiEndCol = m_uiCol;
for (uint32_t uiIndex = 0; m_uiLen != 0xffffffff && uiIndex < m_uiLen; uiIndex++)
{
if (uiIndex) uiEndCol++; // Do not count the first column
if (m_szCode[uiIndex] == '\n')
{
// Only increase the line count when this is not the last character of the snippet.
if (uiIndex < m_uiLen - 1) uiEndCol = 0;
}
}
return uiEndCol;
}
uint32_t CToken::GetLength() const
{
return m_uiLen;
}
ETokenType CToken::GetType() const
{
return m_eType;
}
ETokenLiteralType CToken::GetLiteralType() const
{
return m_eLiteralType;
}
ETokenMetaType CToken::GetMetaType() const
{
return m_eMetaType;
}
CToken::operator bool() const
{
// Is there any cache?
if (!m_ssCache.empty()) return true;
// Validity checks on the token
if (!m_szCode) return false;
// Sanity check by getting the value
if (m_eType == ETokenType::token_literal && m_eLiteralType != ETokenLiteralType::token_undefined)
ValueRef();
// No invalidity detected.
return true;
}
CToken::operator const std::string&() const
{
if (m_ssCache.empty())
{
if (!m_szCode)
return m_ssCache;
if (!m_uiCol)
return m_ssCache;
if (m_uiLen != 0xffffffff)
m_ssCache = std::string(m_szCode, m_uiLen);
else
m_ssCache = std::string(m_szCode);
}
return m_ssCache;
}
const char* CToken::c_str() const
{
if (m_ssCache.empty())
{
if (!m_szCode)
return m_ssCache.c_str();
if (!m_uiCol)
return m_ssCache.c_str();
if (m_uiLen != 0xffffffff)
m_ssCache = std::string(m_szCode, m_uiLen);
else
m_ssCache = std::string(m_szCode);
}
return m_ssCache.c_str();
}
std::string CToken::Left(uint32_t uiLen) const
{
if (!m_ssCache.empty()) return m_ssCache.substr(0, uiLen);
if (!m_szCode) return std::string();
if (!m_uiCol) return std::string();
uint32_t uiLocalLen = m_uiLen != 0xffffffff ? m_uiLen : static_cast<uint32_t>(std::strlen(m_szCode));
return std::string(m_szCode, std::min(uiLen, uiLocalLen));
}
std::string CToken::Right(uint32_t uiLen) const
{
if (!m_ssCache.empty())
{
if (uiLen > m_ssCache.size()) return m_ssCache;
return m_ssCache.substr(m_ssCache.size() - uiLen);
}
if (!m_szCode)
return std::string();
if (!m_uiCol) return std::string();
uint32_t uiLocalLen = m_uiLen != 0xffffffff ? m_uiLen : static_cast<uint32_t>(std::strlen(m_szCode));
uint32_t uiOffset = uiLocalLen < uiLen ? 0 : uiLocalLen - uiLen;
return std::string(m_szCode + uiOffset, std::min(uiLen, uiLocalLen));
}
bool CToken::operator==(const char* szString) const
{
if (!m_ssCache.empty()) return m_ssCache == szString;
if (!m_szCode && szString) return false;
if (!szString) return false;
return static_cast<std::string>(*this) == szString;
}
bool CToken::operator!=(const char* szString) const
{
if (!m_ssCache.empty()) return m_ssCache != szString;
if (!m_szCode && szString) return true;
if (!szString) return true;
return static_cast<std::string>(*this) != szString;
}
bool CToken::operator==(const std::string& rssString) const
{
if (!m_ssCache.empty()) return m_ssCache == rssString;
if (!m_szCode && !rssString.empty()) return false;
if (rssString.empty()) return false;
return rssString == static_cast<std::string>(*this);
}
bool CToken::operator!=(const std::string& rssString) const
{
if (!m_ssCache.empty()) return m_ssCache != rssString;
if (!m_szCode && !rssString.empty()) return true;
if (rssString.empty()) return true;
return rssString != static_cast<std::string>(*this);
}
bool CToken::IsLiteral() const
{
return m_eType == ETokenType::token_literal &&
m_eLiteralType != ETokenLiteralType::token_undefined;
}
bool CToken::IsInteger() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_oct_integer:
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_bin_integer:
return true;
default:
return false;
}
}
bool CToken::IsSigned() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_oct_integer:
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_bin_integer:
// Check the string for not having the suffix U or u
return !Contains('U', 'u');
case ETokenLiteralType::token_literal_dec_floating_point:
case ETokenLiteralType::token_literal_hex_floating_point:
case ETokenLiteralType::token_literal_fixed_point:
// Always signed
return true;
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_character_sequence:
// True for 'char' type; false for all others
return IsAscii();
default:
return false;
}
}
bool CToken::IsUnsigned() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_oct_integer:
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_bin_integer:
// Check the string for having the suffix U or u
return Contains('U', 'u');
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_character_sequence:
// True for all but 'char' type
return !IsAscii();
default:
return false;
}
}
bool CToken::IsLong() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_oct_integer:
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_bin_integer:
case ETokenLiteralType::token_literal_dec_floating_point:
case ETokenLiteralType::token_literal_hex_floating_point:
// Check the string for having the suffix L or l
return Contains('L', 'l') && !Contains("LL", "ll");
case ETokenLiteralType::token_literal_character_sequence:
// The length of all characters in the sequence should fit the long
if (IsWide())
{
std::wstring ssText;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode, "\'", ssText, uiByteCnt);
return ssText.size() * sizeof(wchar_t) == sizeof(long);
}
else
{
std::string ssText;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode, "\'", ssText, uiByteCnt, false, IsAscii());
return ssText.size() == sizeof(long);
}
default:
return false;
}
}
bool CToken::IsLongLong() const
{
uint32_t uiByteCnt = 0;
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_oct_integer:
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_bin_integer:
// Check the string for having the suffix LL or l
return Contains("LL", "ll");
case ETokenLiteralType::token_literal_character_sequence:
// The length of all characters in the sequence should fit the long
if (IsWide())
{
std::wstring ssText;
uiByteCnt = 0;
InterpretCText(m_szCode, "\'", ssText, uiByteCnt);
return ssText.size() * sizeof(wchar_t) == sizeof(long long);
}
else
{
std::string ssText;
uiByteCnt = 0;
InterpretCText(m_szCode, "\'", ssText, uiByteCnt, false, IsAscii());
return ssText.size() == sizeof(long long);
}
default:
return false;
}
}
bool CToken::IsDecimal() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_integer:
case ETokenLiteralType::token_literal_dec_floating_point:
return true;
default:
return false;
}
}
bool CToken::IsHexadecimal() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_hex_integer:
case ETokenLiteralType::token_literal_hex_floating_point:
return true;
default:
return false;
}
}
bool CToken::IsOctal() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_oct_integer:
return true;
default:
return false;
}
}
bool CToken::IsBinary() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_bin_integer:
return true;
default:
return false;
}
}
bool CToken::IsFloatingPoint() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_dec_floating_point:
case ETokenLiteralType::token_literal_hex_floating_point:
return true;
default:
return false;
}
}
bool CToken::IsFixedPoint() const
{ switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_fixed_point:
return true;
default:
return false;
}
}
bool CToken::IsCharacter() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
return true;
default:
return false;
}
}
bool CToken::IsCharacterSequence() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character_sequence:
return true;
default:
return false;
}
}
bool CToken::IsString() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_string:
case ETokenLiteralType::token_literal_raw_string:
return true;
default:
return false;
}
}
bool CToken::IsAscii() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_character_sequence:
return m_szCode[0] == '\'';
case ETokenLiteralType::token_literal_string:
return m_szCode[0] == '\"';
case ETokenLiteralType::token_literal_raw_string:
return m_szCode[1] == '\"'; // String starting with R"(....)
default:
return false;
}
}
bool CToken::IsUtf8() const
{
// NOTE: UTF-8 character is not defined for C++17.
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_string:
case ETokenLiteralType::token_literal_raw_string:
return m_szCode[0] == 'u' && m_szCode[1] == '8'; // String starting with u8" or u8R"(....)
default:
return false;
}
}
bool CToken::IsUtf16() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_string:
case ETokenLiteralType::token_literal_raw_string:
return m_szCode[0] == 'u' && m_szCode[1] != '8'; // String starting with u" or uR"(....)
default:
return false;
}
}
bool CToken::IsUtf32() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_string:
case ETokenLiteralType::token_literal_raw_string:
return m_szCode[0] == 'U'; // String starting with U" or UR"(....)
default:
return false;
}
}
bool CToken::IsWide() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_character:
case ETokenLiteralType::token_literal_character_sequence:
case ETokenLiteralType::token_literal_string:
case ETokenLiteralType::token_literal_raw_string:
return m_szCode[0] == 'L'; // String starting with L" or LR"(....)
default:
return false;
}
}
bool CToken::IsRawString() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_raw_string:
return true;
default:
return false;
}
}
bool CToken::IsBoolean() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_boolean:
return true;
default:
return false;
}
}
bool CToken::IsNullptr() const
{
switch (m_eLiteralType)
{
case ETokenLiteralType::token_literal_nullptr:
return true;
default:
return false;
}
}
CConstVariant CToken::ValueRef() const
{
if (IsInteger() || IsCharacter() || IsCharacterSequence())
{
if (IsSigned())
return ValueSignedInteger();
else
return ValueUnsignedInteger();
} else if (IsFloatingPoint() || IsFixedPoint())
return ValueFloat();
else if (IsString())
return ValueString();
else if (IsBoolean())
return ValueBoolean();
else if (IsNullptr())
return ValueNullptr();
else
throw CCompileException(*this, "Internal error: invalid value type.");
}
template <typename... TChar>
bool CToken::Contains(char c, TChar... tChars) const
{
// Dependable on the existence of a length use the memchr or the strchr function.
if (m_uiLen == 0xFFFFFFFF)
{
if (std::strchr(m_szCode, c))
return true;
}
else
{
if (std::memchr(m_szCode, c, static_cast<size_t>(m_uiLen)))
return true;
}
return Contains(tChars...);
}
template <typename... TString>
bool CToken::Contains(const char* sz, TString... tStrings) const
{
// Implementation of strnstr (not part of the C/C++ library).
auto fnstrnstr = [](const char *haystack, const char *needle, size_t len) -> char*
{
int i;
size_t needle_len;
if (0 == (needle_len = strnlen(needle, len)))
return (char *)haystack;
for (i=0; i<=(int)(len-needle_len); i++)
{
if ((haystack[0] == needle[0]) &&
(0 == strncmp(haystack, needle, needle_len)))
return (char *)haystack;
haystack++;
}
return NULL;
};
// Dependable on the existence of a length use the strnstr or the strstr function.
if (m_uiLen == 0xFFFFFFFF)
{
if (std::strstr(m_szCode, sz))
return true;
}
else
{
if (fnstrnstr(m_szCode, sz, static_cast<size_t>(m_uiLen)))
return true;
}
return Contains(tStrings...);
}
CConstVariant CToken::ValueSignedInteger() const
{
int64_t iValue = 0ll;
if (IsInteger())
{
// Reset errno... will not be cleared otherwise.
errno = 0;
if (IsOctal())
iValue = static_cast<int64_t>(std::strtoll(m_szCode + 1, nullptr, 8));
else if (IsHexadecimal())
iValue = static_cast<int64_t>(std::strtoll(m_szCode + 2, nullptr, 16));
else if (IsBinary())
iValue = static_cast<int64_t>(std::strtoll(m_szCode + 2, nullptr, 2));
else
iValue = static_cast<int64_t>(std::strtoll(m_szCode, nullptr, 10));
if (errno == ERANGE)
throw CCompileException(*this, "The provided value exceeds the maximum possible value of a long long integer.");
}
if (IsCharacter())
{
if (IsAscii())
{
std::string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 1, "\'", ssValue, uiByteCnt, false, true);
if (!ssValue.empty()) iValue = ssValue[0];
}
if (IsUtf16())
{
std::u16string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty()) iValue = ssValue[0];
}
if (IsUtf32())
{
std::u32string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty()) iValue = ssValue[0];
}
if (IsWide())
{
std::wstring ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty()) iValue = ssValue[0];
}
}
if (IsCharacterSequence())
{
if (IsAscii())
{
std::string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 1, "\'", ssValue, uiByteCnt, false, true);
for (char c : ssValue)
iValue = iValue << 8 | static_cast<uint8_t>(c);
}
if (IsWide())
{
std::wstring ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
for (wchar_t c : ssValue)
{
if constexpr (sizeof(wchar_t) == sizeof(int16_t))
iValue = iValue << 16 | static_cast<uint16_t>(c);
else
iValue = iValue << 32 | static_cast<uint32_t>(c);
}
}
}
CConstVariant varValue;
if (iValue > std::numeric_limits<int8_t>::min() && iValue < std::numeric_limits<int8_t>::max())
varValue = static_cast<int8_t>(iValue);
else if (iValue > std::numeric_limits<int16_t>::min() && iValue < std::numeric_limits<int16_t>::max())
varValue = static_cast<int16_t>(iValue);
else if (iValue > std::numeric_limits<int32_t>::min() && iValue < std::numeric_limits<int32_t>::max())
varValue = static_cast<int32_t>(iValue);
else
varValue = iValue;
return varValue;
}
CConstVariant CToken::ValueUnsignedInteger() const
{
uint64_t uiValue = 0ull;
if (IsInteger())
{
// Reset errno... will not be cleared otherwise.
errno = 0;
if (IsOctal())
uiValue = static_cast<uint64_t>(std::strtoull(m_szCode + 1, nullptr, 8));
else if (IsHexadecimal())
uiValue = static_cast<uint64_t>(std::strtoull(m_szCode + 2, nullptr, 16));
else if (IsBinary())
uiValue = static_cast<uint64_t>(std::strtoull(m_szCode + 2, nullptr, 2));
else
uiValue = static_cast<uint64_t>(std::strtoull(m_szCode, nullptr, 10));
if (errno == ERANGE)
throw CCompileException(*this,
"The provided value exceeds the maximum possible value of an unsigned long long integer.");
}
if (IsCharacter())
{
if (IsAscii())
{
std::string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 1, "\'", ssValue, uiByteCnt, false, true);
if (!ssValue.empty()) uiValue = static_cast<uint8_t>(ssValue[0]);
}
if (IsUtf16())
{
std::u16string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty()) uiValue = static_cast<uint16_t>(ssValue[0]);
}
if (IsUtf32())
{
std::u32string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty()) uiValue = static_cast<uint32_t>(ssValue[0]);
}
if (IsWide())
{
std::wstring ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
if (!ssValue.empty())
uiValue = sizeof(wchar_t) == 2 ? static_cast<uint16_t>(ssValue[0]) : static_cast<uint32_t>(ssValue[0]);
}
}
if (IsCharacterSequence())
{
uiValue = 0;
if (IsAscii())
{
std::string ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 1, "\'", ssValue, uiByteCnt, false, true);
for (char c : ssValue)
uiValue = uiValue << 8 | static_cast<uint8_t>(c);
}
if (IsWide())
{
std::wstring ssValue;
uint32_t uiByteCnt = 0;
InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt);
for (wchar_t c : ssValue)
{
if constexpr (sizeof(wchar_t) == sizeof(int16_t))
uiValue = uiValue << 16 | static_cast<uint16_t>(c);
else
uiValue = uiValue << 32 | static_cast<uint32_t>(c);
}
}
}
CConstVariant varValue;
if (uiValue < static_cast<uint64_t>(std::numeric_limits<uint8_t>::max()))
varValue = static_cast<uint8_t>(uiValue);
else if (uiValue < static_cast<uint64_t>(std::numeric_limits<int16_t>::max()))
varValue = static_cast<int16_t>(uiValue);
else if (uiValue < static_cast<uint64_t>(std::numeric_limits<int32_t>::max()))
varValue = static_cast<int32_t>(uiValue);
else
varValue = uiValue;
return varValue;
}
CConstVariant CToken::ValueFloat() const
{
long double ldValue = 0.0;
// Only integer, character, character sequence and boolean can be assigned.
if (IsInteger() || IsCharacter() || IsCharacterSequence())
{
if (IsSigned())
ldValue = ValueSignedInteger().Get<long double>();
else // unsigned
ldValue = ValueUnsignedInteger().Get<long double>();
}
if (IsFloatingPoint())
{
errno = 0;
ldValue = std::strtold(m_szCode, nullptr);
if (errno == ERANGE)
throw CCompileException(*this, "Floating point doesn't fit into the data type.");
}
if (IsFixedPoint())
{
// A fixed point data type is not supported by C++ at the moment. Use the double data type to calculate and limit the
// result to 31 bits for the value. The definition is not clear how these 31 bits divide between digits and fraction.
errno = 0;
ldValue = std::strtod(m_szCode, nullptr);
if (errno == ERANGE)
throw CCompileException(*this, "Floating point doesn't fit into the data type.");
if (ldValue < -2147483647) // 31 bits
throw CCompileException(*this, "The value falls below the smallest possible value of the type.");
if (ldValue > 2147483648) // 31 bits
throw CCompileException(*this, "The value exceeds the highest possible value of the type.");
int iExpValue = 0;
static int iExpMin = 0;
long double ldDigitsValue = std::fabs(std::frexp(ldValue, &iExpValue));
static long double ldDigitsMin = std::frexp(1.0 / static_cast<double>(1ll << 31), &iExpMin);
if ((iExpValue < iExpMin) || ((iExpValue == iExpMin) && ldDigitsValue < ldDigitsMin))
throw CCompileException(*this, "The value precision falls below the smallest possible precision of the type.");
}
if (IsString())
throw CCompileException(*this, "Cannot assign a string to a floating/fixed point value.");
if (IsBoolean())
ldValue = ValueBoolean().Get<long double>();
if (IsNullptr())
ldValue = ValueNullptr().Get<long double>();
CConstVariant varValue;
static int iExpValue = 0, iExpFloatMin = 0, iExpDoubleMin = 0/*, iExpLongDoubleMin = 0*/;
static float ldDigitsFloatMin = std::frexp(std::numeric_limits<float>::min(), &iExpFloatMin);
static double ldDigitsDoubleMin = std::frexp(std::numeric_limits<double>::min(), &iExpDoubleMin);
// static long double ldDigitsLongDoubleMin = std::frexp(std::numeric_limits<long double>::min(), &iExpLongDoubleMin);
long double ldDigitsValue = std::fabs(std::frexp(ldValue, &iExpValue));
if (ldValue < std::numeric_limits<float>::max() && ldValue > std::numeric_limits<float>::lowest() &&
((iExpValue > iExpFloatMin) || ((iExpValue == iExpFloatMin) && ldDigitsValue > ldDigitsFloatMin)))
varValue = static_cast<float>(ldValue);
else if (ldValue < std::numeric_limits<double>::max() && ldValue > std::numeric_limits<double>::lowest() &&
((iExpValue > iExpDoubleMin) || ((iExpValue == iExpDoubleMin) && ldDigitsValue > ldDigitsDoubleMin)))
varValue = static_cast<double>(ldValue);
else
varValue = ldValue;
return varValue;
}
CConstVariant CToken::ValueBoolean() const
{
if (IsBoolean())
{
if (*this == "true") return CConstVariant(true);
if (*this == "TRUE") return CConstVariant(true);
if (*this == "false") return CConstVariant(false);
if (*this == "FALSE") return CConstVariant(false);
throw CCompileException(*this, "Expecting a boolean value.");
}
if (IsInteger() || IsCharacter() || IsCharacterSequence())
{
int64_t iValue = ValueSignedInteger().Get<int64_t>();
if (iValue == 1) return CConstVariant(true);
if (iValue == 0) return CConstVariant(false);
throw CCompileException(*this, "Expecting a boolean value or an integer value of 1 or 0.");
}
if (IsNullptr())
{
if (ValueNullptr().Get<uint64_t>() == 0) return CConstVariant(false);
throw CCompileException(*this, "Expecting a nullptr value.");
}
throw CCompileException(*this, "Expecting a boolean value.");
}
CConstVariant CToken::ValueNullptr() const
{
if (IsNullptr()) return CConstVariant(0);
if (IsInteger() || IsCharacter() || IsCharacterSequence())
{
int64_t iValue = ValueSignedInteger().Get<int64_t>();
if (iValue == 0) return CConstVariant(0);
throw CCompileException(*this, "Expecting a nullptr value or the integer value of 0.");
}
throw CCompileException(*this, "Expecting a nullptr value.");
}
CConstVariant CToken::ValueString() const
{
if (IsString())
{
if (IsAscii())
{
uint32_t uiByteCnt = 0;
std::string ssValue;
InterpretCText(m_szCode + 1, "\"", ssValue, uiByteCnt, false, true);
return CConstVariant(ssValue);
}
if (IsUtf8())
{
uint32_t uiByteCnt = 0;
std::string ssValue;
InterpretCText(m_szCode + 3, "\"", ssValue, uiByteCnt);
return CConstVariant(ssValue);
}
if (IsUtf16())
{
uint32_t uiByteCnt = 0;
std::u16string ssValue;
InterpretCText(m_szCode + 2, "\"", ssValue, uiByteCnt);
return CConstVariant(ssValue);
}
if (IsUtf32())
{
uint32_t uiByteCnt = 0;
std::u32string ssValue;
InterpretCText(m_szCode + 2, "\"", ssValue, uiByteCnt);
return CConstVariant(ssValue);
}
if (IsWide())
{
uint32_t uiByteCnt = 0;
std::wstring ssValue;
InterpretCText(m_szCode + 2, "\"", ssValue, uiByteCnt);
return CConstVariant(ssValue);
}
}
throw CCompileException(*this, "Cannot convert type to string.");
}