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 <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index 4bcba2f..5437286 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -343,7 +343,9 @@
}
// .?
+ bool hex_point = false;
if (matches(end, ".")) {
+ hex_point = true;
end++;
}
@@ -359,14 +361,18 @@
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 @@
}
}
- // (+|-)?
- 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++;
}
- end++;
- }
- if (!has_exponent) {
- return {Token::Type::kError, source,
- "expected an exponent value for hex float"};
+
+ // 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"};
+ }
}
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 7c6de61..16e3472 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 @@
{"-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 @@
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,