diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index 5fd1ef49a2..c1263b7362 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -495,6 +495,8 @@ Token Lexer::check_keyword(const Source& source, const std::string& str) { return {Token::Type::kContinue, source, "continue"}; if (str == "continuing") return {Token::Type::kContinuing, source, "continuing"}; + if (str == "discard") + return {Token::Type::kDiscard, source, "discard"}; if (str == "default") return {Token::Type::kDefault, source, "default"}; if (str == "else") diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc index de64e6f6bd..aa731affbe 100644 --- a/src/reader/wgsl/lexer_test.cc +++ b/src/reader/wgsl/lexer_test.cc @@ -425,6 +425,7 @@ INSTANTIATE_TEST_SUITE_P( TokenData{"continue", Token::Type::kContinue}, TokenData{"continuing", Token::Type::kContinuing}, TokenData{"default", Token::Type::kDefault}, + TokenData{"discard", Token::Type::kDiscard}, TokenData{"else", Token::Type::kElse}, TokenData{"elseif", Token::Type::kElseIf}, TokenData{"entry_point", Token::Type::kEntryPoint}, diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index c3e7318aa8..dd4a625763 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -29,6 +29,7 @@ #include "src/ast/cast_expression.h" #include "src/ast/continue_statement.h" #include "src/ast/decorated_variable.h" +#include "src/ast/discard_statement.h" #include "src/ast/else_statement.h" #include "src/ast/fallthrough_statement.h" #include "src/ast/float_literal.h" @@ -1426,6 +1427,7 @@ ast::StatementList ParserImpl::statements() { // | variable_stmt SEMICOLON // | break_stmt SEMICOLON // | continue_stmt SEMICOLON +// | DISCARD SEMICOLON // | KILL SEMICOLON // | assignment_stmt SEMICOLON std::unique_ptr ParserImpl::statement() { @@ -1513,6 +1515,18 @@ std::unique_ptr ParserImpl::statement() { return cont; } + if (t.IsDiscard()) { + auto source = t.source(); + next(); // Consume the peek + + t = next(); + if (!t.IsSemicolon()) { + set_error(t, "missing ;"); + return nullptr; + } + return std::make_unique(source); + } + if (t.IsKill()) { auto source = t.source(); next(); // Consume the peek diff --git a/src/reader/wgsl/parser_impl_statement_test.cc b/src/reader/wgsl/parser_impl_statement_test.cc index 9df6b49b51..f5f06f0ee3 100644 --- a/src/reader/wgsl/parser_impl_statement_test.cc +++ b/src/reader/wgsl/parser_impl_statement_test.cc @@ -221,6 +221,22 @@ TEST_F(ParserImplTest, Statement_Kill_MissingSemicolon) { EXPECT_EQ(p->error(), "1:5: missing ;"); } +TEST_F(ParserImplTest, Statement_Discard) { + auto* p = parser("discard;"); + auto e = p->statement(); + ASSERT_FALSE(p->has_error()) << p->error(); + EXPECT_NE(e, nullptr); + ASSERT_TRUE(e->IsDiscard()); +} + +TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) { + auto* p = parser("discard"); + auto e = p->statement(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(e, nullptr); + EXPECT_EQ(p->error(), "1:8: missing ;"); +} + } // namespace } // namespace wgsl } // namespace reader diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc index 0a91ca6eb0..91c489a114 100644 --- a/src/reader/wgsl/token.cc +++ b/src/reader/wgsl/token.cc @@ -131,6 +131,8 @@ std::string Token::TypeToName(Type type) { return "continue"; case Token::Type::kContinuing: return "continuing"; + case Token::Type::kDiscard: + return "discard"; case Token::Type::kDefault: return "default"; case Token::Type::kElse: diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h index 8545cfa792..8e2ffec561 100644 --- a/src/reader/wgsl/token.h +++ b/src/reader/wgsl/token.h @@ -142,6 +142,8 @@ class Token { kContinue, /// A 'continuing' kContinuing, + /// A 'discard' + kDiscard, /// A 'default' kDefault, /// A 'else' @@ -395,6 +397,8 @@ class Token { bool IsContinue() const { return type_ == Type::kContinue; } /// @returns true if token is a 'continuing' bool IsContinuing() const { return type_ == Type::kContinuing; } + /// @returns true if token is a 'discard' + bool IsDiscard() const { return type_ == Type::kDiscard; } /// @returns true if token is a 'default' bool IsDefault() const { return type_ == Type::kDefault; } /// @returns true if token is a 'else'