From 6741f774b162ff1368acf58db0509f4813471303 Mon Sep 17 00:00:00 2001 From: Carl Morgan <92343106+carlatcrown@users.noreply.github.com> Date: Fri, 9 Jun 2023 06:03:41 +1200 Subject: [PATCH] Support integer Z suffix and user defined literals with _ suffix (#10807, #11438) (#5130) Co-authored-by: Carl Morgan --- lib/mathlib.cpp | 37 ++++++++++++++++++++++++++++++++---- test/testmathlib.cpp | 45 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index e332d2b8d..a7a6bd473 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -546,7 +546,7 @@ bool MathLib::isDecimalFloat(const std::string &str) if (str.empty()) return false; enum class State { - START, BASE_DIGITS1, LEADING_DECIMAL, TRAILING_DECIMAL, BASE_DIGITS2, E, MANTISSA_PLUSMINUS, MANTISSA_DIGITS, SUFFIX_F, SUFFIX_L + START, BASE_DIGITS1, LEADING_DECIMAL, TRAILING_DECIMAL, BASE_DIGITS2, E, MANTISSA_PLUSMINUS, MANTISSA_DIGITS, SUFFIX_F, SUFFIX_L, SUFFIX_LITERAL_LEADER, SUFFIX_LITERAL } state = State::START; std::string::const_iterator it = str.cbegin(); if ('+' == *it || '-' == *it) @@ -582,6 +582,8 @@ bool MathLib::isDecimalFloat(const std::string &str) state = State::SUFFIX_F; else if (*it=='l' || *it=='L') state = State::SUFFIX_L; + else if (*it == '_') + state = State::SUFFIX_LITERAL_LEADER; else if (std::isdigit(static_cast(*it))) state = State::BASE_DIGITS2; else @@ -594,6 +596,8 @@ bool MathLib::isDecimalFloat(const std::string &str) state = State::SUFFIX_F; else if (*it=='l' || *it=='L') state = State::SUFFIX_L; + else if (*it == '_') + state = State::SUFFIX_LITERAL_LEADER; else if (!std::isdigit(static_cast(*it))) return false; break; @@ -619,13 +623,18 @@ bool MathLib::isDecimalFloat(const std::string &str) else if (!std::isdigit(static_cast(*it))) return false; break; + // Ensure at least one post _ char for user defined literals + case State::SUFFIX_LITERAL: + case State::SUFFIX_LITERAL_LEADER: + state = State::SUFFIX_LITERAL; + break; case State::SUFFIX_F: return false; case State::SUFFIX_L: return false; } } - return (state==State::BASE_DIGITS2 || state==State::MANTISSA_DIGITS || state==State::TRAILING_DECIMAL || state==State::SUFFIX_F || state==State::SUFFIX_L); + return (state==State::BASE_DIGITS2 || state==State::MANTISSA_DIGITS || state==State::TRAILING_DECIMAL || state==State::SUFFIX_F || state==State::SUFFIX_L || (state==State::SUFFIX_LITERAL)); } bool MathLib::isNegative(const std::string &str) @@ -644,7 +653,7 @@ bool MathLib::isPositive(const std::string &str) static bool isValidIntegerSuffixIt(std::string::const_iterator it, std::string::const_iterator end, bool supportMicrosoftExtensions=true) { - enum class Status { START, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU, SUFFIX_I, SUFFIX_I6, SUFFIX_I64, SUFFIX_UI, SUFFIX_UI6, SUFFIX_UI64 } state = Status::START; + enum class Status { START, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_UZ, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU, SUFFIX_I, SUFFIX_I6, SUFFIX_I64, SUFFIX_UI, SUFFIX_UI6, SUFFIX_UI64, SUFFIX_Z, SUFFIX_LITERAL_LEADER, SUFFIX_LITERAL } state = Status::START; for (; it != end; ++it) { switch (state) { case Status::START: @@ -652,14 +661,20 @@ static bool isValidIntegerSuffixIt(std::string::const_iterator it, std::string:: state = Status::SUFFIX_U; else if (*it == 'l' || *it == 'L') state = Status::SUFFIX_L; + else if (*it == 'z' || *it == 'Z') + state = Status::SUFFIX_Z; else if (supportMicrosoftExtensions && (*it == 'i' || *it == 'I')) state = Status::SUFFIX_I; + else if (*it == '_') + state = Status::SUFFIX_LITERAL_LEADER; else return false; break; case Status::SUFFIX_U: if (*it == 'l' || *it == 'L') state = Status::SUFFIX_UL; // UL + else if (*it == 'z' || *it == 'Z') + state = Status::SUFFIX_UZ; // UZ else if (supportMicrosoftExtensions && (*it == 'i' || *it == 'I')) state = Status::SUFFIX_UI; else @@ -711,19 +726,33 @@ static bool isValidIntegerSuffixIt(std::string::const_iterator it, std::string:: else return false; break; + case Status::SUFFIX_Z: + if (*it == 'u' || *it == 'U') + state = Status::SUFFIX_UZ; + else + return false; + break; + // Ensure at least one post _ char for user defined literals + case Status::SUFFIX_LITERAL: + case Status::SUFFIX_LITERAL_LEADER: + state = Status::SUFFIX_LITERAL; + break; default: return false; } } return ((state == Status::SUFFIX_U) || (state == Status::SUFFIX_L) || + (state == Status::SUFFIX_Z) || (state == Status::SUFFIX_UL) || + (state == Status::SUFFIX_UZ) || (state == Status::SUFFIX_LU) || (state == Status::SUFFIX_LL) || (state == Status::SUFFIX_ULL) || (state == Status::SUFFIX_LLU) || (state == Status::SUFFIX_I64) || - (state == Status::SUFFIX_UI64)); + (state == Status::SUFFIX_UI64) || + (state == Status::SUFFIX_LITERAL)); } // cppcheck-suppress unusedFunction diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index d02598f04..e49d08afa 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -960,6 +960,14 @@ private: ASSERT_EQUALS(true, MathLib::isIntHex("-0x0ULL")); ASSERT_EQUALS(true, MathLib::isIntHex("+0x0LLU")); ASSERT_EQUALS(true, MathLib::isIntHex("-0x0LLU")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0Z")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0Z")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0ZU")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0ZU")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0UZ")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0UZ")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0Uz")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0Uz")); // negative testing ASSERT_EQUALS(false, MathLib::isIntHex("+0x")); @@ -972,10 +980,6 @@ private: ASSERT_EQUALS(false, MathLib::isIntHex(" ")); ASSERT_EQUALS(false, MathLib::isIntHex(" ")); ASSERT_EQUALS(false, MathLib::isIntHex("0")); - ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Z")); - ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Z")); - ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Uz")); - ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Uz")); ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Lz")); ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Lz")); ASSERT_EQUALS(false, MathLib::isIntHex("+0x0LUz")); @@ -1018,12 +1022,19 @@ private: ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("u")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ul")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ull")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("uz")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("l")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("lu")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ll")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("llu")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("llU")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("LLU")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("z")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("Z")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("zu")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("UZ")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ZU")); + // Microsoft extensions: ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("i64")); ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("I64")); @@ -1033,6 +1044,10 @@ private: ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("I64", false)); ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("ui64", false)); ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("UI64", false)); + + // User defined suffix literals + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("_")); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("_MyUserDefinedLiteral")); } void ispositive() const { @@ -1057,6 +1072,13 @@ private: ASSERT_EQUALS(true, MathLib::isFloat("0.f")); ASSERT_EQUALS(true, MathLib::isFloat("0.f")); ASSERT_EQUALS(true, MathLib::isFloat("0xA.Fp-10")); + + // User defined suffix literals + ASSERT_EQUALS(false, MathLib::isFloat("0_")); + ASSERT_EQUALS(false, MathLib::isFloat("0._")); + ASSERT_EQUALS(false, MathLib::isFloat("0.1_")); + ASSERT_EQUALS(true, MathLib::isFloat("0.0_MyUserDefinedLiteral")); + ASSERT_EQUALS(true, MathLib::isFloat("0._MyUserDefinedLiteral")); } void isDecimalFloat() const { @@ -1164,6 +1186,13 @@ private: ASSERT_EQUALS(true, MathLib::isDecimalFloat("1.0E+1")); ASSERT_EQUALS(true, MathLib::isDecimalFloat("1.0E-1")); ASSERT_EQUALS(true, MathLib::isDecimalFloat("-1.0E+1")); + + // User defined suffix literals + ASSERT_EQUALS(false, MathLib::isDecimalFloat("0_")); + ASSERT_EQUALS(false, MathLib::isDecimalFloat(".1_")); + ASSERT_EQUALS(false, MathLib::isDecimalFloat("0.1_")); + ASSERT_EQUALS(true, MathLib::isDecimalFloat("0.0_MyUserDefinedLiteral")); + ASSERT_EQUALS(true, MathLib::isDecimalFloat(".1_MyUserDefinedLiteral")); } void naninf() const { @@ -1198,6 +1227,14 @@ private: ASSERT_EQUALS(false, MathLib::isDec("+x")); ASSERT_EQUALS(false, MathLib::isDec("x")); ASSERT_EQUALS(false, MathLib::isDec("")); + + // User defined suffix literals + ASSERT_EQUALS(false, MathLib::isDec("0_")); + ASSERT_EQUALS(false, MathLib::isDec("+0_")); + ASSERT_EQUALS(false, MathLib::isDec("-1_")); + ASSERT_EQUALS(true, MathLib::isDec("0_MyUserDefinedLiteral")); + ASSERT_EQUALS(true, MathLib::isDec("+1_MyUserDefinedLiteral")); + ASSERT_EQUALS(true, MathLib::isDec("-1_MyUserDefinedLiteral")); } void isNullValue() const {