diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 8fc397b641..1e4a834bd4 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -27,6 +27,7 @@ #include "src/ast/builtin_decoration.h" #include "src/ast/call_expression.h" #include "src/ast/case_statement.h" +#include "src/ast/constant_id_decoration.h" #include "src/ast/continue_statement.h" #include "src/ast/discard_statement.h" #include "src/ast/else_statement.h" @@ -134,6 +135,7 @@ const char kAccessDecoration[] = "access"; const char kBindingDecoration[] = "binding"; const char kBlockDecoration[] = "block"; const char kBuiltinDecoration[] = "builtin"; +const char kConstantIdDecoration[] = "constant_id"; const char kGroupDecoration[] = "group"; const char kLocationDecoration[] = "location"; const char kOffsetDecoration[] = "offset"; @@ -149,10 +151,10 @@ bool is_decoration(Token t) { auto s = t.to_str(); return s == kAccessDecoration || s == kBindingDecoration || s == kBlockDecoration || s == kBuiltinDecoration || - s == kLocationDecoration || s == kOffsetDecoration || - s == kSetDecoration || s == kGroupDecoration || - s == kStageDecoration || s == kStrideDecoration || - s == kWorkgroupSizeDecoration; + s == kConstantIdDecoration || s == kLocationDecoration || + s == kOffsetDecoration || s == kSetDecoration || + s == kGroupDecoration || s == kStageDecoration || + s == kStrideDecoration || s == kWorkgroupSizeDecoration; } /// Enter-exit counters for block token types. @@ -323,7 +325,7 @@ Expect ParserImpl::expect_global_decl() { return true; } - auto gc = global_constant_decl(); + auto gc = global_constant_decl(decos.value); if (gc.errored) return Failure::kErrored; @@ -441,8 +443,9 @@ Maybe ParserImpl::global_variable_decl( } // global_constant_decl -// : CONST variable_ident_decl EQUAL const_expr -Maybe ParserImpl::global_constant_decl() { +// : variable_decoration_list* CONST variable_ident_decl EQUAL const_expr +Maybe ParserImpl::global_constant_decl( + ast::DecorationList& decos) { if (!match(Token::Type::kConst)) return Failure::kNoMatch; @@ -459,6 +462,10 @@ Maybe ParserImpl::global_constant_decl() { if (init.errored) return Failure::kErrored; + auto var_decos = cast_decorations(decos); + if (var_decos.errored) + return Failure::kErrored; + return create( decl->source, // source builder_.Symbols().Register(decl->name), // symbol @@ -466,7 +473,7 @@ Maybe ParserImpl::global_constant_decl() { decl->type, // type true, // is_const init.value, // constructor - ast::VariableDecorationList{}); // decorations + std::move(var_decos.value)); // decorations } // variable_decl @@ -2939,6 +2946,17 @@ Maybe ParserImpl::decoration() { }); } + if (s == kConstantIdDecoration) { + const char* use = "constant_id decoration"; + return expect_paren_block(use, [&]() -> Result { + auto val = expect_positive_sint(use); + if (val.errored) + return Failure::kErrored; + + return create(t.source(), val.value); + }); + } + return Failure::kNoMatch; } diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 56229b79d9..4105416c07 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -365,9 +365,11 @@ class ParserImpl { /// @returns the variable parsed or nullptr /// @param decos the list of decorations for the variable declaration. Maybe global_variable_decl(ast::DecorationList& decos); - /// Parses a `global_constant_decl` grammar element + /// Parses a `global_constant_decl` grammar element with the initial + /// `variable_decoration_list*` provided as `decos` /// @returns the const object or nullptr - Maybe global_constant_decl(); + /// @param decos the list of decorations for the constant declaration. + Maybe global_constant_decl(ast::DecorationList& decos); /// Parses a `variable_decl` grammar element /// @returns the parsed variable declaration info Maybe variable_decl(); diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc index ca2b7f49eb..2025e3b645 100644 --- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc +++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc @@ -26,7 +26,10 @@ namespace { TEST_F(ParserImplTest, GlobalConstantDecl) { auto p = parser("const a : f32 = 1."); - auto e = p->global_constant_decl(); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_constant_decl(decos.value); EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched); EXPECT_FALSE(e.errored); @@ -44,11 +47,16 @@ TEST_F(ParserImplTest, GlobalConstantDecl) { ASSERT_NE(e->constructor(), nullptr); EXPECT_TRUE(e->constructor()->Is()); + + EXPECT_FALSE(e.value->HasConstantIdDecoration()); } TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) { auto p = parser("const a: f32 1."); - auto e = p->global_constant_decl(); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_constant_decl(decos.value); EXPECT_TRUE(p->has_error()); EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); @@ -58,7 +66,10 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { auto p = parser("const a: invalid = 1."); - auto e = p->global_constant_decl(); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_constant_decl(decos.value); EXPECT_TRUE(p->has_error()); EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); @@ -68,7 +79,10 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) { auto p = parser("const a: f32 = if (a) {}"); - auto e = p->global_constant_decl(); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_constant_decl(decos.value); EXPECT_TRUE(p->has_error()); EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); @@ -78,7 +92,10 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) { auto p = parser("const a: f32 ="); - auto e = p->global_constant_decl(); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_constant_decl(decos.value); EXPECT_TRUE(p->has_error()); EXPECT_TRUE(e.errored); EXPECT_FALSE(e.matched); @@ -86,6 +103,66 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) { EXPECT_EQ(p->error(), "1:15: unable to parse const literal"); } +TEST_F(ParserImplTest, GlobalConstantDec_ConstantId) { + auto p = parser("[[constant_id(7)]] const a : f32 = 1."); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + + auto e = p->global_constant_decl(decos.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + + EXPECT_TRUE(e->is_const()); + EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a")); + ASSERT_NE(e->type(), nullptr); + EXPECT_TRUE(e->type()->Is()); + + EXPECT_EQ(e->source().range.begin.line, 1u); + EXPECT_EQ(e->source().range.begin.column, 26u); + EXPECT_EQ(e->source().range.end.line, 1u); + EXPECT_EQ(e->source().range.end.column, 27u); + + ASSERT_NE(e->constructor(), nullptr); + EXPECT_TRUE(e->constructor()->Is()); + + EXPECT_TRUE(e.value->HasConstantIdDecoration()); + EXPECT_EQ(e.value->constant_id(), 7u); +} + +TEST_F(ParserImplTest, GlobalConstantDec_ConstantId_Missing) { + auto p = parser("[[constant_id()]] const a : f32 = 1."); + auto decos = p->decoration_list(); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto e = p->global_constant_decl(decos.value); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), + "1:15: expected signed integer literal for constant_id decoration"); +} + +TEST_F(ParserImplTest, GlobalConstantDec_ConstantId_Invalid) { + auto p = parser("[[constant_id(-7)]] const a : f32 = 1."); + auto decos = p->decoration_list(); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto e = p->global_constant_decl(decos.value); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:15: constant_id decoration must be positive"); +} + } // namespace } // namespace wgsl } // namespace reader