[wgsl-reader][wgsl-writer] Update variable decorations to new syntax.

This CL updates the variable decorations to require ()'s around
parameters.

Bug: tint:238
Change-Id: I835879f41349756ace553a52fc2d460173e70dce
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28583
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 3b9d7a8..ae83f80 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -492,27 +492,45 @@
 }
 
 // variable_decoration
-//  : LOCATION INT_LITERAL
-//  | BUILTIN IDENT
-//  | BINDING INT_LITERAL
-//  | SET INT_LITERAL
+//  : LOCATION PAREN_LEFT INT_LITERAL PAREN_RIGHT
+//  | BUILTIN PAREN_LEFT IDENT PAREN_RIGHT
+//  | BINDING PAREN_LEFT INT_LITERAL PAREN_RIGHT
+//  | SET INT PAREN_LEFT_LITERAL PAREN_RIGHT
 std::unique_ptr<ast::VariableDecoration> ParserImpl::variable_decoration() {
   auto t = peek();
   if (t.IsLocation()) {
     next();  // consume the peek
 
     t = next();
+    if (!t.IsParenLeft()) {
+      set_error(t, "missing ( for location decoration");
+      return {};
+    }
+
+    t = next();
     if (!t.IsSintLiteral()) {
       set_error(t, "invalid value for location decoration");
       return {};
     }
+    int32_t val = t.to_i32();
 
-    return std::make_unique<ast::LocationDecoration>(t.to_i32());
+    t = next();
+    if (!t.IsParenRight()) {
+      set_error(t, "missing ) for location decoration");
+      return {};
+    }
+    return std::make_unique<ast::LocationDecoration>(val);
   }
   if (t.IsBuiltin()) {
     next();  // consume the peek
 
     t = next();
+    if (!t.IsParenLeft()) {
+      set_error(t, "missing ( for builtin decoration");
+      return {};
+    }
+
+    t = next();
     if (!t.IsIdentifier() || t.to_str().empty()) {
       set_error(t, "expected identifier for builtin");
       return {};
@@ -524,29 +542,60 @@
       return {};
     }
 
+    t = next();
+    if (!t.IsParenRight()) {
+      set_error(t, "missing ) for builtin decoration");
+      return {};
+    }
     return std::make_unique<ast::BuiltinDecoration>(builtin);
   }
   if (t.IsBinding()) {
     next();  // consume the peek
 
     t = next();
+    if (!t.IsParenLeft()) {
+      set_error(t, "missing ( for binding decoration");
+      return {};
+    }
+
+    t = next();
     if (!t.IsSintLiteral()) {
       set_error(t, "invalid value for binding decoration");
       return {};
     }
+    int32_t val = t.to_i32();
 
-    return std::make_unique<ast::BindingDecoration>(t.to_i32());
+    t = next();
+    if (!t.IsParenRight()) {
+      set_error(t, "missing ) for binding decoration");
+      return {};
+    }
+
+    return std::make_unique<ast::BindingDecoration>(val);
   }
   if (t.IsSet()) {
     next();  // consume the peek
 
     t = next();
+    if (!t.IsParenLeft()) {
+      set_error(t, "missing ( for set decoration");
+      return {};
+    }
+
+    t = next();
     if (!t.IsSintLiteral()) {
       set_error(t, "invalid value for set decoration");
       return {};
     }
+    uint32_t val = t.to_i32();
 
-    return std::make_unique<ast::SetDecoration>(t.to_i32());
+    t = next();
+    if (!t.IsParenRight()) {
+      set_error(t, "missing ) for set decoration");
+      return {};
+    }
+
+    return std::make_unique<ast::SetDecoration>(val);
   }
 
   return nullptr;
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 fa1aad6..a7d4d4e 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -55,7 +55,7 @@
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
-  auto* p = parser("[[binding 2, set 1]] var<out> a : f32");
+  auto* p = parser("[[binding(2), set(1)]] var<out> a : f32");
   auto e = p->global_variable_decl();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e, nullptr);
@@ -78,11 +78,11 @@
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) {
-  auto* p = parser("[[binding]] var<out> a : f32");
+  auto* p = parser("[[binding()]] var<out> a : f32");
   auto e = p->global_variable_decl();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(e, nullptr);
-  EXPECT_EQ(p->error(), "1:10: invalid value for binding decoration");
+  EXPECT_EQ(p->error(), "1:11: invalid value for binding decoration");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
diff --git a/src/reader/wgsl/parser_impl_test.cc b/src/reader/wgsl/parser_impl_test.cc
index 022e09d..154a33a 100644
--- a/src/reader/wgsl/parser_impl_test.cc
+++ b/src/reader/wgsl/parser_impl_test.cc
@@ -32,7 +32,7 @@
   auto* p = parser(R"(
 import "GLSL.std.430" as glsl;
 
-[[location 0]] var<out> gl_FragColor : vec4<f32>;
+[[location(0)]] var<out> gl_FragColor : vec4<f32>;
 
 entry_point vertex = main;
 fn main() -> void {
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 85cb1b1..33719ca 100644
--- a/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc
@@ -24,7 +24,7 @@
 namespace {
 
 TEST_F(ParserImplTest, VariableDecorationList_Parses) {
-  auto* p = parser(R"([[location 4, builtin position]])");
+  auto* p = parser(R"([[location(4), builtin(position)]])");
   auto decos = p->variable_decoration_list();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_EQ(decos.size(), 2u);
@@ -49,28 +49,28 @@
 }
 
 TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) {
-  auto* p = parser(R"([[builtin position, ]])");
+  auto* p = parser(R"([[builtin(position), ]])");
   auto decos = p->variable_decoration_list();
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:21: missing variable decoration after comma");
+  ASSERT_EQ(p->error(), "1:22: missing variable decoration after comma");
 }
 
 TEST_F(ParserImplTest, VariableDecorationList_MissingComma) {
-  auto* p = parser(R"([[binding 4 location 5]])");
+  auto* p = parser(R"([[binding(4) location(5)]])");
   auto decos = p->variable_decoration_list();
   ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:13: missing comma in variable decoration list");
+  ASSERT_EQ(p->error(), "1:14: missing comma in variable decoration list");
 }
 
 TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) {
-  auto* p = parser(R"([[location bad]])");
+  auto* p = parser(R"([[location(bad)]])");
   auto decos = p->variable_decoration_list();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(p->error(), "1:12: invalid value for location decoration");
 }
 
 TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) {
-  auto* p = parser("[[builtin invalid]]");
+  auto* p = parser("[[builtin(invalid)]]");
   auto decos = p->variable_decoration_list();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(p->error(), "1:11: invalid value for builtin decoration");
diff --git a/src/reader/wgsl/parser_impl_variable_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
index 6775009..070e8ec 100644
--- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc
@@ -26,7 +26,7 @@
 namespace {
 
 TEST_F(ParserImplTest, VariableDecoration_Location) {
-  auto* p = parser("location 4");
+  auto* p = parser("location(4)");
   auto deco = p->variable_decoration();
   ASSERT_NE(deco, nullptr);
   ASSERT_FALSE(p->has_error());
@@ -36,16 +36,32 @@
   EXPECT_EQ(loc->value(), 4u);
 }
 
-TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) {
-  auto* p = parser("location");
+TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) {
+  auto* p = parser("location 4)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: invalid value for location decoration");
+  EXPECT_EQ(p->error(), "1:10: missing ( for location decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) {
+  auto* p = parser("location(4");
+  auto deco = p->variable_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:11: missing ) for location decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) {
+  auto* p = parser("location()");
+  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");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) {
-  auto* p = parser("location nan");
+  auto* p = parser("location(nan)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
@@ -81,7 +97,7 @@
 
 TEST_P(BuiltinTest, VariableDecoration_Builtin) {
   auto params = GetParam();
-  auto* p = parser(std::string("builtin ") + params.input);
+  auto* p = parser(std::string("builtin(") + params.input + ")");
 
   auto deco = p->variable_decoration();
   ASSERT_FALSE(p->has_error()) << p->error();
@@ -107,16 +123,32 @@
         BuiltinData{"global_invocation_id",
                     ast::Builtin::kGlobalInvocationId}));
 
-TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) {
-  auto* p = parser("builtin");
+TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) {
+  auto* p = parser("builtin position)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected identifier for builtin");
+  EXPECT_EQ(p->error(), "1:9: missing ( for builtin decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) {
+  auto* p = parser("builtin(position");
+  auto deco = p->variable_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:17: missing ) for builtin decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) {
+  auto* p = parser("builtin()");
+  auto deco = p->variable_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) {
-  auto* p = parser("builtin other_thingy");
+  auto* p = parser("builtin(other_thingy)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
@@ -124,7 +156,7 @@
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) {
-  auto* p = parser("builtin 3");
+  auto* p = parser("builtin(3)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
@@ -132,7 +164,7 @@
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Binding) {
-  auto* p = parser("binding 4");
+  auto* p = parser("binding(4)");
   auto deco = p->variable_decoration();
   ASSERT_NE(deco, nullptr);
   ASSERT_FALSE(p->has_error());
@@ -142,16 +174,32 @@
   EXPECT_EQ(binding->value(), 4u);
 }
 
-TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) {
-  auto* p = parser("binding");
+TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) {
+  auto* p = parser("binding 4)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: invalid value for binding decoration");
+  EXPECT_EQ(p->error(), "1:9: missing ( for binding decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) {
+  auto* p = parser("binding(4");
+  auto deco = p->variable_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:10: missing ) for binding decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) {
+  auto* p = parser("binding()");
+  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");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) {
-  auto* p = parser("binding nan");
+  auto* p = parser("binding(nan)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
@@ -159,7 +207,7 @@
 }
 
 TEST_F(ParserImplTest, VariableDecoration_set) {
-  auto* p = parser("set 4");
+  auto* p = parser("set(4)");
   auto deco = p->variable_decoration();
   ASSERT_FALSE(p->has_error());
   ASSERT_NE(deco.get(), nullptr);
@@ -169,16 +217,32 @@
   EXPECT_EQ(set->value(), 4u);
 }
 
-TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) {
-  auto* p = parser("set");
+TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) {
+  auto* p = parser("set 2)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: invalid value for set decoration");
+  EXPECT_EQ(p->error(), "1:5: missing ( for set decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) {
+  auto* p = parser("set(2");
+  auto deco = p->variable_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:6: missing ) for set decoration");
+}
+
+TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) {
+  auto* p = parser("set()");
+  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");
 }
 
 TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) {
-  auto* p = parser("set nan");
+  auto* p = parser("set(nan)");
   auto deco = p->variable_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
diff --git a/src/reader/wgsl/parser_test.cc b/src/reader/wgsl/parser_test.cc
index 178794a..767c236 100644
--- a/src/reader/wgsl/parser_test.cc
+++ b/src/reader/wgsl/parser_test.cc
@@ -36,7 +36,7 @@
   Parser p(&ctx, R"(
 import "GLSL.std.430" as glsl;
 
-[[location 0]] var<out> gl_FragColor : vec4<f32>;
+[[location(0)]] var<out> gl_FragColor : vec4<f32>;
 
 entry_point vertex = main;
 fn main() -> void {
diff --git a/src/writer/hlsl/generator_impl_entry_point_test.cc b/src/writer/hlsl/generator_impl_entry_point_test.cc
index ad99c2e..184e725 100644
--- a/src/writer/hlsl/generator_impl_entry_point_test.cc
+++ b/src/writer/hlsl/generator_impl_entry_point_test.cc
@@ -37,8 +37,8 @@
 using HlslGeneratorImplTest_EntryPoint = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Vertex_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // struct vtx_main_in {
   //   float foo : TEXCOORD0;
@@ -98,8 +98,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Vertex_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // struct vtx_main_out {
   //   float foo : TEXCOORD0;
@@ -159,8 +159,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Fragment_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // struct frag_main_in {
   //   float foo : TEXCOORD0;
@@ -220,8 +220,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Fragment_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // struct frag_main_out {
   //   float foo : SV_Target0;
@@ -281,8 +281,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Compute_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // -> Error, not allowed
 
@@ -334,8 +334,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Compute_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // -> Error not allowed
 
@@ -387,8 +387,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_EntryPoint, EmitEntryPointData_Builtins) {
-  // [[builtin frag_coord]] var<in> coord : vec4<f32>;
-  // [[builtin frag_depth]] var<out> depth : f32;
+  // [[builtin(frag_coord)]] var<in> coord : vec4<f32>;
+  // [[builtin(frag_depth)]] var<out> depth : f32;
   //
   // struct main_in {
   //   vector<float, 4> coord : SV_Position;
diff --git a/src/writer/msl/generator_impl_entry_point_test.cc b/src/writer/msl/generator_impl_entry_point_test.cc
index 8c85901..74ad69a 100644
--- a/src/writer/msl/generator_impl_entry_point_test.cc
+++ b/src/writer/msl/generator_impl_entry_point_test.cc
@@ -37,8 +37,8 @@
 using MslGeneratorImplTest = testing::Test;
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Vertex_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // struct vtx_main_in {
   //   float foo [[attribute(0)]];
@@ -103,8 +103,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Vertex_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // struct vtx_main_out {
   //   float foo [[user(locn0)]];
@@ -169,8 +169,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Fragment_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // struct frag_main_in {
   //   float foo [[user(locn0)]];
@@ -235,8 +235,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Fragment_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // struct frag_main_out {
   //   float foo [[color(0)]];
@@ -301,8 +301,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Compute_Input) {
-  // [[location 0]] var<in> foo : f32;
-  // [[location 1]] var<in> bar : i32;
+  // [[location(0)]] var<in> foo : f32;
+  // [[location(1)]] var<in> bar : i32;
   //
   // -> Error, not allowed
 
@@ -359,8 +359,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitEntryPointData_Compute_Output) {
-  // [[location 0]] var<out> foo : f32;
-  // [[location 1]] var<out> bar : i32;
+  // [[location(0)]] var<out> foo : f32;
+  // [[location(1)]] var<out> bar : i32;
   //
   // -> Error not allowed
 
@@ -420,8 +420,8 @@
   // Output builtins go in the output struct, input builtins will be passed
   // as input parameters to the entry point function.
 
-  // [[builtin frag_coord]] var<in> coord : vec4<f32>;
-  // [[builtin frag_depth]] var<out> depth : f32;
+  // [[builtin(frag_coord)]] var<in> coord : vec4<f32>;
+  // [[builtin(frag_depth)]] var<out> depth : f32;
   //
   // struct main_out {
   //   float depth [[depth(any)]];
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 7880442..11d3690 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -791,13 +791,13 @@
     first = false;
 
     if (deco->IsBinding()) {
-      out_ << "binding " << deco->AsBinding()->value();
+      out_ << "binding(" << deco->AsBinding()->value() << ")";
     } else if (deco->IsSet()) {
-      out_ << "set " << deco->AsSet()->value();
+      out_ << "set(" << deco->AsSet()->value() << ")";
     } else if (deco->IsLocation()) {
-      out_ << "location " << deco->AsLocation()->value();
+      out_ << "location(" << deco->AsLocation()->value() << ")";
     } else if (deco->IsBuiltin()) {
-      out_ << "builtin " << deco->AsBuiltin()->value();
+      out_ << "builtin(" << deco->AsBuiltin()->value() << ")";
     } else {
       error_ = "unknown variable decoration";
       return false;
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index 64a9eed..6665a91 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -64,7 +64,7 @@
 
   GeneratorImpl g;
   ASSERT_TRUE(g.EmitVariable(&dv)) << g.error();
-  EXPECT_EQ(g.result(), R"([[location 2]] var a : f32;
+  EXPECT_EQ(g.result(), R"([[location(2)]] var a : f32;
 )");
 }
 
@@ -85,8 +85,9 @@
 
   GeneratorImpl g;
   ASSERT_TRUE(g.EmitVariable(&dv)) << g.error();
-  EXPECT_EQ(g.result(),
-            R"([[builtin position, binding 0, set 1, location 2]] var a : f32;
+  EXPECT_EQ(
+      g.result(),
+      R"([[builtin(position), binding(0), set(1), location(2)]] var a : f32;
 )");
 }
 
diff --git a/test/compute_boids.wgsl b/test/compute_boids.wgsl
index e567f74..ba4d2de 100644
--- a/test/compute_boids.wgsl
+++ b/test/compute_boids.wgsl
@@ -16,10 +16,10 @@
 
 # vertex shader
 
-[[location 0]] var<in> a_particlePos : vec2<f32>;
-[[location 1]] var<in> a_particleVel : vec2<f32>;
-[[location 2]] var<in> a_pos : vec2<f32>;
-[[builtin position]] var<out> gl_Position : vec4<f32>;
+[[location(0)]] var<in> a_particlePos : vec2<f32>;
+[[location(1)]] var<in> a_particleVel : vec2<f32>;
+[[location(2)]] var<in> a_pos : vec2<f32>;
+[[builtin(position)]] var<out> gl_Position : vec4<f32>;
 
 fn vtx_main() -> void {
   var angle : f32 = -std::atan2(a_particleVel.x, a_particleVel.y);
@@ -32,7 +32,7 @@
 entry_point vertex as "vert_main" = vtx_main;
 
 # fragment shader
-[[location 0]] var<out> fragColor : vec4<f32>;
+[[location(0)]] var<out> fragColor : vec4<f32>;
 
 fn frag_main() -> void {
   fragColor = vec4<f32>(1.0, 1.0, 1.0, 1.0);
@@ -60,11 +60,11 @@
   [[offset(0)]] particles : [[stride(16)]] array<Particle, 5>;
 };
 
-[[binding 0, set 0]] var<uniform> params : SimParams;
-[[binding 1, set 0]] var<storage_buffer> particlesA : Particles;
-[[binding 2, set 0]] var<storage_buffer> particlesB : Particles;
+[[binding(0), set(0)]] var<uniform> params : SimParams;
+[[binding(1), set(0)]] var<storage_buffer> particlesA : Particles;
+[[binding(2), set(0)]] var<storage_buffer> particlesB : Particles;
 
-[[builtin global_invocation_id]] var<in> gl_GlobalInvocationID : vec3<u32>;
+[[builtin(global_invocation_id)]] var<in> gl_GlobalInvocationID : vec3<u32>;
 
 # https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
 fn compute_main() -> void {
diff --git a/test/cube.wgsl b/test/cube.wgsl
index 7ed1b2c..6dd5c0a 100644
--- a/test/cube.wgsl
+++ b/test/cube.wgsl
@@ -20,12 +20,12 @@
   [[offset(0)]] modelViewProjectionMatrix : mat4x4<f32>;
 };
 
-[[binding 0, set 0]] var<uniform> uniforms : Uniforms;
+[[binding(0), set(0)]] var<uniform> uniforms : Uniforms;
 
-[[location 0]] var<in> cur_position : vec4<f32>;
-[[location 1]] var<in> color : vec4<f32>;
-[[location 0]] var<out> vtxFragColor : vec4<f32>;
-[[builtin position]] var<out> Position : vec4<f32>;
+[[location(0)]] var<in> cur_position : vec4<f32>;
+[[location(1)]] var<in> color : vec4<f32>;
+[[location(0)]] var<out> vtxFragColor : vec4<f32>;
+[[builtin(position)]] var<out> Position : vec4<f32>;
 
 fn vtx_main() -> void {
    Position = uniforms.modelViewProjectionMatrix * cur_position;
@@ -34,8 +34,8 @@
 }
 
 # Fragment shader
-[[location 0]] var<in> fragColor : vec4<f32>;
-[[location 0]] var<out> outColor : vec4<f32>;
+[[location(0)]] var<in> fragColor : vec4<f32>;
+[[location(0)]] var<out> outColor : vec4<f32>;
 
 fn frag_main() -> void {
   outColor = fragColor;
diff --git a/test/simple.wgsl b/test/simple.wgsl
index d0adf46..e8ec8c6 100644
--- a/test/simple.wgsl
+++ b/test/simple.wgsl
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-[[location 0]] var<out> gl_FragColor : vec4<f32>;
+[[location(0)]] var<out> gl_FragColor : vec4<f32>;
 
 fn bar() -> void {
   return;
diff --git a/test/triangle.wgsl b/test/triangle.wgsl
index d833e83..44b0425 100644
--- a/test/triangle.wgsl
+++ b/test/triangle.wgsl
@@ -18,8 +18,8 @@
     vec2<f32>(-0.5, -0.5),
     vec2<f32>(0.5, -0.5));
 
-[[builtin position]] var<out> Position : vec4<f32>;
-[[builtin vertex_idx]] var<in> VertexIndex : i32;
+[[builtin(position)]] var<out> Position : vec4<f32>;
+[[builtin(vertex_idx)]] var<in> VertexIndex : i32;
 
 fn vtx_main() -> void {
   Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
@@ -28,7 +28,7 @@
 entry_point vertex as "main" = vtx_main;
 
 # Fragment shader
-[[location 0]] var<out> outColor : vec4<f32>;
+[[location(0)]] var<out> outColor : vec4<f32>;
 fn frag_main() -> void {
   outColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
   return;