diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index ec4fc3943e..c53354896b 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -110,12 +110,10 @@ ast::Builtin ident_to_builtin(const std::string& str) { return ast::Builtin::kNone; } -bool IsVariableDecoration(Token t) { - return t.IsLocation() || t.IsBuiltin() || t.IsBinding() || t.IsSet(); -} - -bool IsFunctionDecoration(Token t) { - return t.IsWorkgroupSize() || t.IsStage(); +bool is_decoration(Token t) { + return t.IsLocation() || t.IsBinding() || t.IsSet() || t.IsBuiltin() || + t.IsWorkgroupSize() || t.IsStage() || t.IsBlock() || t.IsStride() || + t.IsOffset(); } } // namespace @@ -219,7 +217,9 @@ void ParserImpl::global_decl() { return; } - auto gv = global_variable_decl(); + auto decos = decoration_list(); + + auto gv = global_variable_decl(decos); if (has_error()) { return; } @@ -255,7 +255,7 @@ void ParserImpl::global_decl() { return; } - auto str = struct_decl(); + auto str = struct_decl(decos); if (has_error()) { return; } @@ -269,7 +269,7 @@ void ParserImpl::global_decl() { return; } - auto func = function_decl(); + auto func = function_decl(decos); if (has_error()) { return; } @@ -278,40 +278,27 @@ void ParserImpl::global_decl() { return; } - add_error(t, "invalid token"); + t = peek(); + if (decos.size() > 0) { + add_error(t, "expected declaration after decorations"); + } else { + add_error(t, "invalid token"); + } } // global_variable_decl // : variable_decoration_list* variable_decl // | variable_decoration_list* variable_decl EQUAL const_expr -std::unique_ptr ParserImpl::global_variable_decl() { - ast::VariableDecorationList decos; - for (;;) { - auto s = decos.size(); - if (!variable_decoration_list(decos)) { - return nullptr; - } - if (s == decos.size()) { - break; - } - } - if (has_error()) - return nullptr; - +std::unique_ptr ParserImpl::global_variable_decl( + ast::DecorationList& decos) { auto var = variable_decl(); - if (has_error()) + if (has_error() || var == nullptr) return nullptr; - if (var == nullptr) { - if (decos.size() > 0) - add_error(peek(), "error parsing variable declaration"); - return nullptr; - } - - if (decos.size() > 0) { + auto var_decos = cast_decorations(decos); + if (var_decos.size() > 0) { auto dv = std::make_unique(std::move(var)); - dv->set_decorations(std::move(decos)); - + dv->set_decorations(std::move(var_decos)); var = std::move(dv); } @@ -365,113 +352,6 @@ std::unique_ptr ParserImpl::global_constant_decl() { return var; } -// variable_decoration_list -// : ATTR_LEFT (variable_decoration COMMA)* variable_decoration ATTR_RIGHT -bool ParserImpl::variable_decoration_list(ast::VariableDecorationList& decos) { - auto t = peek(); - if (!t.IsAttrLeft()) { - return true; - } - - // Check the empty list before verifying the contents - t = peek(1); - if (t.IsAttrRight()) { - add_error(t, "empty variable decoration list"); - return false; - } - - // Make sure we're looking at variable decorations not some other kind - if (!IsVariableDecoration(peek(1))) { - return true; - } - - next(); // consume the peek - - auto deco = variable_decoration(); - if (has_error()) { - return false; - } - if (deco == nullptr) { - add_error(peek(), "missing variable decoration for decoration list"); - return false; - } - for (;;) { - decos.push_back(std::move(deco)); - - if (!match(Token::Type::kComma)) - break; - - deco = variable_decoration(); - if (has_error()) { - return false; - } - if (deco == nullptr) { - add_error(peek(), "missing variable decoration after comma"); - return false; - } - } - - t = peek(); - if (!t.IsAttrRight()) { - deco = variable_decoration(); - if (deco != nullptr) { - add_error(t, "missing comma in variable decoration list"); - return false; - } - add_error(t, "missing ]] for variable decoration"); - return false; - } - next(); // consume the peek - - return true; -} - -// variable_decoration -// : 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 ParserImpl::variable_decoration() { - Source source; - if (match(Token::Type::kLocation, &source)) { - const char* use = "location decoration"; - return expect_paren_block(use, [&] { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, source) - : nullptr; - }); - } - if (match(Token::Type::kBuiltin, &source)) { - return expect_paren_block("builtin decoration", [&] { - ast::Builtin builtin; - std::tie(builtin, source) = expect_builtin(); - return (builtin != ast::Builtin::kNone) - ? std::make_unique(builtin, source) - : nullptr; - }); - } - if (match(Token::Type::kBinding, &source)) { - const char* use = "binding decoration"; - return expect_paren_block(use, [&] { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, source) - : nullptr; - }); - } - if (match(Token::Type::kSet, &source)) { - const char* use = "set decoration"; - return expect_paren_block(use, [&] { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, source) : nullptr; - }); - } - - return nullptr; -} - // variable_decl // : VAR variable_storage_decoration? variable_ident_decl std::unique_ptr ParserImpl::variable_decl() { @@ -1012,30 +892,18 @@ ast::type::Type* ParserImpl::type_decl() { return type_decl_pointer(t); } - ast::ArrayDecorationList decos; - for (;;) { - size_t s = decos.size(); - if (!array_decoration_list(decos)) { - return nullptr; - } - if (decos.size() == s) { - break; - } - } + auto decos = decoration_list(); if (has_error()) { return nullptr; } - if (!decos.empty()) { - t = peek(); - } - if (!decos.empty() && !t.IsArray()) { - add_error(t, "found array decoration but no array"); - return nullptr; - } - if (t.IsArray()) { - next(); // Consume the peek - return type_decl_array(std::move(decos)); + + if (match(Token::Type::kArray)) { + auto array_decos = cast_decorations(decos); + return type_decl_array(std::move(array_decos)); } + + expect_decorations_consumed(decos); + if (t.IsMat2x2() || t.IsMat2x3() || t.IsMat2x4() || t.IsMat3x2() || t.IsMat3x3() || t.IsMat3x4() || t.IsMat4x2() || t.IsMat4x3() || t.IsMat4x4()) { @@ -1155,56 +1023,6 @@ ast::type::Type* ParserImpl::type_decl_array(ast::ArrayDecorationList decos) { return ctx_.type_mgr().Get(std::move(ty)); } -// array_decoration_list -// : ATTR_LEFT (array_decoration COMMA)* array_decoration ATTR_RIGHT -// array_decoration -// : STRIDE PAREN_LEFT INT_LITERAL PAREN_RIGHT -// -// As there is currently only one decoration I'm combining these for now. -// we can split apart later if needed. -bool ParserImpl::array_decoration_list(ast::ArrayDecorationList& decos) { - auto t = peek(); - if (!t.IsAttrLeft()) { - return true; - } - t = peek(1); - if (!t.IsStride()) { - return true; - } - - next(); // consume the peek of [[ - - for (;;) { - Source source; - if (match(Token::Type::kStride, &source)) { - const char* use = "stride decoration"; - auto deco = expect_paren_block(use, [&] { - uint32_t val; - bool ok = expect_nonzero_positive_sint(use, &val); - return ok ? std::make_unique(val, source) - : nullptr; - }); - - if (!deco) - return false; - - decos.emplace_back(std::move(deco)); - } else { - add_error(source, "unknown array decoration"); - return false; - } - - if (!match(Token::Type::kComma)) - break; - } - - if (!expect("array decoration", Token::Type::kAttrRight)) { - return false; - } - - return true; -} - ast::type::Type* ParserImpl::type_decl_matrix(Token t) { next(); // Consume the peek @@ -1298,29 +1116,15 @@ ast::StorageClass ParserImpl::storage_class() { // struct_decl // : struct_decoration_decl* STRUCT IDENT struct_body_decl -std::unique_ptr ParserImpl::struct_decl() { +std::unique_ptr ParserImpl::struct_decl( + ast::DecorationList& decos) { auto t = peek(); auto source = t.source(); - ast::StructDecorationList decos; - for (;;) { - size_t s = decos.size(); - if (!struct_decoration_decl(decos)) { - return nullptr; - } - if (decos.size() == s) { - break; - } - } + if (!match(Token::Type::kStruct)) + return nullptr; - t = peek(); - if (!decos.empty() && !t.IsStruct()) { - add_error(t, "missing struct declaration"); - return nullptr; - } else if (!t.IsStruct()) { - return nullptr; - } - next(); // Consume the peek + auto struct_decos = cast_decorations(decos); std::string name; if (!expect_ident("struct declaration", &name)) @@ -1332,46 +1136,8 @@ std::unique_ptr ParserImpl::struct_decl() { } return std::make_unique( - name, - std::make_unique(source, std::move(decos), std::move(body))); -} - -// struct_decoration_decl -// : ATTR_LEFT struct_decoration ATTR_RIGHT -bool ParserImpl::struct_decoration_decl(ast::StructDecorationList& decos) { - auto t = peek(); - if (!t.IsAttrLeft()) { - return true; - } - - auto deco = struct_decoration(peek(1)); - if (has_error()) { - return false; - } - if (deco == nullptr) { - return true; - } - decos.emplace_back(std::move(deco)); - - next(); // Consume the peek of [[ - next(); // Consume the peek from the struct_decoration - - t = next(); - if (!t.IsAttrRight()) { - add_error(t, "missing ]] for struct decoration"); - return false; - } - - return true; -} - -// struct_decoration -// : BLOCK -std::unique_ptr ParserImpl::struct_decoration(Token t) { - if (t.IsBlock()) { - return std::make_unique(t.source()); - } - return nullptr; + name, std::make_unique(source, std::move(struct_decos), + std::move(body))); } // struct_body_decl @@ -1381,7 +1147,9 @@ ast::StructMemberList ParserImpl::struct_body_decl() { ast::StructMemberList members; while (!peek().IsBraceRight() && !peek().IsEof()) { - auto mem = struct_member(); + auto decos = decoration_list(); + + auto mem = struct_member(decos); if (has_error()) return ast::StructMemberList{}; if (mem == nullptr) { @@ -1398,22 +1166,10 @@ ast::StructMemberList ParserImpl::struct_body_decl() { // struct_member // : struct_member_decoration_decl+ variable_ident_decl SEMICOLON -std::unique_ptr ParserImpl::struct_member() { +std::unique_ptr ParserImpl::struct_member( + ast::DecorationList& decos) { auto t = peek(); - ast::StructMemberDecorationList decos; - for (;;) { - size_t s = decos.size(); - if (!struct_member_decoration_decl(decos)) { - return nullptr; - } - if (decos.size() == s) { - break; - } - } - if (has_error()) - return nullptr; - auto decl = variable_ident_decl(); if (has_error()) return nullptr; @@ -1422,90 +1178,25 @@ std::unique_ptr ParserImpl::struct_member() { return nullptr; } + auto member_decos = cast_decorations(decos); + if (!expect("struct member", Token::Type::kSemicolon)) return nullptr; return std::make_unique(decl.source, decl.name, decl.type, - std::move(decos)); -} - -// struct_member_decoration_decl -// : -// | ATTR_LEFT (struct_member_decoration COMMA)* -// struct_member_decoration ATTR_RIGHT -bool ParserImpl::struct_member_decoration_decl( - ast::StructMemberDecorationList& decos) { - if (!match(Token::Type::kAttrLeft)) - return true; - - auto t = peek(); - if (t.IsAttrRight()) { - add_error(t, "empty struct member decoration found"); - return false; - } - - for (;;) { - auto deco = struct_member_decoration(); - if (has_error()) - return false; - if (deco == nullptr) - break; - - decos.push_back(std::move(deco)); - - t = next(); - if (!t.IsComma()) - break; - } - - if (!t.IsAttrRight()) { - add_error(t, "missing ]] for struct member decoration"); - return false; - } - return true; -} - -// struct_member_decoration -// : OFFSET PAREN_LEFT INT_LITERAL PAREN_RIGHT -std::unique_ptr -ParserImpl::struct_member_decoration() { - Source source; - if (!match(Token::Type::kOffset, &source)) - return nullptr; - - const char* use = "offset decoration"; - return expect_paren_block(use, [&] { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, source) - : nullptr; - }); + std::move(member_decos)); } // function_decl -// : function_decoration_decl* function_header body_stmt -std::unique_ptr ParserImpl::function_decl() { - ast::FunctionDecorationList decos; - for (;;) { - size_t s = decos.size(); - if (!function_decoration_decl(decos)) { - return nullptr; - } - if (decos.size() == s) { - break; - } - } - +// : function_header body_stmt +std::unique_ptr ParserImpl::function_decl( + ast::DecorationList& decos) { auto f = function_header(); - if (has_error()) + if (f == nullptr || has_error()) return nullptr; - if (f == nullptr) { - if (decos.size() > 0) { - add_error(peek(), "error parsing function declaration"); - } - return nullptr; - } - f->set_decorations(std::move(decos)); + + auto func_decos = cast_decorations(decos); + f->set_decorations(std::move(func_decos)); auto body = body_stmt(); if (has_error()) @@ -1515,98 +1206,6 @@ std::unique_ptr ParserImpl::function_decl() { return f; } -// function_decoration_decl -// : ATTR_LEFT (function_decoration COMMA)* function_decoration ATTR_RIGHT -bool ParserImpl::function_decoration_decl(ast::FunctionDecorationList& decos) { - auto t = peek(); - if (!t.IsAttrLeft()) { - return true; - } - // Handle error on empty attributes before the type check - t = peek(1); - if (t.IsAttrRight()) { - add_error(t, "missing decorations for function decoration block"); - return false; - } - - // Make sure we're looking at function decorations and not some other kind - if (!IsFunctionDecoration(peek(1))) { - return true; - } - - next(); // Consume the peek - - size_t count = 0; - for (;;) { - auto deco = function_decoration(); - if (has_error()) { - return false; - } - if (deco == nullptr) { - add_error(peek(), "expected decoration but none found"); - return false; - } - decos.push_back(std::move(deco)); - count++; - - t = peek(); - if (!t.IsComma()) { - break; - } - next(); // Consume the peek - } - if (count == 0) { - add_error(peek(), "missing decorations for function decoration block"); - return false; - } - - t = next(); - if (!t.IsAttrRight()) { - add_error(t, "missing ]] for function decorations"); - return false; - } - return true; -} - -// function_decoration -// : STAGE PAREN_LEFT pipeline_stage PAREN_RIGHT -// | WORKGROUP_SIZE PAREN_LEFT INT_LITERAL -// (COMMA INT_LITERAL (COMMA INT_LITERAL)?)? PAREN_RIGHT -std::unique_ptr ParserImpl::function_decoration() { - Source source; - if (match(Token::Type::kWorkgroupSize, &source)) { - return expect_paren_block("workgroup_size decoration", [&]() { - uint32_t x; - if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) { - return std::unique_ptr(nullptr); - } - uint32_t y = 1; - uint32_t z = 1; - if (match(Token::Type::kComma)) { - if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) { - return std::unique_ptr(nullptr); - } - if (match(Token::Type::kComma)) { - if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) { - return std::unique_ptr(nullptr); - } - } - } - return std::make_unique(x, y, z, source); - }); - } - if (match(Token::Type::kStage, &source)) { - return expect_paren_block("stage decoration", [&]() { - ast::PipelineStage stage; - std::tie(stage, source) = expect_pipeline_stage(); - return (stage != ast::PipelineStage::kNone) - ? std::make_unique(stage, source) - : nullptr; - }); - } - return nullptr; -} - // function_type_decl // : type_decl // | VOID @@ -3174,6 +2773,186 @@ std::unique_ptr ParserImpl::const_expr_internal( std::move(lit)); } +ast::DecorationList ParserImpl::decoration_list() { + ast::DecorationList decos; + while (decoration_bracketed_list(decos)) { + } + return decos; +} + +bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { + if (!match(Token::Type::kAttrLeft)) { + return false; + } + + auto t = peek(); + if (match(Token::Type::kAttrRight)) { + add_error(t, "empty decoration list"); + return false; + } + + while (true) { + if (auto deco = expect_decoration()) { + decos.emplace_back(std::move(deco)); + } else { + return false; + } + + if (has_error()) { + return false; + } + + if (match(Token::Type::kComma)) { + continue; + } + + if (is_decoration(peek())) { + // We have two decorations in a bracket without a separating comma. + // e.g. [[location(1) set(2)]] + // ^^^ expected comma + expect("decoration list", Token::Type::kComma); + return false; + } + + return expect("decoration list", Token::Type::kAttrRight); + } +} + +std::unique_ptr ParserImpl::expect_decoration() { + auto t = peek(); + if (auto deco = decoration()) { + return deco; + } + if (!has_error()) { + add_error(t, "expected decoration"); + } + return nullptr; +} + +std::unique_ptr ParserImpl::decoration() { + auto t = next(); + if (t.IsLocation()) { + const char* use = "location decoration"; + return expect_paren_block(use, [&]() { + uint32_t val; + bool ok = expect_positive_sint(use, &val); + return ok ? std::make_unique(val, t.source()) + : nullptr; + }); + } + if (t.IsBinding()) { + const char* use = "binding decoration"; + return expect_paren_block(use, [&]() { + uint32_t val; + bool ok = expect_positive_sint(use, &val); + return ok ? std::make_unique(val, t.source()) + : nullptr; + }); + } + if (t.IsSet()) { + const char* use = "set decoration"; + return expect_paren_block(use, [&]() { + uint32_t val; + bool ok = expect_positive_sint(use, &val); + return ok ? std::make_unique(val, t.source()) + : nullptr; + }); + } + if (t.IsBuiltin()) { + return expect_paren_block("builtin decoration", [&]() { + ast::Builtin builtin; + Source source; + std::tie(builtin, source) = expect_builtin(); + return (builtin != ast::Builtin::kNone) + ? std::make_unique(builtin, source) + : nullptr; + }); + } + if (t.IsWorkgroupSize()) { + return expect_paren_block("workgroup_size decoration", [&]() { + uint32_t x; + if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) { + return std::unique_ptr(nullptr); + } + uint32_t y = 1; + uint32_t z = 1; + if (match(Token::Type::kComma)) { + if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) { + return std::unique_ptr(nullptr); + } + if (match(Token::Type::kComma)) { + if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) { + return std::unique_ptr(nullptr); + } + } + } + return std::make_unique(x, y, z, t.source()); + }); + } + if (t.IsStage()) { + return expect_paren_block("stage decoration", [&]() { + ast::PipelineStage stage; + Source source; + std::tie(stage, source) = expect_pipeline_stage(); + return (stage != ast::PipelineStage::kNone) + ? std::make_unique(stage, source) + : nullptr; + }); + } + if (t.IsBlock()) { + return std::make_unique(t.source()); + } + if (t.IsStride()) { + const char* use = "stride decoration"; + return expect_paren_block(use, [&]() { + uint32_t val; + bool ok = expect_nonzero_positive_sint(use, &val); + return ok ? std::make_unique(val, t.source()) + : nullptr; + }); + } + if (t.IsOffset()) { + const char* use = "offset decoration"; + return expect_paren_block(use, [&]() { + uint32_t val; + bool ok = expect_positive_sint(use, &val); + return ok ? std::make_unique( + val, t.source()) + : nullptr; + }); + } + return nullptr; +} + +template +std::vector> ParserImpl::cast_decorations( + ast::DecorationList& in) { + std::vector> out; + out.reserve(in.size()); + for (auto& deco : in) { + if (!deco->Is()) { + std::stringstream msg; + msg << deco->GetKind() << " decoration type cannot be used for " + << T::Kind; + add_error(deco->GetSource(), msg.str()); + continue; + } + out.emplace_back(ast::As(std::move(deco))); + } + // clear in so that we can verify decorations were consumed with + // expect_decorations_consumed() + in.clear(); + return out; +} + +bool ParserImpl::expect_decorations_consumed(const ast::DecorationList& in) { + if (in.empty()) { + return true; + } + add_error(in[0]->GetSource(), "unexpected decorations"); + return false; +} + bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) { auto t = peek(); diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index e1de67fe44..dd4dd11503 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "src/ast/array_decoration.h" #include "src/ast/assignment_statement.h" @@ -156,20 +157,15 @@ class ParserImpl { void translation_unit(); /// Parses the `global_decl` grammar element void global_decl(); - /// Parses a `global_variable_decl` grammar element + /// Parses a `global_variable_decl` grammar element with the initial + /// `variable_decoration_list*` provided as |decos|. /// @returns the variable parsed or nullptr - std::unique_ptr global_variable_decl(); + /// @param decos the list of decorations for the variable declaration. + std::unique_ptr global_variable_decl( + ast::DecorationList& decos); /// Parses a `global_constant_decl` grammar element /// @returns the const object or nullptr std::unique_ptr global_constant_decl(); - /// Parses a `variable_decoration_list` grammar element, appending newly - /// parsed decorations to the end of |decos|. - /// @param decos list to store the parsed decorations - /// @returns the true on successful parse; false otherwise - bool variable_decoration_list(ast::VariableDecorationList& decos); - /// Parses a `variable_decoration` grammar element - /// @returns the variable decoration or nullptr if an error is encountered - std::unique_ptr variable_decoration(); /// Parses a `variable_decl` grammar element /// @returns the parsed variable or nullptr otherwise std::unique_ptr variable_decl(); @@ -188,43 +184,25 @@ class ParserImpl { /// Parses a `storage_class` grammar element /// @returns the storage class or StorageClass::kNone if none matched ast::StorageClass storage_class(); - /// Parses a `struct_decl` grammar element + /// Parses a `struct_decl` grammar element with the initial + /// `struct_decoration_decl*` provided as |decos|. /// @returns the struct type or nullptr on error - std::unique_ptr struct_decl(); - /// Parses a `struct_decoration_decl` grammar element, appending newly - /// parsed decorations to the end of |decos|. - /// @param decos list to store the parsed decorations - /// @returns the true on successful parse; false otherwise - bool struct_decoration_decl(ast::StructDecorationList& decos); - /// Parses a `struct_decoration` grammar element - /// @param t the current token - /// @returns the struct decoration or StructDecoraton::kNone if none matched - std::unique_ptr struct_decoration(Token t); + /// @param decos the list of decorations for the struct declaration. + std::unique_ptr struct_decl( + ast::DecorationList& decos); /// Parses a `struct_body_decl` grammar element /// @returns the struct members ast::StructMemberList struct_body_decl(); - /// Parses a `struct_member` grammar element + /// Parses a `struct_member` grammar element with the initial + /// `struct_member_decoration_decl+` provided as |decos|. + /// @param decos the list of decorations for the struct member. /// @returns the struct member or nullptr - std::unique_ptr struct_member(); - /// Parses a `struct_member_decoration_decl` grammar element, appending newly - /// parsed decorations to the end of |decos|. - /// @param decos the decoration list - /// @returns true if parsing was successful. - bool struct_member_decoration_decl(ast::StructMemberDecorationList& decos); - /// Parses a `struct_member_decoration` grammar element - /// @returns the decoration or nullptr if none found - std::unique_ptr struct_member_decoration(); - /// Parses a `function_decl` grammar element + std::unique_ptr struct_member(ast::DecorationList& decos); + /// Parses a `function_decl` grammar element with the initial + /// `function_decoration_decl*` provided as |decos|. + /// @param decos the list of decorations for the function declaration. /// @returns the parsed function, nullptr otherwise - std::unique_ptr function_decl(); - /// Parses a `function_decoration_decl` grammar element, appending newly - /// parsed decorations to the end of |decos|. - /// @param decos list to store the parsed decorations - /// @returns true on successful parse; false otherwise - bool function_decoration_decl(ast::FunctionDecorationList& decos); - /// Parses a `function_decoration` grammar element - /// @returns the parsed decoration, nullptr otherwise - std::unique_ptr function_decoration(); + std::unique_ptr function_decl(ast::DecorationList& decos); /// Parses a `texture_sampler_types` grammar element /// @returns the parsed Type or nullptr if none matched. ast::type::Type* texture_sampler_types(); @@ -434,6 +412,28 @@ class ParserImpl { /// Parses a `assignment_stmt` grammar element /// @returns the parsed assignment or nullptr std::unique_ptr assignment_stmt(); + /// Parses one or more bracketed decoration lists. + /// @return the parsed decoration list, or an empty list on error. + ast::DecorationList decoration_list(); + /// Parses a list of decorations between `ATTR_LEFT` and `ATTR_RIGHT` + /// brackets. + /// @param decos the list to append newly parsed decorations to. + /// @return true if any decorations were be parsed, otherwise false. + bool decoration_bracketed_list(ast::DecorationList& decos); + /// Parses a single decoration of the following types: + /// * `struct_decoration` + /// * `struct_member_decoration` + /// * `array_decoration` + /// * `variable_decoration` + /// * `global_const_decoration` + /// * `function_decoration` + /// @return the parsed decoration, or nullptr. + std::unique_ptr decoration(); + /// Parses a single decoration, reporting an error if the next token does not + /// represent a decoration. + /// @see #decoration for the full list of decorations this method parses. + /// @return the parsed decoration, or nullptr on error. + std::unique_ptr expect_decoration(); private: /// ResultType resolves to the return type for the function or lambda F. @@ -520,11 +520,17 @@ class ParserImpl { /// a zero-initialized |T|. template > T expect_brace_block(const std::string& use, F&& body); + /// Downcasts all the decorations in |list| to the type |T|, raising a parser + /// error if any of the decorations aren't of the type |T|. + template + std::vector> cast_decorations(ast::DecorationList& in); + /// Reports an error if the decoration list |list| is not empty. + /// Used to ensure that all decorations are consumed. + bool expect_decorations_consumed(const ast::DecorationList& list); ast::type::Type* type_decl_pointer(Token t); ast::type::Type* type_decl_vector(Token t); ast::type::Type* type_decl_array(ast::ArrayDecorationList decos); - bool array_decoration_list(ast::ArrayDecorationList& decos); ast::type::Type* type_decl_matrix(Token t); std::unique_ptr const_expr_internal( diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc index 899a6afc86..224f658c4b 100644 --- a/src/reader/wgsl/parser_impl_error_msg_test.cc +++ b/src/reader/wgsl/parser_impl_error_msg_test.cc @@ -253,14 +253,14 @@ TEST_F(ParserImplErrorTest, ForLoopMissingRBrace) { TEST_F(ParserImplErrorTest, FunctionDeclInvalid) { EXPECT("[[stage(vertex)]] x;", - "test.wgsl:1:19 error: error parsing function declaration\n" + "test.wgsl:1:19 error: expected declaration after decorations\n" "[[stage(vertex)]] x;\n" " ^\n"); } TEST_F(ParserImplErrorTest, FunctionDeclDecoMissingEnd) { EXPECT("[[stage(vertex) fn f() -> void {}", - "test.wgsl:1:17 error: missing ]] for function decorations\n" + "test.wgsl:1:17 error: expected ']]' for decoration list\n" "[[stage(vertex) fn f() -> void {}\n" " ^^\n"); } @@ -287,11 +287,10 @@ TEST_F(ParserImplErrorTest, FunctionDeclDecoStageInvalid) { } TEST_F(ParserImplErrorTest, FunctionDeclDecoStageTypeInvalid) { - // TODO(bclayton) - BUG(https://crbug.com/tint/291) EXPECT("[[shader(vertex)]] fn main() -> void {}", - "test.wgsl:1:1 error: invalid token\n" + "test.wgsl:1:3 error: expected decoration\n" "[[shader(vertex)]] fn main() -> void {}\n" - "^^\n"); + " ^^^^^^\n"); } TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeMissingLParen) { @@ -619,14 +618,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingInvalidSubtype) { TEST_F(ParserImplErrorTest, GlobalDeclStructDecoMissingStruct) { EXPECT("[[block]];", - "test.wgsl:1:10 error: missing struct declaration\n" + "test.wgsl:1:10 error: expected declaration after decorations\n" "[[block]];\n" " ^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclStructDecoMissingEnd) { EXPECT("[[block struct {};", - "test.wgsl:1:9 error: missing ]] for struct decoration\n" + "test.wgsl:1:9 error: expected ']]' for decoration list\n" "[[block struct {};\n" " ^^^^^^\n"); } @@ -661,14 +660,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingRBrace) { TEST_F(ParserImplErrorTest, GlobalDeclStructMemberDecoEmpty) { EXPECT("struct S { [[]] i : i32; };", - "test.wgsl:1:14 error: empty struct member decoration found\n" + "test.wgsl:1:14 error: empty decoration list\n" "struct S { [[]] i : i32; };\n" " ^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclStructMemberDecoMissingEnd) { EXPECT("struct S { [[ i : i32; };", - "test.wgsl:1:15 error: missing ]] for struct member decoration\n" + "test.wgsl:1:15 error: expected decoration\n" "struct S { [[ i : i32; };\n" " ^\n"); } @@ -753,9 +752,9 @@ TEST_F(ParserImplErrorTest, GlobalDeclTypeInvalid) { TEST_F(ParserImplErrorTest, GlobalDeclTypeDecoInvalid) { EXPECT("var x : [[]] i32;", - "test.wgsl:1:9 error: invalid type for identifier declaration\n" + "test.wgsl:1:11 error: empty decoration list\n" "var x : [[]] i32;\n" - " ^^\n"); + " ^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingLessThan) { @@ -774,14 +773,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) { TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoNotArray) { EXPECT("var i : [[stride(1)]] i32;", - "test.wgsl:1:23 error: found array decoration but no array\n" + "test.wgsl:1:11 error: unexpected decorations\n" "var i : [[stride(1)]] i32;\n" - " ^^^\n"); + " ^^^^^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoMissingEnd) { EXPECT("var i : [[stride(1) array;", - "test.wgsl:1:21 error: expected ']]' for array decoration\n" + "test.wgsl:1:21 error: expected ']]' for decoration list\n" "var i : [[stride(1) array;\n" " ^^^^^\n"); } @@ -839,28 +838,28 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarArrayNegativeSize) { TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListEmpty) { EXPECT("[[]] var i : i32;", - "test.wgsl:1:3 error: empty variable decoration list\n" + "test.wgsl:1:3 error: empty decoration list\n" "[[]] var i : i32;\n" " ^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListInvalid) { EXPECT("[[location(1), meow]] var i : i32;", - "test.wgsl:1:16 error: missing variable decoration after comma\n" + "test.wgsl:1:16 error: expected decoration\n" "[[location(1), meow]] var i : i32;\n" " ^^^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListMissingComma) { EXPECT("[[location(1) set(2)]] var i : i32;", - "test.wgsl:1:15 error: missing comma in variable decoration list\n" + "test.wgsl:1:15 error: expected ',' for decoration list\n" "[[location(1) set(2)]] var i : i32;\n" " ^^^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListMissingEnd) { EXPECT("[[location(1) meow]] var i : i32;", - "test.wgsl:1:15 error: missing ]] for variable decoration\n" + "test.wgsl:1:15 error: expected ']]' for decoration list\n" "[[location(1) meow]] var i : i32;\n" " ^^^^\n"); } diff --git a/src/reader/wgsl/parser_impl_function_decl_test.cc b/src/reader/wgsl/parser_impl_function_decl_test.cc index 549273aa0f..2de8075c85 100644 --- a/src/reader/wgsl/parser_impl_function_decl_test.cc +++ b/src/reader/wgsl/parser_impl_function_decl_test.cc @@ -26,7 +26,9 @@ namespace { TEST_F(ParserImplTest, FunctionDecl) { auto* p = parser("fn main(a : i32, b : f32) -> void { return; }"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(f, nullptr); @@ -48,7 +50,9 @@ TEST_F(ParserImplTest, FunctionDecl) { TEST_F(ParserImplTest, FunctionDecl_DecorationList) { auto* p = parser("[[workgroup_size(2, 3, 4)]] fn main() -> void { return; }"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(f, nullptr); @@ -80,7 +84,9 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList_MultipleEntries) { auto* p = parser(R"( [[workgroup_size(2, 3, 4), workgroup_size(5, 6, 7)]] fn main() -> void { return; })"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(f, nullptr); @@ -119,7 +125,9 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList_MultipleLists) { [[workgroup_size(2, 3, 4)]] [[workgroup_size(5, 6, 7)]] fn main() -> void { return; })"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(f, nullptr); @@ -155,7 +163,9 @@ fn main() -> void { return; })"); TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { auto* p = parser("fn main() -> { }"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(f, nullptr); EXPECT_EQ(p->error(), "1:14: unable to determine function return type"); @@ -163,7 +173,9 @@ TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { TEST_F(ParserImplTest, FunctionDecl_InvalidBody) { auto* p = parser("fn main() -> void { return }"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(f, nullptr); EXPECT_EQ(p->error(), "1:28: expected ';' for return statement"); @@ -171,7 +183,9 @@ TEST_F(ParserImplTest, FunctionDecl_InvalidBody) { TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) { auto* p = parser("fn main() -> void return; }"); - auto f = p->function_decl(); + auto decorations = p->decoration_list(); + ASSERT_FALSE(p->has_error()) << p->error(); + auto f = p->function_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(f, nullptr); EXPECT_EQ(p->error(), "1:19: expected '{'"); diff --git a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc index 77c1fbc108..3010a46f82 100644 --- a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc +++ b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc @@ -24,20 +24,24 @@ namespace { TEST_F(ParserImplTest, FunctionDecorationList_Parses) { auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)]]"); - ast::FunctionDecorationList decos; - ASSERT_TRUE(p->function_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_EQ(decos.size(), 2u); + auto deco_0 = ast::As(std::move(decos[0])); + auto deco_1 = ast::As(std::move(decos[1])); + ASSERT_NE(deco_0, nullptr); + ASSERT_NE(deco_1, nullptr); + uint32_t x = 0; uint32_t y = 0; uint32_t z = 0; - ASSERT_TRUE(decos[0]->IsWorkgroup()); - std::tie(x, y, z) = decos[0]->AsWorkgroup()->values(); + ASSERT_TRUE(deco_0->IsWorkgroup()); + std::tie(x, y, z) = deco_0->AsWorkgroup()->values(); EXPECT_EQ(x, 2u); - ASSERT_TRUE(decos[1]->IsWorkgroup()); - std::tie(x, y, z) = decos[1]->AsWorkgroup()->values(); + ASSERT_TRUE(deco_1->IsWorkgroup()); + std::tie(x, y, z) = deco_1->AsWorkgroup()->values(); EXPECT_EQ(x, 3u); EXPECT_EQ(y, 4u); EXPECT_EQ(z, 5u); @@ -45,41 +49,36 @@ TEST_F(ParserImplTest, FunctionDecorationList_Parses) { TEST_F(ParserImplTest, FunctionDecorationList_Empty) { auto* p = parser("[[]]"); - ast::FunctionDecorationList decos; - ASSERT_FALSE(p->function_decoration_decl(decos)); + ast::DecorationList decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), - "1:3: missing decorations for function decoration block"); + ASSERT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, FunctionDecorationList_Invalid) { auto* p = parser("[[invalid]]"); - ast::FunctionDecorationList decos; - ASSERT_TRUE(p->function_decoration_decl(decos)); - ASSERT_FALSE(p->has_error()); + ast::DecorationList decos = p->decoration_list(); + ASSERT_TRUE(p->has_error()); ASSERT_TRUE(decos.empty()); + ASSERT_EQ(p->error(), "1:3: expected decoration"); } TEST_F(ParserImplTest, FunctionDecorationList_ExtraComma) { auto* p = parser("[[workgroup_size(2), ]]"); - ast::FunctionDecorationList decos; - ASSERT_FALSE(p->function_decoration_decl(decos)); + ast::DecorationList decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:22: expected decoration but none found"); + ASSERT_EQ(p->error(), "1:22: expected decoration"); } TEST_F(ParserImplTest, FunctionDecorationList_MissingComma) { auto* p = parser("[[workgroup_size(2) workgroup_size(2)]]"); - ast::FunctionDecorationList decos; - ASSERT_FALSE(p->function_decoration_decl(decos)); + ast::DecorationList decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:21: missing ]] for function decorations"); + ASSERT_EQ(p->error(), "1:21: expected ',' for decoration list"); } TEST_F(ParserImplTest, FunctionDecorationList_BadDecoration) { auto* p = parser("[[workgroup_size()]]"); - ast::FunctionDecorationList decos; - ASSERT_FALSE(p->function_decoration_decl(decos)); + ast::DecorationList decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); ASSERT_EQ( p->error(), @@ -88,10 +87,9 @@ TEST_F(ParserImplTest, FunctionDecorationList_BadDecoration) { TEST_F(ParserImplTest, FunctionDecorationList_MissingRightAttr) { auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)"); - ast::FunctionDecorationList decos; - ASSERT_FALSE(p->function_decoration_decl(decos)); + ast::DecorationList decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:45: missing ]] for function decorations"); + ASSERT_EQ(p->error(), "1:45: expected ']]' for decoration list"); } } // namespace diff --git a/src/reader/wgsl/parser_impl_function_decoration_test.cc b/src/reader/wgsl/parser_impl_function_decoration_test.cc index 0ab58b2ec7..90c9344cde 100644 --- a/src/reader/wgsl/parser_impl_function_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_function_decoration_test.cc @@ -25,15 +25,17 @@ namespace { TEST_F(ParserImplTest, FunctionDecoration_Workgroup) { auto* p = parser("workgroup_size(4)"); - auto deco = p->function_decoration(); - ASSERT_NE(deco, nullptr); + auto deco = p->decoration(); + ASSERT_NE(deco, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsWorkgroup()); + auto func_deco = ast::As(std::move(deco)); + ASSERT_NE(func_deco, nullptr); + ASSERT_TRUE(func_deco->IsWorkgroup()); uint32_t x = 0; uint32_t y = 0; uint32_t z = 0; - std::tie(x, y, z) = deco->AsWorkgroup()->values(); + std::tie(x, y, z) = func_deco->AsWorkgroup()->values(); EXPECT_EQ(x, 4u); EXPECT_EQ(y, 1u); EXPECT_EQ(z, 1u); @@ -41,15 +43,17 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) { auto* p = parser("workgroup_size(4, 5)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_NE(deco, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsWorkgroup()); + auto func_deco = ast::As(std::move(deco)); + ASSERT_NE(func_deco, nullptr) << p->error(); + ASSERT_TRUE(func_deco->IsWorkgroup()); uint32_t x = 0; uint32_t y = 0; uint32_t z = 0; - std::tie(x, y, z) = deco->AsWorkgroup()->values(); + std::tie(x, y, z) = func_deco->AsWorkgroup()->values(); EXPECT_EQ(x, 4u); EXPECT_EQ(y, 5u); EXPECT_EQ(z, 1u); @@ -57,15 +61,17 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) { auto* p = parser("workgroup_size(4, 5, 6)"); - auto deco = p->function_decoration(); - ASSERT_NE(deco, nullptr); + auto deco = p->decoration(); + ASSERT_NE(deco, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsWorkgroup()); + auto func_deco = ast::As(std::move(deco)); + ASSERT_NE(func_deco, nullptr); + ASSERT_TRUE(func_deco->IsWorkgroup()); uint32_t x = 0; uint32_t y = 0; uint32_t z = 0; - std::tie(x, y, z) = deco->AsWorkgroup()->values(); + std::tie(x, y, z) = func_deco->AsWorkgroup()->values(); EXPECT_EQ(x, 4u); EXPECT_EQ(y, 5u); EXPECT_EQ(z, 6u); @@ -73,7 +79,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_TooManyValues) { auto* p = parser("workgroup_size(1, 2, 3, 4)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); @@ -81,7 +87,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_TooManyValues) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) { auto* p = parser("workgroup_size(-2, 5, 6)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -90,7 +96,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) { auto* p = parser("workgroup_size(4, 0, 6)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -99,7 +105,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) { auto* p = parser("workgroup_size(4, 5, -3)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -108,7 +114,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingLeftParam) { auto* p = parser("workgroup_size 4, 5, 6)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size decoration"); @@ -116,7 +122,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingLeftParam) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingRightParam) { auto* p = parser("workgroup_size(4, 5, 6"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); @@ -124,7 +130,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingRightParam) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) { auto* p = parser("workgroup_size()"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -134,7 +140,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) { auto* p = parser("workgroup_size(, 2, 3)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -144,7 +150,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Comma) { auto* p = parser("workgroup_size(1 2, 3)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size decoration"); @@ -152,7 +158,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Comma) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) { auto* p = parser("workgroup_size(1, , 3)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -162,7 +168,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Comma) { auto* p = parser("workgroup_size(1, 2 3)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size decoration"); @@ -170,7 +176,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Comma) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) { auto* p = parser("workgroup_size(1, 2, )"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -180,7 +186,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) { auto* p = parser("workgroup_size(nan)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -190,7 +196,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) { auto* p = parser("workgroup_size(2, nan)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -200,7 +206,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) { auto* p = parser("workgroup_size(2, 3, nan)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ( @@ -210,16 +216,18 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Stage) { auto* p = parser("stage(compute)"); - auto deco = p->function_decoration(); - ASSERT_NE(deco, nullptr); + auto deco = p->decoration(); + ASSERT_NE(deco, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsStage()); - EXPECT_EQ(deco->AsStage()->value(), ast::PipelineStage::kCompute); + auto func_deco = ast::As(std::move(deco)); + ASSERT_NE(func_deco, nullptr); + ASSERT_TRUE(func_deco->IsStage()); + EXPECT_EQ(func_deco->AsStage()->value(), ast::PipelineStage::kCompute); } TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) { auto* p = parser("stage()"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); @@ -227,7 +235,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) { auto* p = parser("stage(nan)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); @@ -235,7 +243,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) { auto* p = parser("stage compute)"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: expected '(' for stage decoration"); @@ -243,7 +251,7 @@ TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingRightParen) { auto* p = parser("stage(compute"); - auto deco = p->function_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:14: expected ')' for stage decoration"); diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc index 34a7dbbe16..e76b0b6873 100644 --- a/src/reader/wgsl/parser_impl_global_decl_test.cc +++ b/src/reader/wgsl/parser_impl_global_decl_test.cc @@ -218,7 +218,7 @@ TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) { auto* p = parser("[[block]] A {};"); p->global_decl(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:11: missing struct declaration"); + EXPECT_EQ(p->error(), "1:11: expected declaration after decorations"); } TEST_F(ParserImplTest, GlobalDecl_StructMissing_Semi) { 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 4339900d75..49494c1256 100644 --- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc +++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc @@ -25,7 +25,8 @@ namespace { TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) { auto* p = parser("var a : f32"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(e, nullptr); @@ -44,7 +45,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) { TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) { auto* p = parser("var a : f32 = 1."); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(e, nullptr); @@ -66,7 +68,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) { TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) { auto* p = parser("[[binding(2), set(1)]] var a : f32"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(e, nullptr); ASSERT_TRUE(e->IsDecorated()); @@ -94,7 +97,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) { auto* p = parser("[[binding(2)]] [[set(1)]] var a : f32"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(e, nullptr); ASSERT_TRUE(e->IsDecorated()); @@ -122,7 +126,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) { auto* p = parser("[[binding()]] var a : f32"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), @@ -131,7 +136,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) { auto* p = parser("var a : f32 = if (a) {}"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:20: unable to parse const literal"); @@ -139,7 +145,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) { auto* p = parser("var a : f32;"); - auto e = p->global_variable_decl(); + auto decorations = p->decoration_list(); + auto e = p->global_variable_decl(decorations); ASSERT_TRUE(p->has_error()); ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration"); diff --git a/src/reader/wgsl/parser_impl_struct_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decl_test.cc index ebf1c4ac70..78aafaad5f 100644 --- a/src/reader/wgsl/parser_impl_struct_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decl_test.cc @@ -28,7 +28,9 @@ struct S { a : i32; [[offset(4)]] b : f32; })"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 0u); + auto s = p->struct_decl(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(s, nullptr); ASSERT_EQ(s->name(), "S"); @@ -43,7 +45,9 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) { a : f32; b : f32; })"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 1u); + auto s = p->struct_decl(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(s, nullptr); ASSERT_EQ(s->name(), "B"); @@ -61,7 +65,9 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) { a : f32; b : f32; })"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 2u); + auto s = p->struct_decl(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(s, nullptr); ASSERT_EQ(s->name(), "S"); @@ -75,7 +81,9 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) { TEST_F(ParserImplTest, StructDecl_EmptyMembers) { auto* p = parser("struct S {}"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 0u); + auto s = p->struct_decl(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(s, nullptr); ASSERT_EQ(s->impl()->members().size(), 0u); @@ -83,7 +91,9 @@ TEST_F(ParserImplTest, StructDecl_EmptyMembers) { TEST_F(ParserImplTest, StructDecl_MissingIdent) { auto* p = parser("struct {}"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 0u); + auto s = p->struct_decl(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(s, nullptr); EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration"); @@ -91,7 +101,9 @@ TEST_F(ParserImplTest, StructDecl_MissingIdent) { TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) { auto* p = parser("struct S }"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 0u); + auto s = p->struct_decl(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(s, nullptr); EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration"); @@ -99,7 +111,9 @@ TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) { TEST_F(ParserImplTest, StructDecl_InvalidStructBody) { auto* p = parser("struct S { a : B; }"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 0u); + auto s = p->struct_decl(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(s, nullptr); EXPECT_EQ(p->error(), "1:16: unknown constructed type 'B'"); @@ -107,18 +121,20 @@ TEST_F(ParserImplTest, StructDecl_InvalidStructBody) { TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) { auto* p = parser("[[block struct S { a : i32; }"); - auto s = p->struct_decl(); + auto decos = p->decoration_list(); + auto s = p->struct_decl(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(s, nullptr); - EXPECT_EQ(p->error(), "1:9: missing ]] for struct decoration"); + EXPECT_EQ(p->error(), "1:9: expected ']]' for decoration list"); } TEST_F(ParserImplTest, StructDecl_MissingStruct) { auto* p = parser("[[block]] S {}"); - auto s = p->struct_decl(); - ASSERT_TRUE(p->has_error()); + auto decos = p->decoration_list(); + ASSERT_EQ(decos.size(), 1u); + auto s = p->struct_decl(decos); + ASSERT_FALSE(p->has_error()); ASSERT_EQ(s, nullptr); - EXPECT_EQ(p->error(), "1:11: missing struct declaration"); } } // namespace diff --git a/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc index 3ff9674269..0549a2908c 100644 --- a/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc @@ -23,27 +23,25 @@ namespace { TEST_F(ParserImplTest, StructDecorationDecl_Parses) { auto* p = parser("[[block]]"); - ast::StructDecorationList decos; - ASSERT_TRUE(p->struct_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()); - EXPECT_EQ(decos.size(), 1u); - EXPECT_TRUE(decos[0]->IsBlock()); + ASSERT_EQ(decos.size(), 1u); + auto struct_deco = ast::As(std::move(decos[0])); + EXPECT_TRUE(struct_deco->IsBlock()); } TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) { auto* p = parser("[[block"); - ast::StructDecorationList decos; - ASSERT_FALSE(p->struct_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:8: missing ]] for struct decoration"); + EXPECT_EQ(p->error(), "1:8: expected ']]' for decoration list"); } -// Note, this isn't an error because it could be an array decoration TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) { auto* p = parser("[[invalid]]"); - ast::StructDecorationList decos; - ASSERT_TRUE(p->struct_decoration_decl(decos)); - ASSERT_FALSE(p->has_error()); + auto decos = p->decoration_list(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(decos.size(), 0u); EXPECT_TRUE(decos.empty()); } diff --git a/src/reader/wgsl/parser_impl_struct_decoration_test.cc b/src/reader/wgsl/parser_impl_struct_decoration_test.cc index a8da5b252b..84c6e22a1d 100644 --- a/src/reader/wgsl/parser_impl_struct_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decoration_test.cc @@ -38,9 +38,12 @@ TEST_P(StructDecorationTest, Parses) { auto params = GetParam(); auto* p = parser(params.input); - auto deco = p->struct_decoration(p->peek()); + auto deco = p->decoration(); ASSERT_FALSE(p->has_error()); - EXPECT_EQ(deco->IsBlock(), params.is_block); + ASSERT_NE(deco, nullptr); + auto struct_deco = ast::As(std::move(deco)); + ASSERT_NE(struct_deco, nullptr); + EXPECT_EQ(struct_deco->IsBlock(), params.is_block); } INSTANTIATE_TEST_SUITE_P(ParserImplTest, StructDecorationTest, @@ -48,12 +51,8 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest, TEST_F(ParserImplTest, StructDecoration_NoMatch) { auto* p = parser("not-a-stage"); - auto deco = p->struct_decoration(p->peek()); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); - - auto t = p->next(); - EXPECT_TRUE(t.IsIdentifier()); - EXPECT_EQ(t.to_str(), "not"); } } // namespace diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc index f15b14a9e8..36cc93d237 100644 --- a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc @@ -24,33 +24,32 @@ namespace { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) { auto* p = parser(""); - ast::StructMemberDecorationList decos; - ASSERT_TRUE(p->struct_member_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()); EXPECT_EQ(decos.size(), 0u); } TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) { auto* p = parser("[[]]"); - ast::StructMemberDecorationList decos; - ASSERT_FALSE(p->struct_member_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:3: empty struct member decoration found"); + EXPECT_EQ(decos.size(), 0u); + EXPECT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) { auto* p = parser("[[offset(4)]]"); - ast::StructMemberDecorationList decos; - ASSERT_TRUE(p->struct_member_decoration_decl(decos)); + auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.size(), 1u); - EXPECT_TRUE(decos[0]->IsOffset()); + auto deco = ast::As(std::move(decos[0])); + ASSERT_NE(deco, nullptr); + EXPECT_TRUE(deco->IsOffset()); } TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) { auto* p = parser("[[offset(nan)]]"); - ast::StructMemberDecorationList decos; - ASSERT_FALSE(p->struct_member_decoration_decl(decos)); + p->decoration_list(); ASSERT_TRUE(p->has_error()) << p->error(); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for offset decoration"); @@ -58,10 +57,9 @@ TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) { TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) { auto* p = parser("[[offset(4)"); - ast::StructMemberDecorationList decos; - ASSERT_FALSE(p->struct_member_decoration_decl(decos)); + p->decoration_list(); ASSERT_TRUE(p->has_error()) << p->error(); - EXPECT_EQ(p->error(), "1:12: missing ]] for struct member decoration"); + EXPECT_EQ(p->error(), "1:12: expected ']]' for decoration list"); } } // namespace diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc index da419e2358..ec257333a8 100644 --- a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc @@ -24,18 +24,21 @@ namespace { TEST_F(ParserImplTest, StructMemberDecoration_Offset) { auto* p = parser("offset(4)"); - auto deco = p->struct_member_decoration(); + auto deco = p->decoration(); ASSERT_NE(deco, nullptr); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsOffset()); - auto* o = deco->AsOffset(); + auto member_deco = ast::As(std::move(deco)); + ASSERT_NE(member_deco, nullptr); + ASSERT_TRUE(member_deco->IsOffset()); + + auto* o = member_deco->AsOffset(); EXPECT_EQ(o->offset(), 4u); } TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) { auto* p = parser("offset 4)"); - auto deco = p->struct_member_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected '(' for offset decoration"); @@ -43,7 +46,7 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) { auto* p = parser("offset(4"); - auto deco = p->struct_member_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected ')' for offset decoration"); @@ -51,7 +54,7 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { auto* p = parser("offset()"); - auto deco = p->struct_member_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -60,7 +63,7 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) { auto* p = parser("offset(nan)"); - auto deco = p->struct_member_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc index ad3ce9fd7b..188afb709f 100644 --- a/src/reader/wgsl/parser_impl_struct_member_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_test.cc @@ -28,7 +28,9 @@ TEST_F(ParserImplTest, StructMember_Parses) { auto* i32 = tm()->Get(std::make_unique()); auto* p = parser("a : i32;"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + EXPECT_EQ(decos.size(), 0u); + auto m = p->struct_member(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(m, nullptr); @@ -46,7 +48,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { auto* i32 = tm()->Get(std::make_unique()); auto* p = parser("[[offset(2)]] a : i32;"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + EXPECT_EQ(decos.size(), 1u); + auto m = p->struct_member(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(m, nullptr); @@ -67,7 +71,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { auto* p = parser(R"([[offset(2)]] [[offset(4)]] a : i32;)"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + EXPECT_EQ(decos.size(), 2u); + auto m = p->struct_member(decos); ASSERT_FALSE(p->has_error()); ASSERT_NE(m, nullptr); @@ -87,7 +93,8 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) { auto* p = parser("[[offset(nan)]] a : i32;"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + auto m = p->struct_member(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(m, nullptr); EXPECT_EQ(p->error(), @@ -96,7 +103,8 @@ TEST_F(ParserImplTest, StructMember_InvalidDecoration) { TEST_F(ParserImplTest, StructMember_InvalidVariable) { auto* p = parser("[[offset(4)]] a : B;"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + auto m = p->struct_member(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(m, nullptr); EXPECT_EQ(p->error(), "1:19: unknown constructed type 'B'"); @@ -104,7 +112,8 @@ TEST_F(ParserImplTest, StructMember_InvalidVariable) { TEST_F(ParserImplTest, StructMember_MissingSemicolon) { auto* p = parser("a : i32"); - auto m = p->struct_member(); + auto decos = p->decoration_list(); + auto m = p->struct_member(decos); ASSERT_TRUE(p->has_error()); ASSERT_EQ(m, nullptr); EXPECT_EQ(p->error(), "1:8: expected ';' for struct member"); diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc index a3c435b4b9..e9a6af83be 100644 --- a/src/reader/wgsl/parser_impl_type_decl_test.cc +++ b/src/reader/wgsl/parser_impl_type_decl_test.cc @@ -383,7 +383,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) { auto* t = p->type_decl(); ASSERT_EQ(t, nullptr); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:16: found array decoration but no array"); + EXPECT_EQ(p->error(), "1:3: unexpected decorations"); } TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) { @@ -391,16 +391,15 @@ TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) { auto* t = p->type_decl(); ASSERT_EQ(t, nullptr); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(p->error(), "1:14: expected ']]' for array decoration"); + EXPECT_EQ(p->error(), "1:14: expected ']]' for decoration list"); } -// Note, this isn't an error because it could be a struct decoration, we just -// don't have an array ... TEST_F(ParserImplTest, TypeDecl_Array_Decoration_UnknownDecoration) { auto* p = parser("[[unknown 16]] array"); auto* t = p->type_decl(); ASSERT_EQ(t, nullptr); - ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:3: expected decoration"); } TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) { 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 215e202613..dcbac856e9 100644 --- a/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc @@ -25,52 +25,52 @@ namespace { TEST_F(ParserImplTest, VariableDecorationList_Parses) { auto* p = parser(R"([[location(4), builtin(position)]])"); - ast::VariableDecorationList decos; - EXPECT_TRUE(p->variable_decoration_list(decos)); + auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_EQ(decos.size(), 2u); - ASSERT_TRUE(decos[0]->IsLocation()); - EXPECT_EQ(decos[0]->AsLocation()->value(), 4u); - ASSERT_TRUE(decos[1]->IsBuiltin()); - EXPECT_EQ(decos[1]->AsBuiltin()->value(), ast::Builtin::kPosition); + + auto deco_0 = ast::As(std::move(decos[0])); + auto deco_1 = ast::As(std::move(decos[1])); + ASSERT_NE(deco_0, nullptr); + ASSERT_NE(deco_1, nullptr); + + ASSERT_TRUE(deco_0->IsLocation()); + EXPECT_EQ(deco_0->AsLocation()->value(), 4u); + ASSERT_TRUE(deco_1->IsBuiltin()); + EXPECT_EQ(deco_1->AsBuiltin()->value(), ast::Builtin::kPosition); } TEST_F(ParserImplTest, VariableDecorationList_Empty) { auto* p = parser(R"([[]])"); - ast::VariableDecorationList decos; - EXPECT_FALSE(p->variable_decoration_list(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:3: empty variable decoration list"); + ASSERT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, VariableDecorationList_Invalid) { auto* p = parser(R"([[invalid]])"); - ast::VariableDecorationList decos; - EXPECT_TRUE(p->variable_decoration_list(decos)); - ASSERT_FALSE(p->has_error()); + auto decos = p->decoration_list(); + ASSERT_TRUE(p->has_error()); ASSERT_TRUE(decos.empty()); } TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) { auto* p = parser(R"([[builtin(position), ]])"); - ast::VariableDecorationList decos; - EXPECT_FALSE(p->variable_decoration_list(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:22: missing variable decoration after comma"); + ASSERT_EQ(p->error(), "1:22: expected decoration"); } TEST_F(ParserImplTest, VariableDecorationList_MissingComma) { auto* p = parser(R"([[binding(4) location(5)]])"); - ast::VariableDecorationList decos; - EXPECT_FALSE(p->variable_decoration_list(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:14: missing comma in variable decoration list"); + ASSERT_EQ(p->error(), "1:14: expected ',' for decoration list"); } TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) { auto* p = parser(R"([[location(bad)]])"); - ast::VariableDecorationList decos; - EXPECT_FALSE(p->variable_decoration_list(decos)); + auto decos = p->decoration_list(); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:12: expected signed integer literal for location decoration"); @@ -78,8 +78,7 @@ TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) { TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) { auto* p = parser("[[builtin(invalid)]]"); - ast::VariableDecorationList decos; - EXPECT_FALSE(p->variable_decoration_list(decos)); + auto decos = p->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 63af2bbeef..5ada60c661 100644 --- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc @@ -27,18 +27,20 @@ namespace { TEST_F(ParserImplTest, VariableDecoration_Location) { auto* p = parser("location(4)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_NE(deco, nullptr); + auto var_deco = ast::As(std::move(deco)); + ASSERT_NE(var_deco, nullptr); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsLocation()); + ASSERT_TRUE(var_deco->IsLocation()); - auto* loc = deco->AsLocation(); + auto* loc = var_deco->AsLocation(); EXPECT_EQ(loc->value(), 4u); } TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) { auto* p = parser("location 4)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected '(' for location decoration"); @@ -46,7 +48,7 @@ TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) { auto* p = parser("location(4"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: expected ')' for location decoration"); @@ -54,7 +56,7 @@ TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { auto* p = parser("location()"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -63,7 +65,7 @@ TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) { auto* p = parser("location(nan)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -85,12 +87,14 @@ TEST_P(BuiltinTest, VariableDecoration_Builtin) { auto params = GetParam(); auto* p = parser(std::string("builtin(") + params.input + ")"); - auto deco = p->variable_decoration(); - ASSERT_FALSE(p->has_error()) << p->error(); + auto deco = p->decoration(); ASSERT_NE(deco, nullptr); - ASSERT_TRUE(deco->IsBuiltin()); + auto var_deco = ast::As(std::move(deco)); + ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(var_deco, nullptr); + ASSERT_TRUE(var_deco->IsBuiltin()); - auto* builtin = deco->AsBuiltin(); + auto* builtin = var_deco->AsBuiltin(); EXPECT_EQ(builtin->value(), params.result); } INSTANTIATE_TEST_SUITE_P( @@ -110,7 +114,7 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) { auto* p = parser("builtin position)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected '(' for builtin decoration"); @@ -118,7 +122,7 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) { auto* p = parser("builtin(position"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:17: expected ')' for builtin decoration"); @@ -126,7 +130,7 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) { auto* p = parser("builtin()"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); @@ -134,7 +138,7 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) { auto* p = parser("builtin(other_thingy)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: invalid value for builtin decoration"); @@ -142,7 +146,7 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) { auto* p = parser("builtin(3)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); @@ -150,18 +154,20 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Binding) { auto* p = parser("binding(4)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_NE(deco, nullptr); + auto var_deco = ast::As(std::move(deco)); + ASSERT_NE(var_deco, nullptr); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(deco->IsBinding()); + ASSERT_TRUE(var_deco->IsBinding()); - auto* binding = deco->AsBinding(); + auto* binding = var_deco->AsBinding(); EXPECT_EQ(binding->value(), 4u); } TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) { auto* p = parser("binding 4)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected '(' for binding decoration"); @@ -169,7 +175,7 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) { auto* p = parser("binding(4"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected ')' for binding decoration"); @@ -177,7 +183,7 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { auto* p = parser("binding()"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -186,7 +192,7 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { auto* p = parser("binding(nan)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -195,18 +201,20 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_set) { auto* p = parser("set(4)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); + ASSERT_NE(deco, nullptr); + auto var_deco = ast::As(std::move(deco)); ASSERT_FALSE(p->has_error()); - ASSERT_NE(deco.get(), nullptr); - ASSERT_TRUE(deco->IsSet()); + ASSERT_NE(var_deco.get(), nullptr); + ASSERT_TRUE(var_deco->IsSet()); - auto* set = deco->AsSet(); + auto* set = var_deco->AsSet(); EXPECT_EQ(set->value(), 4u); } TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) { auto* p = parser("set 2)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:5: expected '(' for set decoration"); @@ -214,7 +222,7 @@ TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) { auto* p = parser("set(2"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:6: expected ')' for set decoration"); @@ -222,7 +230,7 @@ TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { auto* p = parser("set()"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), @@ -231,7 +239,7 @@ TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) { auto* p = parser("set(nan)"); - auto deco = p->variable_decoration(); + auto deco = p->decoration(); ASSERT_EQ(deco, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(),