diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index ada6580d84..7e521d12b2 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -342,7 +342,7 @@ Token Lexer::try_hex_float() { auto source = begin_source(); // clang-format off - // -?0x([0-9a-fA-F]*.?[0-9a-fA-F]+ | [0-9a-fA-F]+.[0-9a-fA-F]*)(p|P)(+|-)?[0-9]+ // NOLINT + // -?0[xX]([0-9a-fA-F]*.?[0-9a-fA-F]+ | [0-9a-fA-F]+.[0-9a-fA-F]*)(p|P)(+|-)?[0-9]+ // NOLINT // clang-format on // -? @@ -351,8 +351,8 @@ Token Lexer::try_hex_float() { sign_bit = 1; end++; } - // 0x - if (matches(end, "0x")) { + // 0[xX] + if (matches(end, "0x") || matches(end, "0X")) { end += 2; } else { return {}; @@ -663,7 +663,7 @@ Token Lexer::try_hex_integer() { end++; } - if (matches(end, "0x")) { + if (matches(end, "0x") || matches(end, "0X")) { end += 2; } else { return {}; diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc index fbfea7ad3f..4db3a835d7 100644 --- a/src/reader/wgsl/lexer_test.cc +++ b/src/reader/wgsl/lexer_test.cc @@ -394,11 +394,17 @@ INSTANTIATE_TEST_SUITE_P( IntegerTest_HexSigned, testing::Values( HexSignedIntData{"0x0", 0}, + HexSignedIntData{"0X0", 0}, HexSignedIntData{"0x42", 66}, + HexSignedIntData{"0X42", 66}, HexSignedIntData{"-0x42", -66}, + HexSignedIntData{"-0X42", -66}, HexSignedIntData{"0xeF1Abc9", 250719177}, + HexSignedIntData{"0XeF1Abc9", 250719177}, HexSignedIntData{"-0x80000000", std::numeric_limits::min()}, - HexSignedIntData{"0x7FFFFFFF", std::numeric_limits::max()})); + HexSignedIntData{"-0X80000000", std::numeric_limits::min()}, + HexSignedIntData{"0x7FFFFFFF", std::numeric_limits::max()}, + HexSignedIntData{"0X7FFFFFFF", std::numeric_limits::max()})); TEST_F(LexerTest, HexPrefixOnly_IsError) { // Could be the start of a hex integer or hex float, but is neither. @@ -411,6 +417,17 @@ TEST_F(LexerTest, HexPrefixOnly_IsError) { "integer or float hex literal has no significant digits"); } +TEST_F(LexerTest, HexPrefixUpperCaseOnly_IsError) { + // Could be the start of a hex integer or hex float, but is neither. + Source::FileContent content("0X"); + Lexer l("test.wgsl", &content); + + auto t = l.next(); + ASSERT_TRUE(t.Is(Token::Type::kError)); + EXPECT_EQ(t.to_str(), + "integer or float hex literal has no significant digits"); +} + TEST_F(LexerTest, NegativeHexPrefixOnly_IsError) { // Could be the start of a hex integer or hex float, but is neither. Source::FileContent content("-0x"); @@ -422,6 +439,17 @@ TEST_F(LexerTest, NegativeHexPrefixOnly_IsError) { "integer or float hex literal has no significant digits"); } +TEST_F(LexerTest, NegativeHexPrefixUpperCaseOnly_IsError) { + // Could be the start of a hex integer or hex float, but is neither. + Source::FileContent content("-0X"); + Lexer l("test.wgsl", &content); + + auto t = l.next(); + ASSERT_TRUE(t.Is(Token::Type::kError)); + EXPECT_EQ(t.to_str(), + "integer or float hex literal has no significant digits"); +} + TEST_F(LexerTest, IntegerTest_HexSignedTooLarge) { Source::FileContent content("0x80000000"); Lexer l("test.wgsl", &content); diff --git a/src/reader/wgsl/parser_impl_const_literal_test.cc b/src/reader/wgsl/parser_impl_const_literal_test.cc index 9e6a88a6a2..e91051f158 100644 --- a/src/reader/wgsl/parser_impl_const_literal_test.cc +++ b/src/reader/wgsl/parser_impl_const_literal_test.cc @@ -17,6 +17,8 @@ #include #include +#include "gmock/gmock.h" + namespace tint { namespace reader { namespace wgsl { @@ -115,9 +117,19 @@ TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooLargePositive) { ASSERT_EQ(c.value, nullptr); } +// Returns true if the given non-Nan float numbers are equal. +bool FloatEqual(float a, float b) { + // Avoid Clang complaining about equality test on float. + // -Wfloat-equal. + return (a <= b) && (a >= b); +} + struct FloatLiteralTestCase { - const char* input; + std::string input; float expected; + bool operator==(const FloatLiteralTestCase& other) const { + return (input == other.input) && FloatEqual(expected, other.expected); + } }; inline std::ostream& operator<<(std::ostream& out, FloatLiteralTestCase data) { @@ -140,192 +152,233 @@ TEST_P(ParserImplFloatLiteralTest, Parse) { EXPECT_FLOAT_EQ(c->As()->value, params.expected); } -FloatLiteralTestCase float_literal_test_cases[] = { - {"0.0", 0.0f}, // Zero - {"1.0", 1.0f}, // One - {"-1.0", -1.0f}, // MinusOne - {"1000000000.0", 1e9f}, // Billion - {"-0.0", std::copysign(0.0f, -5.0f)}, // NegativeZero - {"0.0", MakeFloat(0, 0, 0)}, // Zero - {"-0.0", MakeFloat(1, 0, 0)}, // NegativeZero - {"1.0", MakeFloat(0, 127, 0)}, // One - {"-1.0", MakeFloat(1, 127, 0)}, // NegativeOne -}; +using FloatLiteralTestCaseList = std::vector; + +FloatLiteralTestCaseList DecimalFloatCases() { + return FloatLiteralTestCaseList{ + {"0.0", 0.0f}, // Zero + {"1.0", 1.0f}, // One + {"-1.0", -1.0f}, // MinusOne + {"1000000000.0", 1e9f}, // Billion + {"-0.0", std::copysign(0.0f, -5.0f)}, // NegativeZero + {"0.0", MakeFloat(0, 0, 0)}, // Zero + {"-0.0", MakeFloat(1, 0, 0)}, // NegativeZero + {"1.0", MakeFloat(0, 127, 0)}, // One + {"-1.0", MakeFloat(1, 127, 0)}, // NegativeOne + }; +} + INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float, ParserImplFloatLiteralTest, - testing::ValuesIn(float_literal_test_cases)); + testing::ValuesIn(DecimalFloatCases())); const float NegInf = MakeFloat(1, 255, 0); const float PosInf = MakeFloat(0, 255, 0); -FloatLiteralTestCase hexfloat_literal_test_cases[] = { - // Regular numbers - {"0x0p+0", 0.f}, - {"0x1p+0", 1.f}, - {"0x1p+1", 2.f}, - {"0x1.8p+1", 3.f}, - {"0x1.99999ap-4", 0.1f}, - {"0x1p-1", 0.5f}, - {"0x1p-2", 0.25f}, - {"0x1.8p-1", 0.75f}, - {"-0x0p+0", -0.f}, - {"-0x1p+0", -1.f}, - {"-0x1p-1", -0.5f}, - {"-0x1p-2", -0.25f}, - {"-0x1.8p-1", -0.75f}, +FloatLiteralTestCaseList HexFloatCases() { + return FloatLiteralTestCaseList{ + // Regular numbers + {"0x0p+0", 0.f}, + {"0x1p+0", 1.f}, + {"0x1p+1", 2.f}, + {"0x1.8p+1", 3.f}, + {"0x1.99999ap-4", 0.1f}, + {"0x1p-1", 0.5f}, + {"0x1p-2", 0.25f}, + {"0x1.8p-1", 0.75f}, + {"-0x0p+0", -0.f}, + {"-0x1p+0", -1.f}, + {"-0x1p-1", -0.5f}, + {"-0x1p-2", -0.25f}, + {"-0x1.8p-1", -0.75f}, - // Large numbers - {"0x1p+9", 512.f}, - {"0x1p+10", 1024.f}, - {"0x1.02p+10", 1024.f + 8.f}, - {"-0x1p+9", -512.f}, - {"-0x1p+10", -1024.f}, - {"-0x1.02p+10", -1024.f - 8.f}, + // Large numbers + {"0x1p+9", 512.f}, + {"0x1p+10", 1024.f}, + {"0x1.02p+10", 1024.f + 8.f}, + {"-0x1p+9", -512.f}, + {"-0x1p+10", -1024.f}, + {"-0x1.02p+10", -1024.f - 8.f}, - // Small numbers - {"0x1p-9", 1.0f / 512.f}, - {"0x1p-10", 1.0f / 1024.f}, - {"0x1.02p-3", 1.0f / 1024.f + 1.0f / 8.f}, - {"-0x1p-9", 1.0f / -512.f}, - {"-0x1p-10", 1.0f / -1024.f}, - {"-0x1.02p-3", 1.0f / -1024.f - 1.0f / 8.f}, + // Small numbers + {"0x1p-9", 1.0f / 512.f}, + {"0x1p-10", 1.0f / 1024.f}, + {"0x1.02p-3", 1.0f / 1024.f + 1.0f / 8.f}, + {"-0x1p-9", 1.0f / -512.f}, + {"-0x1p-10", 1.0f / -1024.f}, + {"-0x1.02p-3", 1.0f / -1024.f - 1.0f / 8.f}, - // Near lowest non-denorm - {"0x1p-124", std::ldexp(1.f * 8.f, -127)}, - {"0x1p-125", std::ldexp(1.f * 4.f, -127)}, - {"-0x1p-124", -std::ldexp(1.f * 8.f, -127)}, - {"-0x1p-125", -std::ldexp(1.f * 4.f, -127)}, + // Near lowest non-denorm + {"0x1p-124", std::ldexp(1.f * 8.f, -127)}, + {"0x1p-125", std::ldexp(1.f * 4.f, -127)}, + {"-0x1p-124", -std::ldexp(1.f * 8.f, -127)}, + {"-0x1p-125", -std::ldexp(1.f * 4.f, -127)}, - // Lowest non-denorm - {"0x1p-126", std::ldexp(1.f * 2.f, -127)}, - {"-0x1p-126", -std::ldexp(1.f * 2.f, -127)}, + // Lowest non-denorm + {"0x1p-126", std::ldexp(1.f * 2.f, -127)}, + {"-0x1p-126", -std::ldexp(1.f * 2.f, -127)}, - // Denormalized values - {"0x1p-127", std::ldexp(1.f, -127)}, - {"0x1p-128", std::ldexp(1.f / 2.f, -127)}, - {"0x1p-129", std::ldexp(1.f / 4.f, -127)}, - {"0x1p-130", std::ldexp(1.f / 8.f, -127)}, - {"-0x1p-127", -std::ldexp(1.f, -127)}, - {"-0x1p-128", -std::ldexp(1.f / 2.f, -127)}, - {"-0x1p-129", -std::ldexp(1.f / 4.f, -127)}, - {"-0x1p-130", -std::ldexp(1.f / 8.f, -127)}, + // Denormalized values + {"0x1p-127", std::ldexp(1.f, -127)}, + {"0x1p-128", std::ldexp(1.f / 2.f, -127)}, + {"0x1p-129", std::ldexp(1.f / 4.f, -127)}, + {"0x1p-130", std::ldexp(1.f / 8.f, -127)}, + {"-0x1p-127", -std::ldexp(1.f, -127)}, + {"-0x1p-128", -std::ldexp(1.f / 2.f, -127)}, + {"-0x1p-129", -std::ldexp(1.f / 4.f, -127)}, + {"-0x1p-130", -std::ldexp(1.f / 8.f, -127)}, - {"0x1.8p-127", std::ldexp(1.f, -127) + (std::ldexp(1.f, -127) / 2.f)}, - {"0x1.8p-128", std::ldexp(1.f, -127) / 2.f + (std::ldexp(1.f, -127) / 4.f)}, + {"0x1.8p-127", std::ldexp(1.f, -127) + (std::ldexp(1.f, -127) / 2.f)}, + {"0x1.8p-128", + std::ldexp(1.f, -127) / 2.f + (std::ldexp(1.f, -127) / 4.f)}, - {"0x1p-149", MakeFloat(0, 0, 1)}, // +SmallestDenormal - {"0x1p-148", MakeFloat(0, 0, 2)}, // +BiggerDenormal - {"0x1.fffffcp-127", MakeFloat(0, 0, 0x7fffff)}, // +LargestDenormal - {"-0x1p-149", MakeFloat(1, 0, 1)}, // -SmallestDenormal - {"-0x1p-148", MakeFloat(1, 0, 2)}, // -BiggerDenormal - {"-0x1.fffffcp-127", MakeFloat(1, 0, 0x7fffff)}, // -LargestDenormal + {"0x1p-149", MakeFloat(0, 0, 1)}, // +SmallestDenormal + {"0x1p-148", MakeFloat(0, 0, 2)}, // +BiggerDenormal + {"0x1.fffffcp-127", MakeFloat(0, 0, 0x7fffff)}, // +LargestDenormal + {"-0x1p-149", MakeFloat(1, 0, 1)}, // -SmallestDenormal + {"-0x1p-148", MakeFloat(1, 0, 2)}, // -BiggerDenormal + {"-0x1.fffffcp-127", MakeFloat(1, 0, 0x7fffff)}, // -LargestDenormal - {"0x1.2bfaf8p-127", MakeFloat(0, 0, 0xcafebe)}, // +Subnormal - {"-0x1.2bfaf8p-127", MakeFloat(1, 0, 0xcafebe)}, // -Subnormal - {"0x1.55554p-130", MakeFloat(0, 0, 0xaaaaa)}, // +Subnormal - {"-0x1.55554p-130", MakeFloat(1, 0, 0xaaaaa)}, // -Subnormal + {"0x1.2bfaf8p-127", MakeFloat(0, 0, 0xcafebe)}, // +Subnormal + {"-0x1.2bfaf8p-127", MakeFloat(1, 0, 0xcafebe)}, // -Subnormal + {"0x1.55554p-130", MakeFloat(0, 0, 0xaaaaa)}, // +Subnormal + {"-0x1.55554p-130", MakeFloat(1, 0, 0xaaaaa)}, // -Subnormal - // Nan -> Infinity - {"0x1.8p+128", PosInf}, - {"0x1.0002p+128", PosInf}, - {"0x1.0018p+128", PosInf}, - {"0x1.01ep+128", PosInf}, - {"0x1.fffffep+128", PosInf}, - {"-0x1.8p+128", NegInf}, - {"-0x1.0002p+128", NegInf}, - {"-0x1.0018p+128", NegInf}, - {"-0x1.01ep+128", NegInf}, - {"-0x1.fffffep+128", NegInf}, + // Nan -> Infinity + {"0x1.8p+128", PosInf}, + {"0x1.0002p+128", PosInf}, + {"0x1.0018p+128", PosInf}, + {"0x1.01ep+128", PosInf}, + {"0x1.fffffep+128", PosInf}, + {"-0x1.8p+128", NegInf}, + {"-0x1.0002p+128", NegInf}, + {"-0x1.0018p+128", NegInf}, + {"-0x1.01ep+128", NegInf}, + {"-0x1.fffffep+128", NegInf}, - // Infinity - {"0x1p+128", PosInf}, - {"-0x1p+128", NegInf}, - {"0x32p+127", PosInf}, - {"0x32p+500", PosInf}, - {"-0x32p+127", NegInf}, - {"-0x32p+500", NegInf}, + // Infinity + {"0x1p+128", PosInf}, + {"-0x1p+128", NegInf}, + {"0x32p+127", PosInf}, + {"0x32p+500", PosInf}, + {"-0x32p+127", NegInf}, + {"-0x32p+500", NegInf}, - // Overflow -> Infinity - {"0x1p+129", PosInf}, - {"0x1.1p+128", PosInf}, - {"-0x1p+129", NegInf}, - {"-0x1.1p+128", NegInf}, - {"0x1.0p2147483520", PosInf}, // INT_MAX - 127 (largest valid exponent) + // Overflow -> Infinity + {"0x1p+129", PosInf}, + {"0x1.1p+128", PosInf}, + {"-0x1p+129", NegInf}, + {"-0x1.1p+128", NegInf}, + {"0x1.0p2147483520", PosInf}, // INT_MAX - 127 (largest valid exponent) - // Underflow -> Zero - {"0x1p-500", 0.f}, // Exponent underflows - {"-0x1p-500", -0.f}, - {"0x0.00000000001p-126", 0.f}, // Fraction causes underflow - {"-0x0.0000000001p-127", -0.f}, - {"0x0.01p-142", 0.f}, - {"-0x0.01p-142", -0.f}, // Fraction causes additional underflow - {"0x1.0p-2147483520", 0}, // -(INT_MAX - 127) (smallest valid exponent) + // Underflow -> Zero + {"0x1p-500", 0.f}, // Exponent underflows + {"-0x1p-500", -0.f}, + {"0x0.00000000001p-126", 0.f}, // Fraction causes underflow + {"-0x0.0000000001p-127", -0.f}, + {"0x0.01p-142", 0.f}, + {"-0x0.01p-142", -0.f}, // Fraction causes additional underflow + {"0x1.0p-2147483520", 0}, // -(INT_MAX - 127) (smallest valid exponent) - // Zero with non-zero exponent -> Zero - {"0x0p+0", 0.f}, - {"0x0p+1", 0.f}, - {"0x0p-1", 0.f}, - {"0x0p+9999999999", 0.f}, - {"0x0p-9999999999", 0.f}, - // Same, but with very large positive exponents that would cause overflow - // if the mantissa were non-zero. - {"0x0p+4000000000", 0.f}, // 4 billion: - {"0x0p+40000000000", 0.f}, // 40 billion - {"-0x0p+40000000000", 0.f}, // As above 2, but negative mantissa - {"-0x0p+400000000000", 0.f}, - {"0x0.00p+4000000000", 0.f}, // As above 4, but with fractional part - {"0x0.00p+40000000000", 0.f}, - {"-0x0.00p+40000000000", 0.f}, - {"-0x0.00p+400000000000", 0.f}, - {"0x0p-4000000000", 0.f}, // As above 8, but with negative exponents - {"0x0p-40000000000", 0.f}, - {"-0x0p-40000000000", 0.f}, - {"-0x0p-400000000000", 0.f}, - {"0x0.00p-4000000000", 0.f}, - {"0x0.00p-40000000000", 0.f}, - {"-0x0.00p-40000000000", 0.f}, - {"-0x0.00p-400000000000", 0.f}, + // Zero with non-zero exponent -> Zero + {"0x0p+0", 0.f}, + {"0x0p+1", 0.f}, + {"0x0p-1", 0.f}, + {"0x0p+9999999999", 0.f}, + {"0x0p-9999999999", 0.f}, + // Same, but with very large positive exponents that would cause overflow + // if the mantissa were non-zero. + {"0x0p+4000000000", 0.f}, // 4 billion: + {"0x0p+40000000000", 0.f}, // 40 billion + {"-0x0p+40000000000", 0.f}, // As above 2, but negative mantissa + {"-0x0p+400000000000", 0.f}, + {"0x0.00p+4000000000", 0.f}, // As above 4, but with fractional part + {"0x0.00p+40000000000", 0.f}, + {"-0x0.00p+40000000000", 0.f}, + {"-0x0.00p+400000000000", 0.f}, + {"0x0p-4000000000", 0.f}, // As above 8, but with negative exponents + {"0x0p-40000000000", 0.f}, + {"-0x0p-40000000000", 0.f}, + {"-0x0p-400000000000", 0.f}, + {"0x0.00p-4000000000", 0.f}, + {"0x0.00p-40000000000", 0.f}, + {"-0x0.00p-40000000000", 0.f}, + {"-0x0.00p-400000000000", 0.f}, - // Test parsing - {"0x0p0", 0.f}, - {"0x0p-0", 0.f}, - {"0x0p+000", 0.f}, - {"0x00000000000000p+000000000000000", 0.f}, - {"0x00000000000000p-000000000000000", 0.f}, - {"0x00000000000001p+000000000000000", 1.f}, - {"0x00000000000001p-000000000000000", 1.f}, - {"0x0000000000000000000001.99999ap-000000000000000004", 0.1f}, - {"0x2p+0", 2.f}, - {"0xFFp+0", 255.f}, - {"0x0.8p+0", 0.5f}, - {"0x0.4p+0", 0.25f}, - {"0x0.4p+1", 2 * 0.25f}, - {"0x0.4p+2", 4 * 0.25f}, - {"0x123Ep+1", 9340.f}, - {"-0x123Ep+1", -9340.f}, - {"0x1a2b3cP12", 7.024656e+09f}, - {"-0x1a2b3cP12", -7.024656e+09f}, + // Test parsing + {"0x0p0", 0.f}, + {"0x0p-0", 0.f}, + {"0x0p+000", 0.f}, + {"0x00000000000000p+000000000000000", 0.f}, + {"0x00000000000000p-000000000000000", 0.f}, + {"0x00000000000001p+000000000000000", 1.f}, + {"0x00000000000001p-000000000000000", 1.f}, + {"0x0000000000000000000001.99999ap-000000000000000004", 0.1f}, + {"0x2p+0", 2.f}, + {"0xFFp+0", 255.f}, + {"0x0.8p+0", 0.5f}, + {"0x0.4p+0", 0.25f}, + {"0x0.4p+1", 2 * 0.25f}, + {"0x0.4p+2", 4 * 0.25f}, + {"0x123Ep+1", 9340.f}, + {"-0x123Ep+1", -9340.f}, + {"0x1a2b3cP12", 7.024656e+09f}, + {"-0x1a2b3cP12", -7.024656e+09f}, - // Examples without a binary exponent part. - {"0x1.", 1.0f}, - {"0x.8", 0.5f}, - {"0x1.8", 1.5f}, - {"-0x1.", -1.0f}, - {"-0x.8", -0.5f}, - {"-0x1.8", -1.5f}, + // Examples without a binary exponent part. + {"0x1.", 1.0f}, + {"0x.8", 0.5f}, + {"0x1.8", 1.5f}, + {"-0x1.", -1.0f}, + {"-0x.8", -0.5f}, + {"-0x1.8", -1.5f}, - // Examples with a binary exponent and a 'f' suffix. - {"0x1.p0f", 1.0f}, - {"0x.8p2f", 2.0f}, - {"0x1.8p-1f", 0.75f}, - {"0x2p-2f", 0.5f}, // No binary point - {"-0x1.p0f", -1.0f}, - {"-0x.8p2f", -2.0f}, - {"-0x1.8p-1f", -0.75f}, - {"-0x2p-2f", -0.5f}, // No binary point -}; + // Examples with a binary exponent and a 'f' suffix. + {"0x1.p0f", 1.0f}, + {"0x.8p2f", 2.0f}, + {"0x1.8p-1f", 0.75f}, + {"0x2p-2f", 0.5f}, // No binary point + {"-0x1.p0f", -1.0f}, + {"-0x.8p2f", -2.0f}, + {"-0x1.8p-1f", -0.75f}, + {"-0x2p-2f", -0.5f}, // No binary point + }; +} INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat, ParserImplFloatLiteralTest, - testing::ValuesIn(hexfloat_literal_test_cases)); + testing::ValuesIn(HexFloatCases())); + +// Now test all the same hex float cases, but with 0X instead of 0x +template +std::vector UpperCase0X(const ARR& cases) { + std::vector result; + result.reserve(cases.size()); + for (const auto& c : cases) { + result.emplace_back(c); + auto& input = result.back().input; + const auto where = input.find("0x"); + if (where != std::string::npos) { + input[where+1] = 'X'; + } + } + return result; +} + +using UpperCase0XTest = ::testing::Test; +TEST_F(UpperCase0XTest, Samples) { + const auto cases = FloatLiteralTestCaseList{ + {"absent", 0.0}, {"0x", 1.0}, {"0X", 2.0}, {"-0x", 3.0}, + {"-0X", 4.0}, {" 0x1p1", 5.0}, {" -0x1p", 6.0}, {" examine ", 7.0}}; + const auto expected = FloatLiteralTestCaseList{ + {"absent", 0.0}, {"0X", 1.0}, {"0X", 2.0}, {"-0X", 3.0}, + {"-0X", 4.0}, {" 0X1p1", 5.0}, {" -0X1p", 6.0}, {" examine ", 7.0}}; + + auto result = UpperCase0X(cases); + EXPECT_THAT(result, ::testing::ElementsAreArray(expected)); +} + +INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat_UpperCase0X, + ParserImplFloatLiteralTest, + testing::ValuesIn(UpperCase0X(HexFloatCases()))); struct InvalidLiteralTestCase { const char* input;