wsgl parser: Use expect_[nonzero_]uint()

Keeps error message consistent. Reduces code.

Bug: tint:282
Change-Id: If89265dfe4356468d610dab931c906aa3260ce5a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31728
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index ca6274e..2a63c4a 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -437,17 +437,16 @@
   if (t.IsLocation()) {
     next();  // consume the peek
 
-    if (!expect("location decoration", Token::Type::kParenLeft))
+    const char* use = "location decoration";
+
+    if (!expect(use, Token::Type::kParenLeft))
       return nullptr;
 
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "invalid value for location decoration");
-      return {};
-    }
-    int32_t val = t.to_i32();
+    uint32_t val;
+    if (!expect_positive_sint(use, &val))
+      return nullptr;
 
-    if (!expect("location decoration", Token::Type::kParenRight))
+    if (!expect(use, Token::Type::kParenRight))
       return nullptr;
 
     return std::make_unique<ast::LocationDecoration>(val, source);
@@ -478,17 +477,16 @@
   if (t.IsBinding()) {
     next();  // consume the peek
 
-    if (!expect("binding decoration", Token::Type::kParenLeft))
+    const char* use = "binding decoration";
+
+    if (!expect(use, Token::Type::kParenLeft))
       return nullptr;
 
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "invalid value for binding decoration");
-      return {};
-    }
-    int32_t val = t.to_i32();
+    uint32_t val;
+    if (!expect_positive_sint(use, &val))
+      return nullptr;
 
-    if (!expect("binding decoration", Token::Type::kParenRight))
+    if (!expect(use, Token::Type::kParenRight))
       return nullptr;
 
     return std::make_unique<ast::BindingDecoration>(val, source);
@@ -496,17 +494,16 @@
   if (t.IsSet()) {
     next();  // consume the peek
 
-    if (!expect("set decoration", Token::Type::kParenLeft))
+    const char* use = "set decoration";
+
+    if (!expect(use, Token::Type::kParenLeft))
       return nullptr;
 
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "invalid value for set decoration");
-      return {};
-    }
-    uint32_t val = t.to_i32();
+    uint32_t val;
+    if (!expect_positive_sint(use, &val))
+      return nullptr;
 
-    if (!expect("set decoration", Token::Type::kParenRight))
+    if (!expect(use, Token::Type::kParenRight))
       return nullptr;
 
     return std::make_unique<ast::SetDecoration>(val, source);
@@ -1145,7 +1142,8 @@
     return nullptr;
   }
   if (t.IsArray()) {
-    return type_decl_array(t, std::move(decos));
+    next();  // Consume the peek
+    return type_decl_array(std::move(decos));
   }
   if (t.IsMat2x2() || t.IsMat2x3() || t.IsMat2x4() || t.IsMat3x2() ||
       t.IsMat3x3() || t.IsMat3x4() || t.IsMat4x2() || t.IsMat4x3() ||
@@ -1238,15 +1236,11 @@
       std::make_unique<ast::type::VectorType>(subtype, count));
 }
 
-ast::type::Type* ParserImpl::type_decl_array(Token t,
-                                             ast::ArrayDecorationList decos) {
-  next();  // Consume the peek
+ast::type::Type* ParserImpl::type_decl_array(ast::ArrayDecorationList decos) {
+  const char* use = "array declaration";
 
-  t = next();
-  if (!t.IsLessThan()) {
-    add_error(t, "missing < for array declaration");
+  if (!expect(use, Token::Type::kLessThan))
     return nullptr;
-  }
 
   auto* subtype = type_decl();
   if (has_error())
@@ -1256,25 +1250,14 @@
     return nullptr;
   }
 
-  t = next();
   uint32_t size = 0;
-  if (t.IsComma()) {
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "missing size of array declaration");
+  if (match(Token::Type::kComma)) {
+    if (!expect_nonzero_positive_sint("array size", &size))
       return nullptr;
-    }
-    if (t.to_i32() <= 0) {
-      add_error(t, "invalid size for array declaration");
-      return nullptr;
-    }
-    size = static_cast<uint32_t>(t.to_i32());
-    t = next();
   }
-  if (!t.IsGreaterThan()) {
-    add_error(t, "missing > for array declaration");
+
+  if (!expect(use, Token::Type::kGreaterThan))
     return nullptr;
-  }
 
   auto ty = std::make_unique<ast::type::ArrayType>(subtype, size);
   ty->set_decorations(std::move(decos));
@@ -1301,45 +1284,35 @@
   next();  // consume the peek of [[
 
   for (;;) {
-    t = next();
+    auto source = peek().source();
 
-    auto source = t.source();
-
-    if (!t.IsStride()) {
-      add_error(t, "unknown array decoration");
+    if (!match(Token::Type::kStride)) {
+      add_error(source, "unknown array decoration");
       return false;
     }
 
-    if (!expect("stride decoration", Token::Type::kParenLeft))
+    const char* use = "stride decoration";
+
+    if (!expect(use, Token::Type::kParenLeft))
       return false;
 
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "missing value for stride decoration");
+    uint32_t stride;
+    if (!expect_nonzero_positive_sint(use, &stride))
       return false;
-    }
-    if (t.to_i32() < 0) {
-      add_error(t, "invalid stride value: " + t.to_str());
-      return false;
-    }
-    uint32_t stride = static_cast<uint32_t>(t.to_i32());
+
     decos.push_back(std::make_unique<ast::StrideDecoration>(stride, source));
 
-    if (!expect("stride decoration", Token::Type::kParenRight))
+    if (!expect(use, Token::Type::kParenRight))
       return false;
 
-    t = peek();
-    if (!t.IsComma()) {
+    if (!match(Token::Type::kComma))
       break;
-    }
-    next();  // Consume the peek
   }
 
-  t = next();
-  if (!t.IsAttrRight()) {
-    add_error(t, "missing ]] for array decoration");
+  if (!expect("array decoration", Token::Type::kAttrRight)) {
     return false;
   }
+
   return true;
 }
 
@@ -1630,29 +1603,21 @@
 //   : OFFSET PAREN_LEFT INT_LITERAL PAREN_RIGHT
 std::unique_ptr<ast::StructMemberDecoration>
 ParserImpl::struct_member_decoration() {
-  auto t = peek();
-  if (!t.IsOffset())
+  auto source = peek().source();
+
+  if (!match(Token::Type::kOffset))
     return nullptr;
 
-  auto source = t.source();
+  const char* use = "offset decoration";
 
-  next();  // Consume the peek
-
-  if (!expect("offset decoration", Token::Type::kParenLeft))
+  if (!expect(use, Token::Type::kParenLeft))
     return nullptr;
 
-  t = next();
-  if (!t.IsSintLiteral()) {
-    add_error(t, "invalid value for offset decoration");
+  uint32_t val;
+  if (!expect_positive_sint(use, &val))
     return nullptr;
-  }
-  int32_t val = t.to_i32();
-  if (val < 0) {
-    add_error(t, "offset value must be >= 0");
-    return nullptr;
-  }
 
-  if (!expect("offset decoration", Token::Type::kParenRight))
+  if (!expect(use, Token::Type::kParenRight))
     return nullptr;
 
   return std::make_unique<ast::StructMemberOffsetDecoration>(val, source);
@@ -1754,55 +1719,30 @@
   if (t.IsWorkgroupSize()) {
     next();  // Consume the peek
 
-    if (!expect("workgroup_size decoration", Token::Type::kParenLeft))
+    const char* use = "workgroup_size decoration";
+
+    if (!expect(use, Token::Type::kParenLeft))
       return nullptr;
 
-    t = next();
-    if (!t.IsSintLiteral()) {
-      add_error(t, "missing x value for workgroup_size");
+    uint32_t x;
+    if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) {
       return nullptr;
     }
-    if (t.to_i32() <= 0) {
-      add_error(t, "invalid value for workgroup_size x parameter");
-      return nullptr;
-    }
-    int32_t x = t.to_i32();
-    int32_t y = 1;
-    int32_t z = 1;
 
-    t = peek();
-    if (t.IsComma()) {
-      next();  // Consume the peek
-
-      t = next();
-      if (!t.IsSintLiteral()) {
-        add_error(t, "missing y value for workgroup_size");
+    uint32_t y = 1;
+    uint32_t z = 1;
+    if (match(Token::Type::kComma)) {
+      if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) {
         return nullptr;
       }
-      if (t.to_i32() <= 0) {
-        add_error(t, "invalid value for workgroup_size y parameter");
-        return nullptr;
-      }
-      y = t.to_i32();
-
-      t = peek();
-      if (t.IsComma()) {
-        next();  // Consume the peek
-
-        t = next();
-        if (!t.IsSintLiteral()) {
-          add_error(t, "missing z value for workgroup_size");
+      if (match(Token::Type::kComma)) {
+        if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) {
           return nullptr;
         }
-        if (t.to_i32() <= 0) {
-          add_error(t, "invalid value for workgroup_size z parameter");
-          return nullptr;
-        }
-        z = t.to_i32();
       }
     }
 
-    if (!expect("workgroup_size decoration", Token::Type::kParenRight))
+    if (!expect(use, Token::Type::kParenRight))
       return nullptr;
 
     return std::make_unique<ast::WorkgroupDecoration>(uint32_t(x), uint32_t(y),
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 0cf0903..8156017 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -466,7 +466,7 @@
 
   ast::type::Type* type_decl_pointer(Token t);
   ast::type::Type* type_decl_vector(Token t);
-  ast::type::Type* type_decl_array(Token t, ast::ArrayDecorationList decos);
+  ast::type::Type* type_decl_array(ast::ArrayDecorationList decos);
   bool array_decoration_list(ast::ArrayDecorationList& decos);
   ast::type::Type* type_decl_matrix(Token t);
 
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index 7e0e446..73b61d7 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -310,46 +310,76 @@
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeXInvalid) {
   EXPECT("[[workgroup_size(x)]] fn f() -> void {}",
-         "test.wgsl:1:18 error: missing x value for workgroup_size\n"
+         "test.wgsl:1:18 error: expected signed integer literal for "
+         "workgroup_size x parameter\n"
          "[[workgroup_size(x)]] fn f() -> void {}\n"
          "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeXNegative) {
   EXPECT("[[workgroup_size(-1)]] fn f() -> void {}",
-         "test.wgsl:1:18 error: invalid value for workgroup_size x parameter\n"
+         "test.wgsl:1:18 error: workgroup_size x parameter must be greater "
+         "than 0\n"
          "[[workgroup_size(-1)]] fn f() -> void {}\n"
          "                 ^^\n");
 }
 
+TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeXZero) {
+  EXPECT("[[workgroup_size(0)]] fn f() -> void {}",
+         "test.wgsl:1:18 error: workgroup_size x parameter must be greater "
+         "than 0\n"
+         "[[workgroup_size(0)]] fn f() -> void {}\n"
+         "                 ^\n");
+}
+
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeYInvalid) {
   EXPECT("[[workgroup_size(1, x)]] fn f() -> void {}",
-         "test.wgsl:1:21 error: missing y value for workgroup_size\n"
+         "test.wgsl:1:21 error: expected signed integer literal for "
+         "workgroup_size y parameter\n"
          "[[workgroup_size(1, x)]] fn f() -> void {}\n"
          "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeYNegative) {
   EXPECT("[[workgroup_size(1, -1)]] fn f() -> void {}",
-         "test.wgsl:1:21 error: invalid value for workgroup_size y parameter\n"
+         "test.wgsl:1:21 error: workgroup_size y parameter must be greater "
+         "than 0\n"
          "[[workgroup_size(1, -1)]] fn f() -> void {}\n"
          "                    ^^\n");
 }
 
+TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeYZero) {
+  EXPECT("[[workgroup_size(1, 0)]] fn f() -> void {}",
+         "test.wgsl:1:21 error: workgroup_size y parameter must be greater "
+         "than 0\n"
+         "[[workgroup_size(1, 0)]] fn f() -> void {}\n"
+         "                    ^\n");
+}
+
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeZInvalid) {
   EXPECT("[[workgroup_size(1, 2, x)]] fn f() -> void {}",
-         "test.wgsl:1:24 error: missing z value for workgroup_size\n"
+         "test.wgsl:1:24 error: expected signed integer literal for "
+         "workgroup_size z parameter\n"
          "[[workgroup_size(1, 2, x)]] fn f() -> void {}\n"
          "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeZNegative) {
   EXPECT("[[workgroup_size(1, 2, -1)]] fn f() -> void {}",
-         "test.wgsl:1:24 error: invalid value for workgroup_size z parameter\n"
+         "test.wgsl:1:24 error: workgroup_size z parameter must be greater "
+         "than 0\n"
          "[[workgroup_size(1, 2, -1)]] fn f() -> void {}\n"
          "                       ^^\n");
 }
 
+TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeZZero) {
+  EXPECT("[[workgroup_size(1, 2, 0)]] fn f() -> void {}",
+         "test.wgsl:1:24 error: workgroup_size z parameter must be greater "
+         "than 0\n"
+         "[[workgroup_size(1, 2, 0)]] fn f() -> void {}\n"
+         "                       ^\n");
+}
+
 TEST_F(ParserImplErrorTest, FunctionDeclMissingIdentifier) {
   EXPECT("fn () -> void {}",
          "test.wgsl:1:4 error: missing identifier for function\n"
@@ -652,14 +682,15 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetInvaldValue) {
   EXPECT("struct S { [[offset(x)]] i : i32 };",
-         "test.wgsl:1:21 error: invalid value for offset decoration\n"
+         "test.wgsl:1:21 error: expected signed integer literal for offset "
+         "decoration\n"
          "struct S { [[offset(x)]] i : i32 };\n"
          "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetNegativeValue) {
   EXPECT("struct S { [[offset(-2)]] i : i32 };",
-         "test.wgsl:1:21 error: offset value must be >= 0\n"
+         "test.wgsl:1:21 error: offset decoration must be positive\n"
          "struct S { [[offset(-2)]] i : i32 };\n"
          "                    ^^\n");
 }
@@ -708,14 +739,14 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingLessThan) {
   EXPECT("var i : array;",
-         "test.wgsl:1:14 error: missing < for array declaration\n"
+         "test.wgsl:1:14 error: expected '<' for array declaration\n"
          "var i : array;\n"
          "             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
   EXPECT("var i : array<u32, 3;",
-         "test.wgsl:1:21 error: missing > for array declaration\n"
+         "test.wgsl:1:21 error: expected '>' for array declaration\n"
          "var i : array<u32, 3;\n"
          "                    ^\n");
 }
@@ -729,7 +760,7 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoMissingEnd) {
   EXPECT("var i : [[stride(1) array<i32>;",
-         "test.wgsl:1:21 error: missing ]] for array decoration\n"
+         "test.wgsl:1:21 error: expected ']]' for array decoration\n"
          "var i : [[stride(1) array<i32>;\n"
          "                    ^^^^^\n");
 }
@@ -750,14 +781,15 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideInvalid) {
   EXPECT("var i : [[stride(x)]] array<i32>;",
-         "test.wgsl:1:18 error: missing value for stride decoration\n"
+         "test.wgsl:1:18 error: expected signed integer literal for stride "
+         "decoration\n"
          "var i : [[stride(x)]] array<i32>;\n"
          "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideNegative) {
   EXPECT("var i : [[stride(-1)]] array<i32>;",
-         "test.wgsl:1:18 error: invalid stride value: -1\n"
+         "test.wgsl:1:18 error: stride decoration must be greater than 0\n"
          "var i : [[stride(-1)]] array<i32>;\n"
          "                 ^^\n");
 }
@@ -770,15 +802,16 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
-  EXPECT("var i : array<u32, x>;",
-         "test.wgsl:1:20 error: missing size of array declaration\n"
-         "var i : array<u32, x>;\n"
-         "                   ^\n");
+  EXPECT(
+      "var i : array<u32, x>;",
+      "test.wgsl:1:20 error: expected signed integer literal for array size\n"
+      "var i : array<u32, x>;\n"
+      "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayNegativeSize) {
   EXPECT("var i : array<u32, -3>;",
-         "test.wgsl:1:20 error: invalid size for array declaration\n"
+         "test.wgsl:1:20 error: array size must be greater than 0\n"
          "var i : array<u32, -3>;\n"
          "                   ^^\n");
 }
@@ -827,7 +860,8 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoLocationInvalidValue) {
   EXPECT("[[location(x)]] var i : i32;",
-         "test.wgsl:1:12 error: invalid value for location decoration\n"
+         "test.wgsl:1:12 error: expected signed integer literal for location "
+         "decoration\n"
          "[[location(x)]] var i : i32;\n"
          "           ^\n");
 }
@@ -876,7 +910,8 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingInvalidValue) {
   EXPECT("[[binding(x)]] var i : i32;",
-         "test.wgsl:1:11 error: invalid value for binding decoration\n"
+         "test.wgsl:1:11 error: expected signed integer literal for binding "
+         "decoration\n"
          "[[binding(x)]] var i : i32;\n"
          "          ^\n");
 }
@@ -897,7 +932,8 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingSetValue) {
   EXPECT("[[set(x)]] var i : i32;",
-         "test.wgsl:1:7 error: invalid value for set decoration\n"
+         "test.wgsl:1:7 error: expected signed integer literal for set "
+         "decoration\n"
          "[[set(x)]] var i : i32;\n"
          "      ^\n");
 }
diff --git a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
index 9717eed..77c1fbc 100644
--- a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc
@@ -81,7 +81,9 @@
   ast::FunctionDecorationList decos;
   ASSERT_FALSE(p->function_decoration_decl(decos));
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:18: missing x value for workgroup_size");
+  ASSERT_EQ(
+      p->error(),
+      "1:18: expected signed integer literal for workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecorationList_MissingRightAttr) {
diff --git a/src/reader/wgsl/parser_impl_function_decoration_test.cc b/src/reader/wgsl/parser_impl_function_decoration_test.cc
index 5e8ae5b..0ab58b2 100644
--- a/src/reader/wgsl/parser_impl_function_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_function_decoration_test.cc
@@ -84,7 +84,8 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: invalid value for workgroup_size x parameter");
+  EXPECT_EQ(p->error(),
+            "1:16: workgroup_size x parameter must be greater than 0");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) {
@@ -92,7 +93,8 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:19: invalid value for workgroup_size y parameter");
+  EXPECT_EQ(p->error(),
+            "1:19: workgroup_size y parameter must be greater than 0");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) {
@@ -100,7 +102,8 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:22: invalid value for workgroup_size z parameter");
+  EXPECT_EQ(p->error(),
+            "1:22: workgroup_size z parameter must be greater than 0");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingLeftParam) {
@@ -124,7 +127,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: missing x value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:16: expected signed integer literal for workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) {
@@ -132,7 +137,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: missing x value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:16: expected signed integer literal for workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Comma) {
@@ -148,7 +155,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:19: missing y value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:19: expected signed integer literal for workgroup_size y parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Comma) {
@@ -164,7 +173,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:22: missing z value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:22: expected signed integer literal for workgroup_size z parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) {
@@ -172,7 +183,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: missing x value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:16: expected signed integer literal for workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) {
@@ -180,7 +193,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:19: missing y value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:19: expected signed integer literal for workgroup_size y parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) {
@@ -188,7 +203,9 @@
   auto deco = p->function_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:22: missing z value for workgroup_size");
+  EXPECT_EQ(
+      p->error(),
+      "1:22: expected signed integer literal for workgroup_size z parameter");
 }
 
 TEST_F(ParserImplTest, FunctionDecoration_Stage) {
diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc
index fc41e26..34a7dbb 100644
--- a/src/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_decl_test.cc
@@ -157,7 +157,7 @@
 TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
   auto* p = parser("struct A { b: i32; c: f32;};");
   p->global_decl();
-  ASSERT_FALSE(p->has_error());
+  ASSERT_FALSE(p->has_error()) << p->error();
 
   auto m = p->module();
   ASSERT_EQ(m.constructed_types().size(), 1u);
@@ -175,7 +175,7 @@
   auto* p =
       parser("struct A { [[offset(0)]] data: [[stride(4)]] array<f32>; };");
   p->global_decl();
-  ASSERT_FALSE(p->has_error());
+  ASSERT_FALSE(p->has_error()) << p->error();
 
   auto m = p->module();
   ASSERT_EQ(m.constructed_types().size(), 1u);
@@ -199,7 +199,7 @@
 TEST_F(ParserImplTest, GlobalDecl_Struct_WithDecoration) {
   auto* p = parser("[[block]] struct A { [[offset(0)]] data: f32; };");
   p->global_decl();
-  ASSERT_FALSE(p->has_error());
+  ASSERT_FALSE(p->has_error()) << p->error();
 
   auto m = p->module();
   ASSERT_EQ(m.constructed_types().size(), 1u);
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index d6b74c5..4339900 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -125,7 +125,8 @@
   auto e = p->global_variable_decl();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(e, nullptr);
-  EXPECT_EQ(p->error(), "1:11: invalid value for binding decoration");
+  EXPECT_EQ(p->error(),
+            "1:11: expected signed integer literal for binding decoration");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
diff --git a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
index 93d0975..38e8c75 100644
--- a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
@@ -51,7 +51,8 @@
 })");
   auto m = p->struct_body_decl();
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "3:12: invalid value for offset decoration");
+  EXPECT_EQ(p->error(),
+            "3:12: expected signed integer literal for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
index af0f721..f15b14a 100644
--- a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
@@ -52,7 +52,8 @@
   ast::StructMemberDecorationList decos;
   ASSERT_FALSE(p->struct_member_decoration_decl(decos));
   ASSERT_TRUE(p->has_error()) << p->error();
-  EXPECT_EQ(p->error(), "1:10: invalid value for offset decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) {
diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
index a6d2ff7..da419e2 100644
--- a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
@@ -54,7 +54,8 @@
   auto deco = p->struct_member_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: invalid value for offset decoration");
+  EXPECT_EQ(p->error(),
+            "1:8: expected signed integer literal for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) {
@@ -62,7 +63,8 @@
   auto deco = p->struct_member_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: invalid value for offset decoration");
+  EXPECT_EQ(p->error(),
+            "1:8: expected signed integer literal for offset decoration");
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc
index 4c2c3a6..ad3ce9f 100644
--- a/src/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_test.cc
@@ -90,7 +90,8 @@
   auto m = p->struct_member();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(m, nullptr);
-  EXPECT_EQ(p->error(), "1:10: invalid value for offset decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructMember_InvalidVariable) {
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index 55e9cd3..ce95238 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -53,7 +53,7 @@
   p->register_constructed("A", alias_type);
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, alias_type);
   ASSERT_TRUE(t->IsAlias());
 
@@ -77,7 +77,7 @@
   auto* bool_type = tm()->Get(std::make_unique<ast::type::BoolType>());
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, bool_type);
   ASSERT_TRUE(t->IsBool());
 }
@@ -88,7 +88,7 @@
   auto* float_type = tm()->Get(std::make_unique<ast::type::F32Type>());
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, float_type);
   ASSERT_TRUE(t->IsF32());
 }
@@ -99,7 +99,7 @@
   auto* int_type = tm()->Get(std::make_unique<ast::type::I32Type>());
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, int_type);
   ASSERT_TRUE(t->IsI32());
 }
@@ -110,7 +110,7 @@
   auto* uint_type = tm()->Get(std::make_unique<ast::type::U32Type>());
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, uint_type);
   ASSERT_TRUE(t->IsU32());
 }
@@ -130,7 +130,7 @@
   auto params = GetParam();
   auto* p = parser(params.input);
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
   EXPECT_TRUE(t->IsVector());
   EXPECT_EQ(t->AsVector()->size(), params.count);
@@ -300,7 +300,7 @@
 TEST_F(ParserImplTest, TypeDecl_Array) {
   auto* p = parser("array<f32, 5>");
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
   ASSERT_TRUE(t->IsArray());
 
@@ -391,7 +391,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: missing ]] for array decoration");
+  EXPECT_EQ(p->error(), "1:14: expected ']]' for array decoration");
 }
 
 // Note, this isn't an error because it could be a struct decoration, we just
@@ -424,7 +424,8 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: missing value for stride decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for stride decoration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
@@ -432,7 +433,8 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: missing value for stride decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for stride decoration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) {
@@ -440,13 +442,13 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: invalid stride value: -1");
+  EXPECT_EQ(p->error(), "1:10: stride decoration must be greater than 0");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
   auto* p = parser("array<u32>");
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
   ASSERT_TRUE(t->IsArray());
 
@@ -468,7 +470,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
+  ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
@@ -476,7 +478,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
+  ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
@@ -484,7 +486,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:12: missing size of array declaration");
+  ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
@@ -492,7 +494,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:7: missing < for array declaration");
+  ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
@@ -500,7 +502,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:10: missing > for array declaration");
+  ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
@@ -508,7 +510,7 @@
   auto* t = p->type_decl();
   ASSERT_EQ(t, nullptr);
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:11: missing > for array declaration");
+  ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
 }
 
 struct MatrixData {
@@ -527,7 +529,7 @@
   auto params = GetParam();
   auto* p = parser(params.input);
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   ASSERT_FALSE(p->has_error());
   EXPECT_TRUE(t->IsMatrix());
   auto* mat = t->AsMatrix();
@@ -642,7 +644,7 @@
       ast::type::SamplerKind::kSampler));
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, type);
   ASSERT_TRUE(t->IsSampler());
   ASSERT_FALSE(t->AsSampler()->IsComparison());
@@ -656,7 +658,7 @@
       ast::type::TextureDimension::kCube, &f32));
 
   auto* t = p->type_decl();
-  ASSERT_NE(t, nullptr);
+  ASSERT_NE(t, nullptr) << p->error();
   EXPECT_EQ(t, type);
   ASSERT_TRUE(t->IsTexture());
   ASSERT_TRUE(t->AsTexture()->IsSampled());
diff --git a/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc
index 7ab0f83..215e202 100644
--- a/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc
@@ -72,7 +72,8 @@
   ast::VariableDecorationList decos;
   EXPECT_FALSE(p->variable_decoration_list(decos));
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:12: invalid value for location decoration");
+  ASSERT_EQ(p->error(),
+            "1:12: expected signed integer literal for location decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) {
diff --git a/src/reader/wgsl/parser_impl_variable_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
index 68736e8..63af2bb 100644
--- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
@@ -57,7 +57,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: invalid value for location decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for location decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) {
@@ -65,7 +66,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: invalid value for location decoration");
+  EXPECT_EQ(p->error(),
+            "1:10: expected signed integer literal for location decoration");
 }
 
 struct BuiltinData {
@@ -178,7 +180,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: invalid value for binding decoration");
+  EXPECT_EQ(p->error(),
+            "1:9: expected signed integer literal for binding decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) {
@@ -186,7 +189,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: invalid value for binding decoration");
+  EXPECT_EQ(p->error(),
+            "1:9: expected signed integer literal for binding decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_set) {
@@ -221,7 +225,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: invalid value for set decoration");
+  EXPECT_EQ(p->error(),
+            "1:5: expected signed integer literal for set decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) {
@@ -229,7 +234,8 @@
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: invalid value for set decoration");
+  EXPECT_EQ(p->error(),
+            "1:5: expected signed integer literal for set decoration");
 }
 
 }  // namespace