/******************************************************************************** * 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 ********************************************************************************/ #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(-iOffset)) iLocalOffset = -static_cast(m_uiCol); // Adjust the position and length m_uiCol -= static_cast(-iLocalOffset); if (m_uiLen != 0xffffffff) m_uiLen += static_cast(-iLocalOffset); } else { // Not past the end if (static_cast(iOffset) > m_uiLen) iLocalOffset = static_cast(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(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(-iOffset) > m_uiLen) m_uiLen = 0; else m_uiLen -= static_cast(-iOffset); } else m_uiLen += static_cast(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(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(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(*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(*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(*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(*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 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(m_uiLen))) return true; } return Contains(tChars...); } template 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(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(std::strtoll(m_szCode + 1, nullptr, 8)); else if (IsHexadecimal()) iValue = static_cast(std::strtoll(m_szCode + 2, nullptr, 16)); else if (IsBinary()) iValue = static_cast(std::strtoll(m_szCode + 2, nullptr, 2)); else iValue = static_cast(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(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(c); else iValue = iValue << 32 | static_cast(c); } } } CConstVariant varValue; if (iValue > std::numeric_limits::min() && iValue < std::numeric_limits::max()) varValue = static_cast(iValue); else if (iValue > std::numeric_limits::min() && iValue < std::numeric_limits::max()) varValue = static_cast(iValue); else if (iValue > std::numeric_limits::min() && iValue < std::numeric_limits::max()) varValue = static_cast(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(std::strtoull(m_szCode + 1, nullptr, 8)); else if (IsHexadecimal()) uiValue = static_cast(std::strtoull(m_szCode + 2, nullptr, 16)); else if (IsBinary()) uiValue = static_cast(std::strtoull(m_szCode + 2, nullptr, 2)); else uiValue = static_cast(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(ssValue[0]); } if (IsUtf16()) { std::u16string ssValue; uint32_t uiByteCnt = 0; InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt); if (!ssValue.empty()) uiValue = static_cast(ssValue[0]); } if (IsUtf32()) { std::u32string ssValue; uint32_t uiByteCnt = 0; InterpretCText(m_szCode + 2, "\'", ssValue, uiByteCnt); if (!ssValue.empty()) uiValue = static_cast(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(ssValue[0]) : static_cast(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(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(c); else uiValue = uiValue << 32 | static_cast(c); } } } CConstVariant varValue; if (uiValue < static_cast(std::numeric_limits::max())) varValue = static_cast(uiValue); else if (uiValue < static_cast(std::numeric_limits::max())) varValue = static_cast(uiValue); else if (uiValue < static_cast(std::numeric_limits::max())) varValue = static_cast(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(); else // unsigned ldValue = ValueUnsignedInteger().Get(); } 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(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(); if (IsNullptr()) ldValue = ValueNullptr().Get(); CConstVariant varValue; static int iExpValue = 0, iExpFloatMin = 0, iExpDoubleMin = 0/*, iExpLongDoubleMin = 0*/; static float ldDigitsFloatMin = std::frexp(std::numeric_limits::min(), &iExpFloatMin); static double ldDigitsDoubleMin = std::frexp(std::numeric_limits::min(), &iExpDoubleMin); // static long double ldDigitsLongDoubleMin = std::frexp(std::numeric_limits::min(), &iExpLongDoubleMin); long double ldDigitsValue = std::fabs(std::frexp(ldValue, &iExpValue)); if (ldValue < std::numeric_limits::max() && ldValue > std::numeric_limits::lowest() && ((iExpValue > iExpFloatMin) || ((iExpValue == iExpFloatMin) && ldDigitsValue > ldDigitsFloatMin))) varValue = static_cast(ldValue); else if (ldValue < std::numeric_limits::max() && ldValue > std::numeric_limits::lowest() && ((iExpValue > iExpDoubleMin) || ((iExpValue == iExpDoubleMin) && ldDigitsValue > ldDigitsDoubleMin))) varValue = static_cast(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(); 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() == 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(); 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."); }