[wgsl-reader] Add support for entry point parameters

This just handles non-struct parameters for now. Structs will be
handled in a later patch.

Bug: tint:513
Change-Id: Idfb202a599fcd84400b89515f21bfed6fd3795b5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44081
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 420b528..6f8184a 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1263,40 +1263,54 @@
 
 // param_list
 //   :
-//   | (variable_ident_decl COMMA)* variable_ident_decl
+//   | (param COMMA)* param
 Expect<ast::VariableList> ParserImpl::expect_param_list() {
-  if (!peek().IsIdentifier())  // Empty list
+  // Check for an empty list.
+  auto t = peek();
+  if (!t.IsIdentifier() && !t.IsAttrLeft()) {
     return ast::VariableList{};
+  }
+
+  ast::VariableList ret;
+  while (synchronized_) {
+    auto param = expect_param();
+    if (param.errored)
+      return Failure::kErrored;
+    ret.push_back(param.value);
+
+    if (!match(Token::Type::kComma))
+      break;
+  }
+
+  return ret;
+}
+
+// param
+//   : decoration_list* variable_ident_decl
+Expect<ast::Variable*> ParserImpl::expect_param() {
+  auto decos = decoration_list();
+  auto var_decos = cast_decorations<ast::VariableDecoration>(decos.value);
+  if (var_decos.errored)
+    return Failure::kErrored;
 
   auto decl = expect_variable_ident_decl("parameter");
   if (decl.errored)
     return Failure::kErrored;
 
-  ast::VariableList ret;
-  for (;;) {
-    auto* var = create<ast::Variable>(
-        decl->source,                             // source
-        builder_.Symbols().Register(decl->name),  // symbol
-        ast::StorageClass::kNone,                 // storage_class
-        decl->type,                               // type
-        true,                                     // is_const
-        nullptr,                                  // constructor
-        ast::VariableDecorationList{});           // decorations
-    // Formal parameters are treated like a const declaration where the
-    // initializer value is provided by the call's argument.  The key point is
-    // that it's not updatable after intially set.  This is unlike C or GLSL
-    // which treat formal parameters like local variables that can be updated.
-    ret.push_back(var);
+  auto* var =
+      create<ast::Variable>(decl->source,                             // source
+                            builder_.Symbols().Register(decl->name),  // symbol
+                            ast::StorageClass::kNone,     // storage_class
+                            decl->type,                   // type
+                            true,                         // is_const
+                            nullptr,                      // constructor
+                            std::move(var_decos.value));  // decorations
+  // Formal parameters are treated like a const declaration where the
+  // initializer value is provided by the call's argument.  The key point is
+  // that it's not updatable after initially set.  This is unlike C or GLSL
+  // which treat formal parameters like local variables that can be updated.
 
-    if (!match(Token::Type::kComma))
-      break;
-
-    decl = expect_variable_ident_decl("parameter");
-    if (decl.errored)
-      return Failure::kErrored;
-  }
-
-  return ret;
+  return var;
 }
 
 // pipeline_stage
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 7ac2169..2f3ba07 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -419,6 +419,9 @@
   /// Parses a `param_list` grammar element, erroring on parse failure.
   /// @returns the parsed variables
   Expect<ast::VariableList> expect_param_list();
+  /// Parses a `param` grammar element, erroring on parse failure.
+  /// @returns the parsed variable
+  Expect<ast::Variable*> expect_param();
   /// Parses a `pipeline_stage` grammar element, erroring if the next token does
   /// not match a stage name.
   /// @returns the pipeline stage.
diff --git a/src/reader/wgsl/parser_impl_param_list_test.cc b/src/reader/wgsl/parser_impl_param_list_test.cc
index d4ebd03..0bf7686 100644
--- a/src/reader/wgsl/parser_impl_param_list_test.cc
+++ b/src/reader/wgsl/parser_impl_param_list_test.cc
@@ -95,6 +95,47 @@
   EXPECT_EQ(p->error(), "1:9: expected identifier for parameter");
 }
 
+TEST_F(ParserImplTest, ParamList_Decorations) {
+  auto p = parser(
+      "[[builtin(frag_coord)]] coord : vec4<f32>, "
+      "[[location(1)]] loc1 : f32");
+
+  auto* f32 = p->builder().create<type::F32>();
+  auto* vec4 = p->builder().create<type::Vector>(f32, 4);
+
+  auto e = p->expect_param_list();
+  ASSERT_FALSE(p->has_error()) << p->error();
+  ASSERT_FALSE(e.errored);
+  ASSERT_EQ(e.value.size(), 2u);
+
+  EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("coord"));
+  EXPECT_EQ(e.value[0]->type(), vec4);
+  EXPECT_TRUE(e.value[0]->is_const());
+  auto decos0 = e.value[0]->decorations();
+  ASSERT_EQ(decos0.size(), 1u);
+  EXPECT_TRUE(decos0[0]->Is<ast::BuiltinDecoration>());
+  EXPECT_EQ(decos0[0]->As<ast::BuiltinDecoration>()->value(),
+            ast::Builtin::kFragCoord);
+
+  ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
+  ASSERT_EQ(e.value[0]->source().range.begin.column, 25u);
+  ASSERT_EQ(e.value[0]->source().range.end.line, 1u);
+  ASSERT_EQ(e.value[0]->source().range.end.column, 30u);
+
+  EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("loc1"));
+  EXPECT_EQ(e.value[1]->type(), f32);
+  EXPECT_TRUE(e.value[1]->is_const());
+  auto decos1 = e.value[1]->decorations();
+  ASSERT_EQ(decos1.size(), 1u);
+  EXPECT_TRUE(decos1[0]->Is<ast::LocationDecoration>());
+  EXPECT_EQ(decos1[0]->As<ast::LocationDecoration>()->value(), 1u);
+
+  ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
+  ASSERT_EQ(e.value[1]->source().range.begin.column, 60u);
+  ASSERT_EQ(e.value[1]->source().range.end.line, 1u);
+  ASSERT_EQ(e.value[1]->source().range.end.column, 64u);
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace reader