[wgsl-reader] Parsing storage texture type

Bug: tint:147
Change-Id: I446786b529e777d709213e100e57cbae78ded75f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28122
Commit-Queue: Tomek Ponitka <tommek@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 6cbda0d..dc3b085 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -917,6 +917,7 @@
     "src/reader/wgsl/parser_impl_statement_test.cc",
     "src/reader/wgsl/parser_impl_statements_test.cc",
     "src/reader/wgsl/parser_impl_storage_class_test.cc",
+    "src/reader/wgsl/parser_impl_storage_texture_type_test.cc",
     "src/reader/wgsl/parser_impl_struct_body_decl_test.cc",
     "src/reader/wgsl/parser_impl_struct_decl_test.cc",
     "src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 43e3524..fc5fc11 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -448,6 +448,7 @@
     reader/wgsl/parser_impl_statement_test.cc
     reader/wgsl/parser_impl_statements_test.cc
     reader/wgsl/parser_impl_storage_class_test.cc
+    reader/wgsl/parser_impl_storage_texture_type_test.cc
     reader/wgsl/parser_impl_struct_body_decl_test.cc
     reader/wgsl/parser_impl_struct_decl_test.cc
     reader/wgsl/parser_impl_struct_decoration_decl_test.cc
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index b282685..66a2dc2 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -657,6 +657,18 @@
     return {Token::Type::kTextureDepthCubeArray, source,
             "texture_depth_cube_array"};
   }
+  if (str == "texture_ro_1d")
+    return {Token::Type::kTextureStorageReadonly1d, source, "texture_ro_1d"};
+  if (str == "texture_ro_1d_array")
+    return {Token::Type::kTextureStorageReadonly1dArray, source,
+            "texture_ro_1d_array"};
+  if (str == "texture_ro_2d")
+    return {Token::Type::kTextureStorageReadonly2d, source, "texture_ro_2d"};
+  if (str == "texture_ro_2d_array")
+    return {Token::Type::kTextureStorageReadonly2dArray, source,
+            "texture_ro_2d_array"};
+  if (str == "texture_ro_3d")
+    return {Token::Type::kTextureStorageReadonly3d, source, "texture_ro_3d"};
   if (str == "texture_sampled_1d")
     return {Token::Type::kTextureSampled1d, source, "texture_sampled_1d"};
   if (str == "texture_sampled_1d_array") {
@@ -683,6 +695,18 @@
     return {Token::Type::kTextureSampledCubeArray, source,
             "texture_sampled_cube_array"};
   }
+  if (str == "texture_wo_1d")
+    return {Token::Type::kTextureStorageWriteonly1d, source, "texture_wo_1d"};
+  if (str == "texture_wo_1d_array")
+    return {Token::Type::kTextureStorageWriteonly1dArray, source,
+            "texture_wo_1d_array"};
+  if (str == "texture_wo_2d")
+    return {Token::Type::kTextureStorageWriteonly2d, source, "texture_wo_2d"};
+  if (str == "texture_wo_2d_array")
+    return {Token::Type::kTextureStorageWriteonly2dArray, source,
+            "texture_wo_2d_array"};
+  if (str == "texture_wo_3d")
+    return {Token::Type::kTextureStorageWriteonly3d, source, "texture_wo_3d"};
   if (str == "true")
     return {Token::Type::kTrue, source, "true"};
   if (str == "type")
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index 8cddbf1..4806cb6 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -505,6 +505,13 @@
         TokenData{"texture_depth_cube", Token::Type::kTextureDepthCube},
         TokenData{"texture_depth_cube_array",
                   Token::Type::kTextureDepthCubeArray},
+        TokenData{"texture_ro_1d", Token::Type::kTextureStorageReadonly1d},
+        TokenData{"texture_ro_1d_array",
+                  Token::Type::kTextureStorageReadonly1dArray},
+        TokenData{"texture_ro_2d", Token::Type::kTextureStorageReadonly2d},
+        TokenData{"texture_ro_2d_array",
+                  Token::Type::kTextureStorageReadonly2dArray},
+        TokenData{"texture_ro_3d", Token::Type::kTextureStorageReadonly3d},
         TokenData{"texture_sampled_1d", Token::Type::kTextureSampled1d},
         TokenData{"texture_sampled_1d_array",
                   Token::Type::kTextureSampled1dArray},
@@ -518,6 +525,13 @@
         TokenData{"texture_sampled_cube", Token::Type::kTextureSampledCube},
         TokenData{"texture_sampled_cube_array",
                   Token::Type::kTextureSampledCubeArray},
+        TokenData{"texture_wo_1d", Token::Type::kTextureStorageWriteonly1d},
+        TokenData{"texture_wo_1d_array",
+                  Token::Type::kTextureStorageWriteonly1dArray},
+        TokenData{"texture_wo_2d", Token::Type::kTextureStorageWriteonly2d},
+        TokenData{"texture_wo_2d_array",
+                  Token::Type::kTextureStorageWriteonly2dArray},
+        TokenData{"texture_wo_3d", Token::Type::kTextureStorageWriteonly3d},
         TokenData{"true", Token::Type::kTrue},
         TokenData{"type", Token::Type::kType},
         TokenData{"u32", Token::Type::kU32},
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index d8bee52..50925f3 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -583,7 +583,7 @@
 //  | depth_texture_type
 //  | sampled_texture_type LESS_THAN type_decl GREATER_THAN
 //  | TODO: multisampled_texture_type LESS_THAN type_decl GREATER_THAN
-//  | TODO: storage_texture_type LESS_THAN image_storage_type GREATER_THAN
+//  | storage_texture_type LESS_THAN image_storage_type GREATER_THAN
 ast::type::Type* ParserImpl::texture_sampler_types() {
   auto* type = sampler_type();
   if (type != nullptr) {
@@ -595,8 +595,8 @@
     return type;
   }
 
-  auto dim = sampled_texture_type();
-  if (dim != ast::type::TextureDimension::kNone) {
+  auto sampled_dim = sampled_texture_type();
+  if (sampled_dim != ast::type::TextureDimension::kNone) {
     auto t = next();
     if (!t.IsLessThan()) {
       set_error(peek(), "missing '<' for sampled texture type");
@@ -618,7 +618,35 @@
     }
 
     return ctx_.type_mgr().Get(
-        std::make_unique<ast::type::SampledTextureType>(dim, subtype));
+        std::make_unique<ast::type::SampledTextureType>(sampled_dim, subtype));
+  }
+
+  ast::type::TextureDimension storage_dim;
+  ast::type::StorageAccess storage_access;
+  std::tie(storage_dim, storage_access) = storage_texture_type();
+  if (storage_dim != ast::type::TextureDimension::kNone) {
+    auto t = next();
+    if (!t.IsLessThan()) {
+      set_error(peek(), "missing '<' for storage texture type");
+      return nullptr;
+    }
+
+    auto format = image_storage_type();
+    if (has_error())
+      return nullptr;
+    if (format == ast::type::ImageFormat::kNone) {
+      set_error(peek(), "invalid format for storage texture type");
+      return nullptr;
+    }
+
+    t = next();
+    if (!t.IsGreaterThan()) {
+      set_error(peek(), "missing '>' for storage texture type");
+      return nullptr;
+    }
+
+    return ctx_.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
+        storage_dim, storage_access, format));
   }
 
   return nullptr;
@@ -693,6 +721,67 @@
   return ast::type::TextureDimension::kNone;
 }
 
+// storage_texture_type
+//  : TEXTURE_RO_1D
+//  | TEXTURE_RO_1D_ARRAY
+//  | TEXTURE_RO_2D
+//  | TEXTURE_RO_2D_ARRAY
+//  | TEXTURE_RO_3D
+//  | TEXTURE_WO_1D
+//  | TEXTURE_WO_1D_ARRAY
+//  | TEXTURE_WO_2D
+//  | TEXTURE_WO_2D_ARRAY
+//  | TEXTURE_WO_3D
+std::pair<ast::type::TextureDimension, ast::type::StorageAccess>
+ParserImpl::storage_texture_type() {
+  auto t = peek();
+  if (t.IsTextureStorageReadonly1d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k1d, ast::type::StorageAccess::kRead};
+  }
+  if (t.IsTextureStorageReadonly1dArray()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k1dArray,
+            ast::type::StorageAccess::kRead};
+  }
+  if (t.IsTextureStorageReadonly2d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k2d, ast::type::StorageAccess::kRead};
+  }
+  if (t.IsTextureStorageReadonly2dArray()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k2dArray,
+            ast::type::StorageAccess::kRead};
+  }
+  if (t.IsTextureStorageReadonly3d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k3d, ast::type::StorageAccess::kRead};
+  }
+  if (t.IsTextureStorageWriteonly1d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k1d, ast::type::StorageAccess::kWrite};
+  }
+  if (t.IsTextureStorageWriteonly1dArray()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k1dArray,
+            ast::type::StorageAccess::kWrite};
+  }
+  if (t.IsTextureStorageWriteonly2d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k2d, ast::type::StorageAccess::kWrite};
+  }
+  if (t.IsTextureStorageWriteonly2dArray()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k2dArray,
+            ast::type::StorageAccess::kWrite};
+  }
+  if (t.IsTextureStorageWriteonly3d()) {
+    next();  // Consume the peek
+    return {ast::type::TextureDimension::k3d, ast::type::StorageAccess::kWrite};
+  }
+  return {ast::type::TextureDimension::kNone, ast::type::StorageAccess::kRead};
+}
+
 // depth_texture_type
 //  : TEXTURE_DEPTH_2D
 //  | TEXTURE_DEPTH_2D_ARRAY
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 76dea6d..eb35b3d 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -191,6 +191,11 @@
   /// Parses a `sampled_texture_type` grammar element
   /// @returns returns the sample texture dimension or kNone if none matched.
   ast::type::TextureDimension sampled_texture_type();
+  /// Parses a `storage_texture_type` grammar element
+  /// @returns returns the storage texture dimension and the storage access.
+  ///          Returns kNone and kRead if none matched.
+  std::pair<ast::type::TextureDimension, ast::type::StorageAccess>
+  storage_texture_type();
   /// Parses a `depth_texture_type` grammar element
   /// @returns the parsed Type or nullptr if none matched.
   ast::type::Type* depth_texture_type();
diff --git a/src/reader/wgsl/parser_impl_storage_texture_type_test.cc b/src/reader/wgsl/parser_impl_storage_texture_type_test.cc
new file mode 100644
index 0000000..5a5924a
--- /dev/null
+++ b/src/reader/wgsl/parser_impl_storage_texture_type_test.cc
@@ -0,0 +1,116 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "src/ast/type/storage_texture_type.h"
+#include "src/reader/wgsl/parser_impl.h"
+#include "src/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint {
+namespace reader {
+namespace wgsl {
+namespace {
+
+TEST_F(ParserImplTest, StorageTextureType_Invalid) {
+  auto* p = parser("abc");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::kNone);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Readonly1d) {
+  auto* p = parser("texture_ro_1d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k1d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Readonly1dArray) {
+  auto* p = parser("texture_ro_1d_array");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k1dArray);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Readonly2d) {
+  auto* p = parser("texture_ro_2d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k2d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Readonly2dArray) {
+  auto* p = parser("texture_ro_2d_array");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k2dArray);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Readonly3d) {
+  auto* p = parser("texture_ro_3d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k3d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kRead);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Writeonly1d) {
+  auto* p = parser("texture_wo_1d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k1d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kWrite);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Writeonly1dArray) {
+  auto* p = parser("texture_wo_1d_array");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k1dArray);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kWrite);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Writeonly2d) {
+  auto* p = parser("texture_wo_2d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k2d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kWrite);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Writeonly2dArray) {
+  auto* p = parser("texture_wo_2d_array");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k2dArray);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kWrite);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_Writeonly3d) {
+  auto* p = parser("texture_wo_3d");
+  auto t = p->storage_texture_type();
+  EXPECT_EQ(t.first, ast::type::TextureDimension::k3d);
+  EXPECT_EQ(t.second, ast::type::StorageAccess::kWrite);
+  EXPECT_FALSE(p->has_error());
+}
+
+}  // namespace
+}  // namespace wgsl
+}  // namespace reader
+}  // namespace tint
diff --git a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
index 262dca9..3174004 100644
--- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
+++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
@@ -119,6 +119,62 @@
   EXPECT_EQ(p->error(), "1:23: missing '>' for sampled texture type");
 }
 
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) {
+  auto* p = parser("texture_ro_1d<r8unorm>");
+  auto* t = p->texture_sampler_types();
+  ASSERT_NE(t, nullptr);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
+            ast::type::ImageFormat::kR8Unorm);
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
+            ast::type::StorageAccess::kRead);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
+  auto* p = parser("texture_wo_2d<r16float>");
+  auto* t = p->texture_sampler_types();
+  ASSERT_NE(t, nullptr);
+  ASSERT_TRUE(t->IsTexture());
+  ASSERT_TRUE(t->AsTexture()->IsStorage());
+  EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(),
+            ast::type::ImageFormat::kR16Float);
+  EXPECT_EQ(t->AsTexture()->AsStorage()->access(),
+            ast::type::StorageAccess::kWrite);
+  EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d);
+  EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
+  auto* p = parser("texture_ro_1d<abc>");
+  auto* t = p->texture_sampler_types();
+  EXPECT_EQ(t, nullptr);
+  EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
+  auto* p = parser("texture_wo_1d<>");
+  auto* t = p->texture_sampler_types();
+  EXPECT_EQ(t, nullptr);
+  EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
+  auto* p = parser("texture_ro_1d");
+  auto* t = p->texture_sampler_types();
+  EXPECT_EQ(t, nullptr);
+  EXPECT_EQ(p->error(), "1:14: missing '<' for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
+  auto* p = parser("texture_wo_1d<r8unorm");
+  auto* t = p->texture_sampler_types();
+  EXPECT_EQ(t, nullptr);
+  EXPECT_EQ(p->error(), "1:22: missing '>' for storage texture type");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace reader
diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc
index 5b9e595..58d60f4 100644
--- a/src/reader/wgsl/token.cc
+++ b/src/reader/wgsl/token.cc
@@ -289,6 +289,16 @@
       return "texture_depth_cube";
     case Token::Type::kTextureDepthCubeArray:
       return "texture_depth_cube_array";
+    case Token::Type::kTextureStorageReadonly1d:
+      return "texture_ro_1d";
+    case Token::Type::kTextureStorageReadonly1dArray:
+      return "texture_ro_1d_array";
+    case Token::Type::kTextureStorageReadonly2d:
+      return "texture_ro_2d";
+    case Token::Type::kTextureStorageReadonly2dArray:
+      return "texture_ro_2d_array";
+    case Token::Type::kTextureStorageReadonly3d:
+      return "texture_ro_3d";
     case Token::Type::kTextureSampled1d:
       return "texture_sampled_1d";
     case Token::Type::kTextureSampled1dArray:
@@ -307,6 +317,16 @@
       return "texture_sampled_cube";
     case Token::Type::kTextureSampledCubeArray:
       return "texture_sampled_cube_array";
+    case Token::Type::kTextureStorageWriteonly1d:
+      return "texture_wo_1d";
+    case Token::Type::kTextureStorageWriteonly1dArray:
+      return "texture_wo_1d_array";
+    case Token::Type::kTextureStorageWriteonly2d:
+      return "texture_wo_2d";
+    case Token::Type::kTextureStorageWriteonly2dArray:
+      return "texture_wo_2d_array";
+    case Token::Type::kTextureStorageWriteonly3d:
+      return "texture_wo_3d";
     case Token::Type::kTrue:
       return "true";
     case Token::Type::kType:
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h
index e893bca..2e9f2da 100644
--- a/src/reader/wgsl/token.h
+++ b/src/reader/wgsl/token.h
@@ -300,6 +300,16 @@
     kTextureDepthCube,
     /// A 'texture_depth_cube_array'
     kTextureDepthCubeArray,
+    /// A 'texture_ro_1d'
+    kTextureStorageReadonly1d,
+    /// A 'texture_ro_2d_array'
+    kTextureStorageReadonly1dArray,
+    /// A 'texture_ro_2d'
+    kTextureStorageReadonly2d,
+    /// A 'texture_ro_2d_array'
+    kTextureStorageReadonly2dArray,
+    /// A 'texture_ro_3d'
+    kTextureStorageReadonly3d,
     /// A 'texture_sampled_1d'
     kTextureSampled1d,
     /// A 'texture_sampled_1d_array'
@@ -318,6 +328,16 @@
     kTextureSampledCube,
     /// A 'texture_sampled_cube_array'
     kTextureSampledCubeArray,
+    /// A 'texture_wo_1d'
+    kTextureStorageWriteonly1d,
+    /// A 'texture_wo_2d_array'
+    kTextureStorageWriteonly1dArray,
+    /// A 'texture_wo_2d'
+    kTextureStorageWriteonly2d,
+    /// A 'texture_wo_2d_array'
+    kTextureStorageWriteonly2dArray,
+    /// A 'texture_wo_3d'
+    kTextureStorageWriteonly3d,
     /// A 'true'
     kTrue,
     /// A 'type'
@@ -669,6 +689,26 @@
   bool IsTextureDepthCubeArray() const {
     return type_ == Type::kTextureDepthCubeArray;
   }
+  /// @returns true if token is a 'texture_ro_1d'
+  bool IsTextureStorageReadonly1d() const {
+    return type_ == Type::kTextureStorageReadonly1d;
+  }
+  /// @returns true if token is a 'texture_ro_1d_array'
+  bool IsTextureStorageReadonly1dArray() const {
+    return type_ == Type::kTextureStorageReadonly1dArray;
+  }
+  /// @returns true if token is a 'texture_ro_2d'
+  bool IsTextureStorageReadonly2d() const {
+    return type_ == Type::kTextureStorageReadonly2d;
+  }
+  /// @returns true if token is a 'texture_ro_2d_array'
+  bool IsTextureStorageReadonly2dArray() const {
+    return type_ == Type::kTextureStorageReadonly2dArray;
+  }
+  /// @returns true if token is a 'texture_ro_3d'
+  bool IsTextureStorageReadonly3d() const {
+    return type_ == Type::kTextureStorageReadonly3d;
+  }
   /// @returns true if token is a 'texture_sampled_1d'
   bool IsTextureSampled1d() const { return type_ == Type::kTextureSampled1d; }
   /// @returns true if token is a 'texture_sampled_1d_array'
@@ -699,6 +739,26 @@
   bool IsTextureSampledCubeArray() const {
     return type_ == Type::kTextureSampledCubeArray;
   }
+  /// @returns true if token is a 'texture_wo_1d'
+  bool IsTextureStorageWriteonly1d() const {
+    return type_ == Type::kTextureStorageWriteonly1d;
+  }
+  /// @returns true if token is a 'texture_wo_1d_array'
+  bool IsTextureStorageWriteonly1dArray() const {
+    return type_ == Type::kTextureStorageWriteonly1dArray;
+  }
+  /// @returns true if token is a 'texture_wo_2d'
+  bool IsTextureStorageWriteonly2d() const {
+    return type_ == Type::kTextureStorageWriteonly2d;
+  }
+  /// @returns true if token is a 'texture_wo_2d_array'
+  bool IsTextureStorageWriteonly2dArray() const {
+    return type_ == Type::kTextureStorageWriteonly2dArray;
+  }
+  /// @returns true if token is a 'texture_wo_3d'
+  bool IsTextureStorageWriteonly3d() const {
+    return type_ == Type::kTextureStorageWriteonly3d;
+  }
   /// @returns true if token is a 'true'
   bool IsTrue() const { return type_ == Type::kTrue; }
   /// @returns true if token is a 'type'