tint/reader/wgsl: Lex abstract floats

And remove lexer errors about float magnitudes been too small.

Also add tests for non-hex float literal overflow.

Bug: tint:1504
Bug: tint:1564
Change-Id: Ia26817d4f2a99af694e9935692b98ef91f97d2b3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91428
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index fbaebf0..bfec1d1 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -358,31 +358,22 @@
     advance(end - start);
     end_source(source);
 
-    double value = strtod(&at(start), nullptr);
+    double value = std::strtod(&at(start), nullptr);
 
     if (has_f_suffix) {
         if (auto f = CheckedConvert<f32>(AFloat(value))) {
-            return {Token::Type::kFloatLiteral_F, source, value};
+            return {Token::Type::kFloatLiteral_F, source, static_cast<double>(f.Get())};
+        } else if (f.Failure() == ConversionFailure::kTooSmall) {
+            return {Token::Type::kFloatLiteral_F, source, 0.0};
         } else {
-            if (f.Failure() == ConversionFailure::kTooSmall) {
-                return {Token::Type::kError, source,
-                        "value magnitude too small to be represented as 'f32'"};
-            }
             return {Token::Type::kError, source, "value cannot be represented as 'f32'"};
         }
     }
 
-    // TODO(crbug.com/tint/1504): Properly support abstract float:
-    // Change `AbstractFloatType` to `double`, update errors to say 'abstract int'.
-    using AbstractFloatType = f32;
-    if (auto f = CheckedConvert<AbstractFloatType>(AFloat(value))) {
-        return {Token::Type::kFloatLiteral, source, value};
+    if (value == HUGE_VAL || -value == HUGE_VAL) {
+        return {Token::Type::kError, source, "value cannot be represented as 'abstract-float'"};
     } else {
-        if (f.Failure() == ConversionFailure::kTooSmall) {
-            return {Token::Type::kError, source,
-                    "value magnitude too small to be represented as 'f32'"};
-        }
-        return {Token::Type::kError, source, "value cannot be represented as 'f32'"};
+        return {Token::Type::kFloatLiteral, source, value};
     }
 }
 
diff --git a/src/tint/reader/wgsl/lexer_test.cc b/src/tint/reader/wgsl/lexer_test.cc
index 52f5cb8..801b62c 100644
--- a/src/tint/reader/wgsl/lexer_test.cc
+++ b/src/tint/reader/wgsl/lexer_test.cc
@@ -362,12 +362,12 @@
                              FloatData{"-5.", -5.},
                              FloatData{"-.7", -.7},
                              // Non-zero with decimal and 'f' suffix
-                             FloatData{"5.7f", 5.7},
-                             FloatData{"5.f", 5.},
-                             FloatData{".7f", .7},
-                             FloatData{"-5.7f", -5.7},
-                             FloatData{"-5.f", -5.},
-                             FloatData{"-.7f", -.7},
+                             FloatData{"5.7f", static_cast<double>(5.7f)},
+                             FloatData{"5.f", static_cast<double>(5.f)},
+                             FloatData{".7f", static_cast<double>(.7f)},
+                             FloatData{"-5.7f", static_cast<double>(-5.7f)},
+                             FloatData{"-5.f", static_cast<double>(-5.f)},
+                             FloatData{"-.7f", static_cast<double>(-.7f)},
 
                              // No decimal, with exponent
                              FloatData{"1e5", 1e5},
@@ -375,10 +375,10 @@
                              FloatData{"1e-5", 1e-5},
                              FloatData{"1E-5", 1e-5},
                              // No decimal, with exponent and 'f' suffix
-                             FloatData{"1e5f", 1e5},
-                             FloatData{"1E5f", 1e5},
-                             FloatData{"1e-5f", 1e-5},
-                             FloatData{"1E-5f", 1e-5},
+                             FloatData{"1e5f", static_cast<double>(1e5f)},
+                             FloatData{"1E5f", static_cast<double>(1e5f)},
+                             FloatData{"1e-5f", static_cast<double>(1e-5f)},
+                             FloatData{"1E-5f", static_cast<double>(1e-5f)},
                              // With decimal and exponents
                              FloatData{"0.2e+12", 0.2e12},
                              FloatData{"1.2e-5", 1.2e-5},
@@ -386,11 +386,15 @@
                              FloatData{"2.5e+0", 2.5},
                              FloatData{"2.5e-0", 2.5},
                              // With decimal and exponents and 'f' suffix
-                             FloatData{"0.2e+12f", 0.2e12},
-                             FloatData{"1.2e-5f", 1.2e-5},
-                             FloatData{"2.57e23f", 2.57e23},
-                             FloatData{"2.5e+0f", 2.5},
-                             FloatData{"2.5e-0f", 2.5}));
+                             FloatData{"0.2e+12f", static_cast<double>(0.2e12f)},
+                             FloatData{"1.2e-5f", static_cast<double>(1.2e-5f)},
+                             FloatData{"2.57e23f", static_cast<double>(2.57e23f)},
+                             FloatData{"2.5e+0f", static_cast<double>(2.5f)},
+                             FloatData{"2.5e-0f", static_cast<double>(2.5f)},
+                             // Quantization
+                             FloatData{"3.141592653589793", 3.141592653589793},   // no quantization
+                             FloatData{"3.141592653589793f", 3.1415927410125732}  // f32 quantized
+                             ));
 
 using FloatTest_Invalid = testing::TestWithParam<const char*>;
 TEST_P(FloatTest_Invalid, Handles) {
@@ -415,11 +419,11 @@
                                          ".e+",
                                          ".e-",
                                          // Overflow
-                                         "2.5e+256",
-                                         "-2.5e+127",
+                                         "2.5e+256f",
+                                         "-2.5e+127f",
                                          // Magnitude smaller than smallest positive f32.
-                                         "2.5e-300",
-                                         "-2.5e-300",
+                                         "2.5e-300f",
+                                         "-2.5e-300f",
                                          // Decimal exponent must immediately
                                          // follow the 'e'.
                                          "2.5e 12",
diff --git a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
index 5d882ca..8ce5178 100644
--- a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
@@ -117,34 +117,6 @@
     ASSERT_EQ(c.value, nullptr);
 }
 
-TEST_F(ParserImplTest, ConstLiteral_Float) {
-    auto p = parser("234.e12");
-    auto c = p->const_literal();
-    EXPECT_TRUE(c.matched);
-    EXPECT_FALSE(c.errored);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(c.value, nullptr);
-    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-    EXPECT_DOUBLE_EQ(c->As<ast::FloatLiteralExpression>()->value, 234e12);
-    EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
-              ast::FloatLiteralExpression::Suffix::kNone);
-    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, ConstLiteral_FloatF) {
-    auto p = parser("234.e12f");
-    auto c = p->const_literal();
-    EXPECT_TRUE(c.matched);
-    EXPECT_FALSE(c.errored);
-    EXPECT_FALSE(p->has_error()) << p->error();
-    ASSERT_NE(c.value, nullptr);
-    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-    EXPECT_DOUBLE_EQ(c->As<ast::FloatLiteralExpression>()->value, 234e12);
-    EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
-              ast::FloatLiteralExpression::Suffix::kF);
-    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 9u}}));
-}
-
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_IncompleteExponent) {
     auto p = parser("1.0e+");
     auto c = p->const_literal();
@@ -154,33 +126,6 @@
     ASSERT_EQ(c.value, nullptr);
 }
 
-TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooSmallMagnitude) {
-    auto p = parser("1e-256");
-    auto c = p->const_literal();
-    EXPECT_FALSE(c.matched);
-    EXPECT_TRUE(c.errored);
-    EXPECT_EQ(p->error(), "1:1: value magnitude too small to be represented as 'f32'");
-    ASSERT_EQ(c.value, nullptr);
-}
-
-TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooLargeNegative) {
-    auto p = parser("-1.2e+256");
-    auto c = p->const_literal();
-    EXPECT_FALSE(c.matched);
-    EXPECT_TRUE(c.errored);
-    EXPECT_EQ(p->error(), "1:1: value cannot be represented as 'f32'");
-    ASSERT_EQ(c.value, nullptr);
-}
-
-TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooLargePositive) {
-    auto p = parser("1.2e+256");
-    auto c = p->const_literal();
-    EXPECT_FALSE(c.matched);
-    EXPECT_TRUE(c.errored);
-    EXPECT_EQ(p->error(), "1:1: value cannot be represented as 'f32'");
-    ASSERT_EQ(c.value, nullptr);
-}
-
 struct FloatLiteralTestCase {
     std::string input;
     double expected;
@@ -217,26 +162,54 @@
         EXPECT_EQ(c->As<ast::FloatLiteralExpression>()->suffix,
                   ast::FloatLiteralExpression::Suffix::kNone);
     }
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 1u + params.input.size()}}));
 }
 using FloatLiteralTestCaseList = std::vector<FloatLiteralTestCase>;
 
-FloatLiteralTestCaseList DecimalFloatCases() {
-    return FloatLiteralTestCaseList{
-        {"0.0", 0.0},                        // Zero
-        {"1.0", 1.0},                        // One
-        {"-1.0", -1.0},                      // MinusOne
-        {"1000000000.0", 1e9},               // Billion
-        {"-0.0", std::copysign(0.0, -5.0)},  // NegativeZero
-        {"0.0", MakeDouble(0, 0, 0)},        // Zero
-        {"-0.0", MakeDouble(1, 0, 0)},       // NegativeZero
-        {"1.0", MakeDouble(0, 1023, 0)},     // One
-        {"-1.0", MakeDouble(1, 1023, 0)},    // NegativeOne
-    };
-}
-
 INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float,
                          ParserImplFloatLiteralTest,
-                         testing::ValuesIn(DecimalFloatCases()));
+                         testing::ValuesIn(FloatLiteralTestCaseList{
+                             {"0.0", 0.0},                        // Zero
+                             {"1.0", 1.0},                        // One
+                             {"-1.0", -1.0},                      // MinusOne
+                             {"1000000000.0", 1e9},               // Billion
+                             {"-0.0", std::copysign(0.0, -5.0)},  // NegativeZero
+                             {"0.0", MakeDouble(0, 0, 0)},        // Zero
+                             {"-0.0", MakeDouble(1, 0, 0)},       // NegativeZero
+                             {"1.0", MakeDouble(0, 1023, 0)},     // One
+                             {"-1.0", MakeDouble(1, 1023, 0)},    // NegativeOne
+
+                             {"234.e12", 234.e12},
+                             {"234.e12f", static_cast<double>(234.e12f)},
+
+                             // Tiny cases
+                             {"1e-5000", 0.0},
+                             {"-1e-5000", 0.0},
+                             {"1e-5000f", 0.0},
+                             {"-1e-5000f", 0.0},
+                             {"1e-50f", 0.0},
+                             {"-1e-50f", 0.0},
+
+                             // Nearly overflow
+                             {"1.e308", 1.e308},
+                             {"-1.e308", -1.e308},
+                             {"1.8e307", 1.8e307},
+                             {"-1.8e307", -1.8e307},
+                             {"1.798e307", 1.798e307},
+                             {"-1.798e307", -1.798e307},
+                             {"1.7977e307", 1.7977e307},
+                             {"-1.7977e307", -1.7977e307},
+
+                             // Nearly overflow
+                             {"1e38f", static_cast<double>(1e38f)},
+                             {"-1e38f", static_cast<double>(-1e38f)},
+                             {"4.0e37f", static_cast<double>(4.0e37f)},
+                             {"-4.0e37f", static_cast<double>(-4.0e37f)},
+                             {"3.5e37f", static_cast<double>(3.5e37f)},
+                             {"-3.5e37f", static_cast<double>(-3.5e37f)},
+                             {"3.403e37f", static_cast<double>(3.403e37f)},
+                             {"-3.403e37f", static_cast<double>(-3.403e37f)},
+                         }));
 
 const double NegInf = MakeDouble(1, 0x7FF, 0);
 const double PosInf = MakeDouble(0, 0x7FF, 0);
@@ -535,7 +508,7 @@
                      })));
 
 INSTANTIATE_TEST_SUITE_P(
-    NaNAFloat,
+    HexNaNAFloat,
     ParserImplInvalidLiteralTest,
     testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),
                      testing::ValuesIn(std::vector<const char*>{
@@ -552,7 +525,7 @@
                      })));
 
 INSTANTIATE_TEST_SUITE_P(
-    NaNF32,
+    HexNaNF32,
     ParserImplInvalidLiteralTest,
     testing::Combine(testing::Values("1:1: value cannot be represented as 'f32'"),
                      testing::ValuesIn(std::vector<const char*>{
@@ -569,7 +542,7 @@
                      })));
 
 INSTANTIATE_TEST_SUITE_P(
-    OverflowAFloat,
+    HexOverflowAFloat,
     ParserImplInvalidLiteralTest,
     testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),
                      testing::ValuesIn(std::vector<const char*>{
@@ -588,7 +561,7 @@
                      })));
 
 INSTANTIATE_TEST_SUITE_P(
-    OverflowF32,
+    HexOverflowF32,
     ParserImplInvalidLiteralTest,
     testing::Combine(testing::Values("1:1: value cannot be represented as 'f32'"),
                      testing::ValuesIn(std::vector<const char*>{
@@ -604,6 +577,40 @@
                          "-0x32p+500f",
                      })));
 
+INSTANTIATE_TEST_SUITE_P(
+    DecOverflowAFloat,
+    ParserImplInvalidLiteralTest,
+    testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),
+                     testing::ValuesIn(std::vector<const char*>{
+                         "1.e309",
+                         "-1.e309",
+                         "1.8e308",
+                         "-1.8e308",
+                         "1.798e308",
+                         "-1.798e308",
+                         "1.7977e308",
+                         "-1.7977e308",
+                         "1.2e+5000",
+                         "-1.2e+5000",
+                     })));
+
+INSTANTIATE_TEST_SUITE_P(
+    DecOverflowF32,
+    ParserImplInvalidLiteralTest,
+    testing::Combine(testing::Values("1:1: value cannot be represented as 'f32'"),
+                     testing::ValuesIn(std::vector<const char*>{
+                         "1e39f",
+                         "-1e39f",
+                         "4.0e38f",
+                         "-4.0e38f",
+                         "3.5e38f",
+                         "-3.5e38f",
+                         "3.403e38f",
+                         "-3.403e38f",
+                         "1.2e+256f",
+                         "-1.2e+256f",
+                     })));
+
 TEST_F(ParserImplTest, ConstLiteral_FloatHighest) {
     const auto highest = std::numeric_limits<float>::max();
     const auto expected_highest = 340282346638528859811704183484516925440.0f;