wgsl-reader: support multiple case selectors

Bug: tint:454
Change-Id: I5a046e19f66b5807723e96593ea6ba107ef69e6c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38261
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 2175a46..264f23f 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1856,13 +1856,26 @@
 
   for (;;) {
     auto t = peek();
+    auto matched_comma = match(Token::Type::kComma);
+
+    if (selectors.empty() && matched_comma)
+      return add_error(t, "a selector is expected before the comma");
+    if (matched_comma)
+      t = peek();
+
     auto cond = const_literal();
     if (cond.errored)
       return Failure::kErrored;
-    if (!cond.matched)
+    if (!cond.matched) {
+      if (matched_comma) {
+        return add_error(t, "a selector is expected after the comma");
+      }
       break;
+    }
     if (!cond->Is<ast::IntLiteral>())
       return add_error(t, "invalid case selector must be an integer value");
+    if (!selectors.empty() && !matched_comma)
+      return add_error(t, "expected a comma after the previous selector");
 
     selectors.push_back(cond.value->As<ast::IntLiteral>());
   }
diff --git a/src/reader/wgsl/parser_impl_switch_body_test.cc b/src/reader/wgsl/parser_impl_switch_body_test.cc
index 73ab068..ba98d01 100644
--- a/src/reader/wgsl/parser_impl_switch_body_test.cc
+++ b/src/reader/wgsl/parser_impl_switch_body_test.cc
@@ -105,6 +105,61 @@
   EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
 }
 
+TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors) {
+  auto p = parser("case 1, 2: { }");
+  auto e = p->switch_body();
+  EXPECT_FALSE(p->has_error()) << p->error();
+  EXPECT_TRUE(e.matched);
+  EXPECT_FALSE(e.errored);
+  ASSERT_NE(e.value, nullptr);
+  ASSERT_TRUE(e->Is<ast::CaseStatement>());
+  EXPECT_FALSE(e->IsDefault());
+  ASSERT_EQ(e->body()->size(), 0u);
+  ASSERT_EQ(e->selectors().size(), 2u);
+  ASSERT_EQ(e->selectors()[0]->to_str(), "1");
+  ASSERT_EQ(e->selectors()[1]->to_str(), "2");
+}
+
+TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsMissingColon) {
+  auto p = parser("case 1, 2 { }");
+  auto e = p->switch_body();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(e.errored);
+  EXPECT_FALSE(e.matched);
+  EXPECT_EQ(e.value, nullptr);
+  EXPECT_EQ(p->error(), "1:11: expected ':' for case statement");
+}
+
+TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsMissingComma) {
+  auto p = parser("case 1 2: { }");
+  auto e = p->switch_body();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(e.errored);
+  EXPECT_FALSE(e.matched);
+  EXPECT_EQ(e.value, nullptr);
+  EXPECT_EQ(p->error(), "1:8: expected a comma after the previous selector");
+}
+
+TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsEndsWithComma) {
+  auto p = parser("case 1, 2,: { }");
+  auto e = p->switch_body();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(e.errored);
+  EXPECT_FALSE(e.matched);
+  EXPECT_EQ(e.value, nullptr);
+  EXPECT_EQ(p->error(), "1:11: a selector is expected after the comma");
+}
+
+TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsStartsWithComma) {
+  auto p = parser("case , 1, 2: { }");
+  auto e = p->switch_body();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(e.errored);
+  EXPECT_FALSE(e.matched);
+  EXPECT_EQ(e.value, nullptr);
+  EXPECT_EQ(p->error(), "1:6: a selector is expected before the comma");
+}
+
 TEST_F(ParserImplTest, SwitchBody_Default) {
   auto p = parser("default: { a = 4; }");
   auto e = p->switch_body();