From a6969c435943152d70021fe6a28e5c085cd123b4 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 14 Oct 2021 21:38:01 +0000 Subject: [PATCH] wgsl-reader: Hex float exponents are optional Fixed: tint:1210 Change-Id: I4256494e3ca3f98082f360e0447d0392964073bd Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/66040 Auto-Submit: David Neto Kokoro: Kokoro Reviewed-by: Antonio Maiorano Commit-Queue: Antonio Maiorano --- src/reader/wgsl/lexer.cc | 80 +++++++++++-------- .../wgsl/parser_impl_const_literal_test.cc | 17 ++++ 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index 4bcba2f423..5437286268 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -343,7 +343,9 @@ Token Lexer::try_hex_float() { } // .? + bool hex_point = false; if (matches(end, ".")) { + hex_point = true; end++; } @@ -359,14 +361,18 @@ Token Lexer::try_hex_float() { return {}; } - // (p|P) - if (matches(end, "p") || matches(end, "P")) { + // Is the binary exponent present? It's optional. + const bool has_exponent = (matches(end, "p") || matches(end, "P")); + if (has_exponent) { end++; - } else { + } + if (!has_exponent && !hex_point) { + // It's not a hex float. At best it's a hex integer. return {}; } - // At this point, we know for sure our token is a hex float value. + // At this point, we know for sure our token is a hex float value, + // or an invalid token. // Parse integer part // [0-9a-fA-F]* @@ -423,42 +429,48 @@ Token Lexer::try_hex_float() { } } - // (+|-)? - int32_t exponent_sign = 1; - if (matches(end, "+")) { - end++; - } else if (matches(end, "-")) { - exponent_sign = -1; - end++; - } - - // Determine if the value is zero. + // Determine if the value of the mantissa is zero. // Note: it's not enough to check mantissa == 0 as we drop the initial bit, // whether it's in the integer part or the fractional part. const bool is_zero = !seen_prior_one_bits; TINT_ASSERT(Reader, !is_zero || mantissa == 0); - // Parse exponent from input - // [0-9]+ - // Allow overflow (in uint32_t) when the floating point value magnitude is - // zero. - bool has_exponent = false; - uint32_t input_exponent = 0; - while (end < len_ && isdigit(content_->data[end])) { - has_exponent = true; - auto prev_exponent = input_exponent; - input_exponent = (input_exponent * 10) + dec_value(content_->data[end]); - // Check if we've overflowed input_exponent. This only matters when - // the mantissa is non-zero. - if (!is_zero && (prev_exponent > input_exponent)) { - return {Token::Type::kError, source, - "exponent is too large for hex float"}; + // Parse the optional exponent. + // ((p|P)(\+|-)?[0-9]+)? + uint32_t input_exponent = 0; // Defaults to 0 if not present + int32_t exponent_sign = 1; + // If the 'p' part is present, the rest of the exponent must exist. + if (has_exponent) { + // Parse the rest of the exponent. + // (+|-)? + if (matches(end, "+")) { + end++; + } else if (matches(end, "-")) { + exponent_sign = -1; + end++; + } + + // Parse exponent from input + // [0-9]+ + // Allow overflow (in uint32_t) when the floating point value magnitude is + // zero. + bool has_exponent_digits = false; + while (end < len_ && isdigit(content_->data[end])) { + has_exponent_digits = true; + auto prev_exponent = input_exponent; + input_exponent = (input_exponent * 10) + dec_value(content_->data[end]); + // Check if we've overflowed input_exponent. This only matters when + // the mantissa is non-zero. + if (!is_zero && (prev_exponent > input_exponent)) { + return {Token::Type::kError, source, + "exponent is too large for hex float"}; + } + end++; + } + if (!has_exponent_digits) { + return {Token::Type::kError, source, + "expected an exponent value for hex float"}; } - end++; - } - if (!has_exponent) { - return {Token::Type::kError, source, - "expected an exponent value for hex float"}; } pos_ = end; diff --git a/src/reader/wgsl/parser_impl_const_literal_test.cc b/src/reader/wgsl/parser_impl_const_literal_test.cc index 7c6de61801..16e3472782 100644 --- a/src/reader/wgsl/parser_impl_const_literal_test.cc +++ b/src/reader/wgsl/parser_impl_const_literal_test.cc @@ -275,6 +275,14 @@ FloatLiteralTestCase hexfloat_literal_test_cases[] = { {"-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}, }; INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat, ParserImplFloatLiteralTest, @@ -326,9 +334,18 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(invalid_hexfloat_exponent_too_large_cases)); InvalidLiteralTestCase invalid_hexfloat_exponent_missing_cases[] = { + // Lower case p {"0x0p", "1:1: expected an exponent value for hex float"}, + {"0x0p+", "1:1: expected an exponent value for hex float"}, + {"0x0p-", "1:1: expected an exponent value for hex float"}, {"0x1.0p", "1:1: expected an exponent value for hex float"}, {"0x0.1p", "1:1: expected an exponent value for hex float"}, + // Upper case p + {"0x0P", "1:1: expected an exponent value for hex float"}, + {"0x0P+", "1:1: expected an exponent value for hex float"}, + {"0x0P-", "1:1: expected an exponent value for hex float"}, + {"0x1.0P", "1:1: expected an exponent value for hex float"}, + {"0x0.1P", "1:1: expected an exponent value for hex float"}, }; INSTANTIATE_TEST_SUITE_P( ParserImplInvalidLiteralTest_HexFloatExponentMissing,