From ab5dfee240ebdbed0c1a2621c641f370b3f850c7 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 9 Nov 2020 19:52:24 +0000 Subject: [PATCH] wsgl parser: Add ParserImpl::Maybe And use it for the non-ParserImpl::expect_xxx() methods. Another step towards supporting multiple error messages, as the caller can now test to see if the specific call errored, or didn't match, instead of using a global error state. Makes reading the control flow conditionals a bit easier too. Change-Id: Ie8627b8499ec9079167965da2a566401cd6bd903 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32102 Commit-Queue: Ben Clayton Reviewed-by: dan sinclair --- src/reader/wgsl/parser_impl.cc | 1465 ++++++++--------- src/reader/wgsl/parser_impl.h | 199 ++- .../parser_impl_additive_expression_test.cc | 40 +- .../wgsl/parser_impl_and_expression_test.cc | 30 +- .../wgsl/parser_impl_assignment_stmt_test.cc | 64 +- .../wgsl/parser_impl_break_stmt_test.cc | 7 +- src/reader/wgsl/parser_impl_call_stmt_test.cc | 28 +- src/reader/wgsl/parser_impl_case_body_test.cc | 30 +- .../wgsl/parser_impl_const_literal_test.cc | 60 +- .../wgsl/parser_impl_continue_stmt_test.cc | 7 +- .../wgsl/parser_impl_continuing_stmt_test.cc | 14 +- .../parser_impl_depth_texture_type_test.cc | 54 +- src/reader/wgsl/parser_impl_else_stmt_test.cc | 24 +- .../wgsl/parser_impl_elseif_stmt_test.cc | 44 +- .../parser_impl_equality_expression_test.cc | 40 +- src/reader/wgsl/parser_impl_error_msg_test.cc | 16 +- ...arser_impl_exclusive_or_expression_test.cc | 28 +- src/reader/wgsl/parser_impl_for_stmt_test.cc | 6 +- .../wgsl/parser_impl_function_decl_test.cc | 178 +- ...rser_impl_function_decoration_list_test.cc | 60 +- .../parser_impl_function_decoration_test.cc | 138 +- .../wgsl/parser_impl_function_header_test.cc | 64 +- .../parser_impl_function_type_decl_test.cc | 24 +- .../parser_impl_global_constant_decl_test.cc | 50 +- .../parser_impl_global_variable_decl_test.cc | 183 +- src/reader/wgsl/parser_impl_if_stmt_test.cc | 78 +- ...arser_impl_inclusive_or_expression_test.cc | 30 +- ...parser_impl_logical_and_expression_test.cc | 30 +- .../parser_impl_logical_or_expression_test.cc | 30 +- src/reader/wgsl/parser_impl_loop_stmt_test.cc | 72 +- ...ser_impl_multiplicative_expression_test.cc | 48 +- .../parser_impl_postfix_expression_test.cc | 108 +- .../parser_impl_primary_expression_test.cc | 134 +- .../parser_impl_relational_expression_test.cc | 56 +- .../parser_impl_sampled_texture_type_test.cc | 59 +- .../wgsl/parser_impl_sampler_type_test.cc | 26 +- .../wgsl/parser_impl_shift_expression_test.cc | 40 +- src/reader/wgsl/parser_impl_statement_test.cc | 147 +- .../parser_impl_storage_texture_type_test.cc | 124 +- .../wgsl/parser_impl_struct_decl_test.cc | 156 +- ...parser_impl_struct_decoration_decl_test.cc | 20 +- .../parser_impl_struct_decoration_test.cc | 10 +- ...impl_struct_member_decoration_decl_test.cc | 32 +- ...rser_impl_struct_member_decoration_test.cc | 31 +- .../wgsl/parser_impl_struct_member_test.cc | 36 +- .../wgsl/parser_impl_switch_body_test.cc | 94 +- .../wgsl/parser_impl_switch_stmt_test.cc | 70 +- .../parser_impl_texture_sampler_types_test.cc | 320 ++-- .../wgsl/parser_impl_type_alias_test.cc | 56 +- src/reader/wgsl/parser_impl_type_decl_test.cc | 394 +++-- .../wgsl/parser_impl_unary_expression_test.cc | 42 +- .../wgsl/parser_impl_variable_decl_test.cc | 60 +- ...rser_impl_variable_decoration_list_test.cc | 50 +- .../parser_impl_variable_decoration_test.cc | 126 +- .../wgsl/parser_impl_variable_stmt_test.cc | 98 +- ...r_impl_variable_storage_decoration_test.cc | 32 +- 56 files changed, 3224 insertions(+), 2238 deletions(-) diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index b04a509dde..a4e4e71652 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -77,6 +77,9 @@ namespace { template using Expect = ParserImpl::Expect; +template +using Maybe = ParserImpl::Maybe; + /// Controls the maximum number of times we'll call into the const_expr function /// from itself. This is to guard against stack overflow when there is an /// excessive number of type constructors inside the const_expr. @@ -217,66 +220,70 @@ Expect ParserImpl::expect_global_decl() { auto decos = decoration_list(); - auto gv = global_variable_decl(decos); + // FUDGE - Abort early if we enter with an error state to avoid accumulating + // multiple error messages. + // TODO(ben-clayton) - remove this once resynchronization is implemented. if (has_error()) return Failure::kErrored; - if (gv != nullptr) { + auto gv = global_variable_decl(decos.value); + if (gv.errored) + return Failure::kErrored; + if (gv.matched) { if (!expect("variable declaration", Token::Type::kSemicolon)) return Failure::kErrored; - module_.AddGlobalVariable(std::move(gv)); + module_.AddGlobalVariable(std::move(gv.value)); return true; } auto gc = global_constant_decl(); - if (has_error()) + if (gc.errored) { return Failure::kErrored; - - if (gc != nullptr) { + } + if (gc.matched) { if (!expect("constant declaration", Token::Type::kSemicolon)) return Failure::kErrored; - module_.AddGlobalVariable(std::move(gc)); + module_.AddGlobalVariable(std::move(gc.value)); return true; } - auto* ta = type_alias(); - if (has_error()) + auto ta = type_alias(); + if (ta.errored) return Failure::kErrored; - if (ta != nullptr) { + if (ta.matched) { if (!expect("type alias", Token::Type::kSemicolon)) return Failure::kErrored; - module_.AddConstructedType(ta); + module_.AddConstructedType(ta.value); return true; } - auto str = struct_decl(decos); - if (has_error()) + auto str = struct_decl(decos.value); + if (str.errored) return Failure::kErrored; - if (str != nullptr) { + if (str.matched) { if (!expect("struct declaration", Token::Type::kSemicolon)) return Failure::kErrored; - auto* type = ctx_.type_mgr().Get(std::move(str)); + auto* type = ctx_.type_mgr().Get(std::move(str.value)); register_constructed(type->AsStruct()->name(), type); module_.AddConstructedType(type); return true; } - auto func = function_decl(decos); - if (has_error()) + auto func = function_decl(decos.value); + if (func.errored) return Failure::kErrored; - - if (func != nullptr) { - module_.AddFunction(std::move(func)); + if (func.matched) { + module_.AddFunction(std::move(func.value)); return true; } - if (decos.size() > 0) { + if (decos.value.size() > 0) { add_error(peek(), "expected declaration after decorations"); } else { add_error(peek(), "invalid token"); @@ -287,15 +294,19 @@ Expect ParserImpl::expect_global_decl() { // global_variable_decl // : variable_decoration_list* variable_decl // | variable_decoration_list* variable_decl EQUAL const_expr -std::unique_ptr ParserImpl::global_variable_decl( +Maybe> ParserImpl::global_variable_decl( ast::DecorationList& decos) { - auto var = variable_decl(); - if (has_error() || var == nullptr) - return nullptr; + auto decl = variable_decl(); + if (decl.errored) + return Failure::kErrored; + if (!decl.matched) + return Failure::kNoMatch; + + auto var = std::move(decl.value); auto var_decos = cast_decorations(decos); if (var_decos.errored) - return nullptr; + return Failure::kErrored; if (var_decos.value.size() > 0) { auto dv = std::make_unique(std::move(var)); @@ -306,34 +317,34 @@ std::unique_ptr ParserImpl::global_variable_decl( if (match(Token::Type::kEqual)) { auto expr = expect_const_expr(); if (expr.errored) - return nullptr; + return Failure::kErrored; var->set_constructor(std::move(expr.value)); } - return var; + return std::move(var); } // global_constant_decl // : CONST variable_ident_decl EQUAL const_expr -std::unique_ptr ParserImpl::global_constant_decl() { +Maybe> ParserImpl::global_constant_decl() { if (!match(Token::Type::kConst)) - return nullptr; + return Failure::kNoMatch; const char* use = "constant declaration"; auto decl = expect_variable_ident_decl(use); if (decl.errored) - return nullptr; + return Failure::kErrored; auto var = std::make_unique( decl->source, decl->name, ast::StorageClass::kNone, decl->type); var->set_is_const(true); if (!expect(use, Token::Type::kEqual)) - return nullptr; + return Failure::kErrored; auto init = expect_const_expr(); if (init.errored) - return nullptr; + return Failure::kErrored; var->set_constructor(std::move(init.value)); @@ -342,20 +353,21 @@ std::unique_ptr ParserImpl::global_constant_decl() { // variable_decl // : VAR variable_storage_decoration? variable_ident_decl -std::unique_ptr ParserImpl::variable_decl() { +Maybe> ParserImpl::variable_decl() { if (!match(Token::Type::kVar)) - return nullptr; + return Failure::kNoMatch; auto sc = variable_storage_decoration(); - if (has_error()) - return nullptr; + if (sc.errored) + return Failure::kErrored; auto decl = expect_variable_ident_decl("variable declaration"); if (decl.errored) - return nullptr; + return Failure::kErrored; - return std::make_unique(decl->source, decl->name, sc, - decl->type); + return std::make_unique( + decl->source, decl->name, + sc.matched ? sc.value : ast::StorageClass::kNone, decl->type); } // texture_sampler_types @@ -364,88 +376,81 @@ std::unique_ptr ParserImpl::variable_decl() { // | sampled_texture_type LESS_THAN type_decl GREATER_THAN // | multisampled_texture_type LESS_THAN type_decl 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) { +Maybe ParserImpl::texture_sampler_types() { + auto type = sampler_type(); + if (type.matched) return type; - } type = depth_texture_type(); - if (type != nullptr) { - return type; - } + if (type.matched) + return type.value; auto dim = sampled_texture_type(); - if (dim != ast::type::TextureDimension::kNone) { + if (dim.matched) { const char* use = "sampled texture type"; if (!expect(use, Token::Type::kLessThan)) - return nullptr; + return Failure::kErrored; - auto* subtype = type_decl(); - if (has_error()) - return nullptr; - if (subtype == nullptr) { - add_error(peek().source(), "invalid subtype", use); - return nullptr; - } + auto subtype = type_decl(); + if (subtype.errored) + return Failure::kErrored; + if (!subtype.matched) + return add_error(peek().source(), "invalid subtype", use); if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; - return ctx_.type_mgr().Get( - std::make_unique(dim, subtype)); + return ctx_.type_mgr().Get(std::make_unique( + dim.value, subtype.value)); } - dim = multisampled_texture_type(); - if (dim != ast::type::TextureDimension::kNone) { + auto ms_dim = multisampled_texture_type(); + if (ms_dim.matched) { const char* use = "multisampled texture type"; if (!expect(use, Token::Type::kLessThan)) - return nullptr; + return Failure::kErrored; - auto* subtype = type_decl(); - if (has_error()) - return nullptr; - if (subtype == nullptr) { - add_error(peek().source(), "invalid subtype", use); - return nullptr; - } + auto subtype = type_decl(); + if (subtype.errored) + return Failure::kErrored; + if (!subtype.matched) + return add_error(peek().source(), "invalid subtype", use); if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; return ctx_.type_mgr().Get( - std::make_unique(dim, subtype)); + std::make_unique(ms_dim.value, + subtype.value)); } - ast::type::TextureDimension storage_dim; - ast::AccessControl access; - std::tie(storage_dim, access) = storage_texture_type(); - if (storage_dim != ast::type::TextureDimension::kNone) { + auto storage = storage_texture_type(); + if (storage.matched) { const char* use = "storage texture type"; if (!expect(use, Token::Type::kLessThan)) - return nullptr; + return Failure::kErrored; auto format = expect_image_storage_type(use); if (format.errored) - return nullptr; + return Failure::kErrored; if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; return ctx_.type_mgr().Get(std::make_unique( - storage_dim, access, format.value)); + storage->first, storage->second, format.value)); } - return nullptr; + return Failure::kNoMatch; } // sampler_type // : SAMPLER // | SAMPLER_COMPARISON -ast::type::Type* ParserImpl::sampler_type() { +Maybe ParserImpl::sampler_type() { if (match(Token::Type::kSampler)) return ctx_.type_mgr().Get(std::make_unique( ast::type::SamplerKind::kSampler)); @@ -454,7 +459,7 @@ ast::type::Type* ParserImpl::sampler_type() { return ctx_.type_mgr().Get(std::make_unique( ast::type::SamplerKind::kComparisonSampler)); - return nullptr; + return Failure::kNoMatch; } // sampled_texture_type @@ -465,7 +470,7 @@ ast::type::Type* ParserImpl::sampler_type() { // | TEXTURE_SAMPLED_3D // | TEXTURE_SAMPLED_CUBE // | TEXTURE_SAMPLED_CUBE_ARRAY -ast::type::TextureDimension ParserImpl::sampled_texture_type() { +Maybe ParserImpl::sampled_texture_type() { if (match(Token::Type::kTextureSampled1d)) return ast::type::TextureDimension::k1d; @@ -487,16 +492,16 @@ ast::type::TextureDimension ParserImpl::sampled_texture_type() { if (match(Token::Type::kTextureSampledCubeArray)) return ast::type::TextureDimension::kCubeArray; - return ast::type::TextureDimension::kNone; + return Failure::kNoMatch; } // multisampled_texture_type // : TEXTURE_MULTISAMPLED_2D -ast::type::TextureDimension ParserImpl::multisampled_texture_type() { +Maybe ParserImpl::multisampled_texture_type() { if (match(Token::Type::kTextureMultisampled2d)) return ast::type::TextureDimension::k2d; - return ast::type::TextureDimension::kNone; + return Failure::kNoMatch; } // storage_texture_type @@ -520,43 +525,57 @@ ast::type::TextureDimension ParserImpl::multisampled_texture_type() { // | TEXTURE_STORAGE_WO_2D // | TEXTURE_STORAGE_WO_2D_ARRAY // | TEXTURE_STORAGE_WO_3D -std::pair +Maybe> ParserImpl::storage_texture_type() { - if (match(Token::Type::kTextureStorageReadonly1d)) - return {ast::type::TextureDimension::k1d, ast::AccessControl::kReadOnly}; + using Ret = std::pair; + if (match(Token::Type::kTextureStorageReadonly1d)) { + return Ret{ast::type::TextureDimension::k1d, ast::AccessControl::kReadOnly}; + } - if (match(Token::Type::kTextureStorageReadonly1dArray)) - return {ast::type::TextureDimension::k1dArray, - ast::AccessControl::kReadOnly}; + if (match(Token::Type::kTextureStorageReadonly1dArray)) { + return Ret{ast::type::TextureDimension::k1dArray, + ast::AccessControl::kReadOnly}; + } - if (match(Token::Type::kTextureStorageReadonly2d)) - return {ast::type::TextureDimension::k2d, ast::AccessControl::kReadOnly}; + if (match(Token::Type::kTextureStorageReadonly2d)) { + return Ret{ast::type::TextureDimension::k2d, ast::AccessControl::kReadOnly}; + } - if (match(Token::Type::kTextureStorageReadonly2dArray)) - return {ast::type::TextureDimension::k2dArray, - ast::AccessControl::kReadOnly}; + if (match(Token::Type::kTextureStorageReadonly2dArray)) { + return Ret{ast::type::TextureDimension::k2dArray, + ast::AccessControl::kReadOnly}; + } - if (match(Token::Type::kTextureStorageReadonly3d)) - return {ast::type::TextureDimension::k3d, ast::AccessControl::kReadOnly}; + if (match(Token::Type::kTextureStorageReadonly3d)) { + return Ret{ast::type::TextureDimension::k3d, ast::AccessControl::kReadOnly}; + } - if (match(Token::Type::kTextureStorageWriteonly1d)) - return {ast::type::TextureDimension::k1d, ast::AccessControl::kWriteOnly}; + if (match(Token::Type::kTextureStorageWriteonly1d)) { + return Ret{ast::type::TextureDimension::k1d, + ast::AccessControl::kWriteOnly}; + } - if (match(Token::Type::kTextureStorageWriteonly1dArray)) - return {ast::type::TextureDimension::k1dArray, - ast::AccessControl::kWriteOnly}; + if (match(Token::Type::kTextureStorageWriteonly1dArray)) { + return Ret{ast::type::TextureDimension::k1dArray, + ast::AccessControl::kWriteOnly}; + } - if (match(Token::Type::kTextureStorageWriteonly2d)) - return {ast::type::TextureDimension::k2d, ast::AccessControl::kWriteOnly}; + if (match(Token::Type::kTextureStorageWriteonly2d)) { + return Ret{ast::type::TextureDimension::k2d, + ast::AccessControl::kWriteOnly}; + } - if (match(Token::Type::kTextureStorageWriteonly2dArray)) - return {ast::type::TextureDimension::k2dArray, - ast::AccessControl::kWriteOnly}; + if (match(Token::Type::kTextureStorageWriteonly2dArray)) { + return Ret{ast::type::TextureDimension::k2dArray, + ast::AccessControl::kWriteOnly}; + } - if (match(Token::Type::kTextureStorageWriteonly3d)) - return {ast::type::TextureDimension::k3d, ast::AccessControl::kWriteOnly}; + if (match(Token::Type::kTextureStorageWriteonly3d)) { + return Ret{ast::type::TextureDimension::k3d, + ast::AccessControl::kWriteOnly}; + } - return {ast::type::TextureDimension::kNone, ast::AccessControl::kReadOnly}; + return Failure::kNoMatch; } // depth_texture_type @@ -564,7 +583,7 @@ ParserImpl::storage_texture_type() { // | TEXTURE_DEPTH_2D_ARRAY // | TEXTURE_DEPTH_CUBE // | TEXTURE_DEPTH_CUBE_ARRAY -ast::type::Type* ParserImpl::depth_texture_type() { +Maybe ParserImpl::depth_texture_type() { if (match(Token::Type::kTextureDepth2d)) return ctx_.type_mgr().Get(std::make_unique( ast::type::TextureDimension::k2d)); @@ -581,7 +600,7 @@ ast::type::Type* ParserImpl::depth_texture_type() { return ctx_.type_mgr().Get(std::make_unique( ast::type::TextureDimension::kCubeArray)); - return nullptr; + return Failure::kNoMatch; } // image_storage_type @@ -742,42 +761,39 @@ Expect ParserImpl::expect_variable_ident_decl( return Failure::kErrored; auto t = peek(); - auto* type = type_decl(); - if (has_error()) + auto type = type_decl(); + if (type.errored) return Failure::kErrored; + if (!type.matched) + return add_error(t.source(), "invalid type", use); - if (type == nullptr) { - add_error(t.source(), "invalid type", use); - return Failure::kErrored; - } - - return TypedIdentifier{type, ident.value, ident.source}; + return TypedIdentifier{type.value, ident.value, ident.source}; } // variable_storage_decoration // : LESS_THAN storage_class GREATER_THAN -ast::StorageClass ParserImpl::variable_storage_decoration() { +Maybe ParserImpl::variable_storage_decoration() { if (!match(Token::Type::kLessThan)) - return ast::StorageClass::kNone; + return Failure::kNoMatch; const char* use = "variable decoration"; auto sc = expect_storage_class(use); if (sc.errored) - return ast::StorageClass::kNone; + return Failure::kErrored; if (!expect(use, Token::Type::kGreaterThan)) - return ast::StorageClass::kNone; + return Failure::kErrored; return sc.value; } // type_alias // : TYPE IDENT EQUAL type_decl -ast::type::Type* ParserImpl::type_alias() { +Maybe ParserImpl::type_alias() { auto t = peek(); if (!t.IsType()) - return nullptr; + return Failure::kNoMatch; next(); // Consume the peek @@ -785,21 +801,19 @@ ast::type::Type* ParserImpl::type_alias() { auto name = expect_ident(use); if (name.errored) - return nullptr; + return Failure::kErrored; if (!expect(use, Token::Type::kEqual)) - return nullptr; + return Failure::kErrored; - auto* type = type_decl(); - if (has_error()) - return nullptr; - if (type == nullptr) { - add_error(peek(), "invalid type alias"); - return nullptr; - } + auto type = type_decl(); + if (type.errored) + return Failure::kErrored; + if (!type.matched) + return add_error(peek(), "invalid type alias"); auto* alias = ctx_.type_mgr().Get( - std::make_unique(name.value, type)); + std::make_unique(name.value, type.value)); register_constructed(name.value, alias); return alias->AsAlias(); @@ -829,14 +843,13 @@ ast::type::Type* ParserImpl::type_alias() { // | MAT4x3 LESS_THAN type_decl GREATER_THAN // | MAT4x4 LESS_THAN type_decl GREATER_THAN // | texture_sampler_types -ast::type::Type* ParserImpl::type_decl() { +Maybe ParserImpl::type_decl() { auto t = peek(); if (match(Token::Type::kIdentifier)) { auto* ty = get_constructed(t.to_str()); - if (ty == nullptr) { - add_error(t, "unknown constructed type '" + t.to_str() + "'"); - return nullptr; - } + if (ty == nullptr) + return add_error(t, "unknown constructed type '" + t.to_str() + "'"); + return ty; } @@ -853,40 +866,42 @@ ast::type::Type* ParserImpl::type_decl() { return ctx_.type_mgr().Get(std::make_unique()); if (t.IsVec2() || t.IsVec3() || t.IsVec4()) { - return expect_type_decl_vector(t).value; + next(); // Consume the peek + return expect_type_decl_vector(t); } if (match(Token::Type::kPtr)) - return expect_type_decl_pointer().value; + return expect_type_decl_pointer(); auto decos = decoration_list(); - if (has_error()) - return nullptr; + if (decos.errored) + return Failure::kErrored; if (match(Token::Type::kArray)) { - auto array_decos = cast_decorations(decos); + auto array_decos = cast_decorations(decos.value); if (array_decos.errored) - return nullptr; - return expect_type_decl_array(std::move(array_decos.value)).value; + return Failure::kErrored; + + return expect_type_decl_array(std::move(array_decos.value)); } - expect_decorations_consumed(decos); + if (!expect_decorations_consumed(decos.value)) + return Failure::kErrored; if (t.IsMat2x2() || t.IsMat2x3() || t.IsMat2x4() || t.IsMat3x2() || t.IsMat3x3() || t.IsMat3x4() || t.IsMat4x2() || t.IsMat4x3() || t.IsMat4x4()) { - return expect_type_decl_matrix(t).value; + next(); // Consume the peek + return expect_type_decl_matrix(t); } - auto* texture_or_sampler = texture_sampler_types(); - if (has_error()) { - return nullptr; - } - if (texture_or_sampler != nullptr) { - return texture_or_sampler; - } + auto texture_or_sampler = texture_sampler_types(); + if (texture_or_sampler.errored) + return Failure::kErrored; + if (texture_or_sampler.matched) + return texture_or_sampler.value; - return nullptr; + return Failure::kNoMatch; } Expect ParserImpl::expect_type_decl_pointer() { @@ -902,22 +917,20 @@ Expect ParserImpl::expect_type_decl_pointer() { if (!expect(use, Token::Type::kComma)) return Failure::kErrored; - auto* subtype = type_decl(); - if (has_error()) + auto subtype = type_decl(); + if (subtype.errored) return Failure::kErrored; - if (subtype == nullptr) + if (!subtype.matched) return add_error(peek().source(), "missing type", use); if (!expect(use, Token::Type::kGreaterThan)) return Failure::kErrored; return ctx_.type_mgr().Get( - std::make_unique(subtype, sc.value)); + std::make_unique(subtype.value, sc.value)); } Expect ParserImpl::expect_type_decl_vector(Token t) { - next(); // Consume the peek - uint32_t count = 2; if (t.IsVec3()) count = 3; @@ -929,18 +942,17 @@ Expect ParserImpl::expect_type_decl_vector(Token t) { if (!expect(use, Token::Type::kLessThan)) return Failure::kErrored; - auto* subtype = type_decl(); - if (has_error()) + auto subtype = type_decl(); + if (subtype.errored) return Failure::kErrored; - if (subtype == nullptr) { + if (!subtype.matched) return add_error(peek().source(), "unable to determine subtype", use); - } if (!expect(use, Token::Type::kGreaterThan)) return Failure::kErrored; return ctx_.type_mgr().Get( - std::make_unique(subtype, count)); + std::make_unique(subtype.value, count)); } Expect ParserImpl::expect_type_decl_array( @@ -950,10 +962,10 @@ Expect ParserImpl::expect_type_decl_array( if (!expect(use, Token::Type::kLessThan)) return Failure::kErrored; - auto* subtype = type_decl(); - if (has_error()) + auto subtype = type_decl(); + if (subtype.errored) return Failure::kErrored; - if (subtype == nullptr) + if (!subtype.matched) return add_error(peek(), "invalid type for array declaration"); uint32_t size = 0; @@ -967,14 +979,12 @@ Expect ParserImpl::expect_type_decl_array( if (!expect(use, Token::Type::kGreaterThan)) return Failure::kErrored; - auto ty = std::make_unique(subtype, size); + auto ty = std::make_unique(subtype.value, size); ty->set_decorations(std::move(decos)); return ctx_.type_mgr().Get(std::move(ty)); } Expect ParserImpl::expect_type_decl_matrix(Token t) { - next(); // Consume the peek - uint32_t rows = 2; uint32_t columns = 2; if (t.IsMat3x2() || t.IsMat3x3() || t.IsMat3x4()) { @@ -988,22 +998,22 @@ Expect ParserImpl::expect_type_decl_matrix(Token t) { columns = 4; } - t = next(); - if (!t.IsLessThan()) - return add_error(t, "missing < for matrix"); + const char* use = "matrix"; - auto* subtype = type_decl(); - if (has_error()) + if (!expect(use, Token::Type::kLessThan)) return Failure::kErrored; - if (subtype == nullptr) - return add_error(peek(), "unable to determine subtype for matrix"); - t = next(); - if (!t.IsGreaterThan()) - return add_error(t, "missing > for matrix"); + auto subtype = type_decl(); + if (subtype.errored) + return Failure::kErrored; + if (!subtype.matched) + return add_error(peek().source(), "unable to determine subtype", use); + + if (!expect(use, Token::Type::kGreaterThan)) + return Failure::kErrored; return ctx_.type_mgr().Get( - std::make_unique(subtype, rows, columns)); + std::make_unique(subtype.value, rows, columns)); } // storage_class @@ -1050,25 +1060,25 @@ Expect ParserImpl::expect_storage_class( // struct_decl // : struct_decoration_decl* STRUCT IDENT struct_body_decl -std::unique_ptr ParserImpl::struct_decl( +Maybe> ParserImpl::struct_decl( ast::DecorationList& decos) { auto t = peek(); auto source = t.source(); if (!match(Token::Type::kStruct)) - return nullptr; + return Failure::kNoMatch; auto struct_decos = cast_decorations(decos); if (struct_decos.errored) - return nullptr; + return Failure::kErrored; auto name = expect_ident("struct declaration"); if (name.errored) - return nullptr; + return Failure::kErrored; auto body = expect_struct_body_decl(); if (body.errored) - return nullptr; + return Failure::kErrored; return std::make_unique( name.value, @@ -1085,10 +1095,10 @@ Expect ParserImpl::expect_struct_body_decl() { while (!peek().IsBraceRight() && !peek().IsEof()) { auto decos = decoration_list(); - if (has_error()) + if (decos.errored) return Failure::kErrored; - auto mem = expect_struct_member(decos); + auto mem = expect_struct_member(decos.value); if (mem.errored) return Failure::kErrored; @@ -1122,6 +1132,8 @@ Expect> ParserImpl::expect_struct_member( return Failure::kErrored; auto member_decos = cast_decorations(decos); + if (member_decos.errored) + return Failure::kErrored; if (!expect("struct member", Token::Type::kSemicolon)) return Failure::kErrored; @@ -1132,71 +1144,66 @@ Expect> ParserImpl::expect_struct_member( // function_decl // : function_header body_stmt -std::unique_ptr ParserImpl::function_decl( +Maybe> ParserImpl::function_decl( ast::DecorationList& decos) { auto f = function_header(); - if (f == nullptr || has_error()) - return nullptr; + if (f.errored) + return Failure::kErrored; + if (!f.matched) + return Failure::kNoMatch; auto func_decos = cast_decorations(decos); if (func_decos.errored) - return nullptr; - f->set_decorations(std::move(func_decos.value)); + return Failure::kErrored; + + f.value->set_decorations(std::move(func_decos.value)); auto body = expect_body_stmt(); if (body.errored) - return nullptr; + return Failure::kErrored; - f->set_body(std::move(body.value)); - return f; + f.value->set_body(std::move(body.value)); + return std::move(f.value); } // function_type_decl // : type_decl // | VOID -ast::type::Type* ParserImpl::function_type_decl() { - auto t = peek(); - if (t.IsVoid()) { - next(); // Consume the peek +Maybe ParserImpl::function_type_decl() { + if (match(Token::Type::kVoid)) return ctx_.type_mgr().Get(std::make_unique()); - } + return type_decl(); } // function_header // : FN IDENT PAREN_LEFT param_list PAREN_RIGHT ARROW function_type_decl -std::unique_ptr ParserImpl::function_header() { +Maybe> ParserImpl::function_header() { Source source; if (!match(Token::Type::kFn, &source)) - return nullptr; + return Failure::kNoMatch; const char* use = "function declaration"; auto name = expect_ident(use); if (name.errored) - return nullptr; + return Failure::kErrored; auto params = expect_paren_block(use, [&] { return expect_param_list(); }); - if (params.errored) - return nullptr; + return Failure::kErrored; - auto t = next(); - if (!t.IsArrow()) { - add_error(t, "missing -> for function declaration"); - return nullptr; - } + if (!expect(use, Token::Type::kArrow)) + return Failure::kErrored; - auto* type = function_type_decl(); - if (has_error()) - return nullptr; - if (type == nullptr) { - add_error(peek(), "unable to determine function return type"); - return nullptr; - } + auto type = function_type_decl(); + if (type.errored) + return Failure::kErrored; + if (!type.matched) + return add_error(peek(), "unable to determine function return type"); return std::make_unique(source, name.value, - std::move(params.value), type); + std::move(params.value), type.value); } // param_list @@ -1274,13 +1281,12 @@ Expect> ParserImpl::expect_paren_rhs_stmt() { return expect_paren_block( "", [&]() -> Expect> { auto expr = logical_or_expression(); - if (has_error()) + if (expr.errored) return Failure::kErrored; - - if (expr == nullptr) + if (!expr.matched) return add_error(peek(), "unable to parse expression"); - return expr; + return std::move(expr.value); }); } @@ -1291,12 +1297,12 @@ Expect> ParserImpl::expect_statements() { for (;;) { auto stmt = statement(); - if (has_error()) + if (stmt.errored) return Failure::kErrored; - if (!stmt) + if (!stmt.matched) break; - ret->append(std::move(stmt)); + ret->append(std::move(stmt.value)); } return ret; @@ -1316,84 +1322,84 @@ Expect> ParserImpl::expect_statements() { // | DISCARD SEMICOLON // | assignment_stmt SEMICOLON // | body_stmt? -std::unique_ptr ParserImpl::statement() { +Maybe> ParserImpl::statement() { while (match(Token::Type::kSemicolon)) { // Skip empty statements } auto t = peek(); auto ret_stmt = return_stmt(); - if (has_error()) - return nullptr; - if (ret_stmt != nullptr) { + if (ret_stmt.errored) + return Failure::kErrored; + if (ret_stmt.matched) { if (!expect("return statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return ret_stmt; + return std::move(ret_stmt.value); } auto stmt_if = if_stmt(); - if (has_error()) - return nullptr; - if (stmt_if != nullptr) - return stmt_if; + if (stmt_if.errored) + return Failure::kErrored; + if (stmt_if.matched) + return std::move(stmt_if.value); auto sw = switch_stmt(); - if (has_error()) - return nullptr; - if (sw != nullptr) - return sw; + if (sw.errored) + return Failure::kErrored; + if (sw.matched) + return std::move(sw.value); auto loop = loop_stmt(); - if (has_error()) - return nullptr; - if (loop != nullptr) - return loop; + if (loop.errored) + return Failure::kErrored; + if (loop.matched) + return std::move(loop.value); auto stmt_for = for_stmt(); - if (has_error()) - return nullptr; - if (stmt_for != nullptr) - return stmt_for; + if (stmt_for.errored) + return Failure::kErrored; + if (stmt_for.matched) + return std::move(stmt_for.value); auto func = func_call_stmt(); - if (has_error()) - return nullptr; - if (func != nullptr) { + if (func.errored) + return Failure::kErrored; + if (func.matched) { if (!expect("function call", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return func; + return std::move(func.value); } auto var = variable_stmt(); - if (has_error()) - return nullptr; - if (var != nullptr) { + if (var.errored) + return Failure::kErrored; + if (var.matched) { if (!expect("variable declaration", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return var; + return std::move(var.value); } auto b = break_stmt(); - if (has_error()) - return nullptr; - if (b != nullptr) { + if (b.errored) + return Failure::kErrored; + if (b.matched) { if (!expect("break statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return b; + return std::move(b.value); } auto cont = continue_stmt(); - if (has_error()) - return nullptr; - if (cont != nullptr) { + if (cont.errored) + return Failure::kErrored; + if (cont.matched) { if (!expect("continue statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return cont; + return std::move(cont.value); } if (t.IsDiscard()) { @@ -1401,160 +1407,151 @@ std::unique_ptr ParserImpl::statement() { next(); // Consume the peek if (!expect("discard statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; return std::make_unique(source); } auto assign = assignment_stmt(); - if (has_error()) - return nullptr; - if (assign != nullptr) { + if (assign.errored) + return Failure::kErrored; + if (assign.matched) { if (!expect("assignment statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return assign; + return std::move(assign.value); } t = peek(); if (t.IsBraceLeft()) { auto body = expect_body_stmt(); if (body.errored) - return nullptr; + return Failure::kErrored; return std::move(body.value); } - return nullptr; + return Failure::kNoMatch; } // return_stmt // : RETURN logical_or_expression? -std::unique_ptr ParserImpl::return_stmt() { +Maybe> ParserImpl::return_stmt() { Source source; if (!match(Token::Type::kReturn, &source)) - return nullptr; + return Failure::kNoMatch; - std::unique_ptr expr = nullptr; - if (!peek().IsSemicolon()) { - expr = logical_or_expression(); - if (has_error()) - return nullptr; - } - return std::make_unique(source, std::move(expr)); + if (peek().IsSemicolon()) + return std::make_unique(source, nullptr); + + auto expr = logical_or_expression(); + if (expr.errored) + return Failure::kErrored; + // TODO(bclayton): Check matched? + return std::make_unique(source, std::move(expr.value)); } // variable_stmt // : variable_decl // | variable_decl EQUAL logical_or_expression // | CONST variable_ident_decl EQUAL logical_or_expression -std::unique_ptr ParserImpl::variable_stmt() { - auto t = peek(); - if (t.IsConst()) { - next(); // Consume the peek - +Maybe> ParserImpl::variable_stmt() { + if (match(Token::Type::kConst)) { auto decl = expect_variable_ident_decl("constant declaration"); - if (has_error()) - return nullptr; + if (decl.errored) + return Failure::kErrored; if (!expect("constant declaration", Token::Type::kEqual)) - return nullptr; + return Failure::kErrored; auto constructor = logical_or_expression(); - if (has_error()) - return nullptr; - if (constructor == nullptr) { - add_error(peek(), "missing constructor for const declaration"); - return nullptr; - } + if (constructor.errored) + return Failure::kErrored; + if (!constructor.matched) + return add_error(peek(), "missing constructor for const declaration"); auto var = std::make_unique( decl->source, decl->name, ast::StorageClass::kNone, decl->type); var->set_is_const(true); - var->set_constructor(std::move(constructor)); + var->set_constructor(std::move(constructor.value)); return std::make_unique(decl->source, std::move(var)); } auto var = variable_decl(); - if (has_error()) - return nullptr; - if (var == nullptr) - return nullptr; + if (var.errored) + return Failure::kErrored; + if (!var.matched) + return Failure::kNoMatch; if (match(Token::Type::kEqual)) { auto constructor = logical_or_expression(); - if (has_error()) - return nullptr; - if (constructor == nullptr) { - add_error(peek(), "missing constructor for variable declaration"); - return nullptr; - } - var->set_constructor(std::move(constructor)); + if (constructor.errored) + return Failure::kErrored; + if (!constructor.matched) + return add_error(peek(), "missing constructor for variable declaration"); + + var.value->set_constructor(std::move(constructor.value)); } - return std::make_unique(var->source(), - std::move(var)); + return std::make_unique(var.value->source(), + std::move(var.value)); } // if_stmt // : IF paren_rhs_stmt body_stmt elseif_stmt? else_stmt? -std::unique_ptr ParserImpl::if_stmt() { +Maybe> ParserImpl::if_stmt() { Source source; if (!match(Token::Type::kIf, &source)) - return nullptr; + return Failure::kNoMatch; auto condition = expect_paren_rhs_stmt(); if (condition.errored) - return nullptr; + return Failure::kErrored; auto body = expect_body_stmt(); if (body.errored) - return nullptr; + return Failure::kErrored; auto elseif = elseif_stmt(); - if (has_error()) - return nullptr; + if (elseif.errored) + return Failure::kErrored; auto el = else_stmt(); - if (has_error()) - return nullptr; + if (el.errored) + return Failure::kErrored; auto stmt = std::make_unique( source, std::move(condition.value), std::move(body.value)); - if (el != nullptr) { - elseif.push_back(std::move(el)); + if (el.matched) { + elseif.value.push_back(std::move(el.value)); } - stmt->set_else_statements(std::move(elseif)); + stmt->set_else_statements(std::move(elseif.value)); return stmt; } // elseif_stmt // : ELSE_IF paren_rhs_stmt body_stmt elseif_stmt? -ast::ElseStatementList ParserImpl::elseif_stmt() { - auto t = peek(); - if (!t.IsElseIf()) - return {}; +Maybe ParserImpl::elseif_stmt() { + Source source; + if (!match(Token::Type::kElseIf, &source)) + return Failure::kNoMatch; ast::ElseStatementList ret; for (;;) { - auto source = t.source(); - next(); // Consume the peek - auto condition = expect_paren_rhs_stmt(); if (condition.errored) - return {}; + return Failure::kErrored; auto body = expect_body_stmt(); if (body.errored) - return {}; + return Failure::kErrored; ret.push_back(std::make_unique( source, std::move(condition.value), std::move(body.value))); - t = peek(); - if (!t.IsElseIf()) + if (!match(Token::Type::kElseIf, &source)) break; } @@ -1563,60 +1560,58 @@ ast::ElseStatementList ParserImpl::elseif_stmt() { // else_stmt // : ELSE body_stmt -std::unique_ptr ParserImpl::else_stmt() { - auto t = peek(); - if (!t.IsElse()) - return nullptr; - - auto source = t.source(); - next(); // Consume the peek +Maybe> ParserImpl::else_stmt() { + Source source; + if (!match(Token::Type::kElse, &source)) + return Failure::kNoMatch; auto body = expect_body_stmt(); if (body.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(source, std::move(body.value)); } // switch_stmt // : SWITCH paren_rhs_stmt BRACKET_LEFT switch_body+ BRACKET_RIGHT -std::unique_ptr ParserImpl::switch_stmt() { +Maybe> ParserImpl::switch_stmt() { Source source; if (!match(Token::Type::kSwitch, &source)) - return nullptr; + return Failure::kNoMatch; auto condition = expect_paren_rhs_stmt(); if (condition.errored) - return nullptr; + return Failure::kErrored; - ast::CaseStatementList body; - bool ok = expect_brace_block_old("switch statement", [&] { - for (;;) { - auto stmt = switch_body(); - if (has_error()) - return false; - if (stmt == nullptr) - break; + auto body = expect_brace_block("switch statement", + [&]() -> Expect { + ast::CaseStatementList list; + for (;;) { + auto stmt = switch_body(); + if (stmt.errored) + return Failure::kErrored; + if (!stmt.matched) + break; - body.push_back(std::move(stmt)); - } - return true; - }); + list.push_back(std::move(stmt.value)); + } + return std::move(list); + }); - if (!ok) - return nullptr; + if (body.errored) + return Failure::kErrored; return std::make_unique( - source, std::move(condition.value), std::move(body)); + source, std::move(condition.value), std::move(body.value)); } // switch_body // : CASE case_selectors COLON BRACKET_LEFT case_body BRACKET_RIGHT // | DEFAULT COLON BRACKET_LEFT case_body BRACKET_RIGHT -std::unique_ptr ParserImpl::switch_body() { +Maybe> ParserImpl::switch_body() { auto t = peek(); if (!t.IsCase() && !t.IsDefault()) - return nullptr; + return Failure::kNoMatch; auto source = t.source(); next(); // Consume the peek @@ -1625,26 +1620,25 @@ std::unique_ptr ParserImpl::switch_body() { stmt->set_source(source); if (t.IsCase()) { auto selectors = expect_case_selectors(); - if (has_error()) - return nullptr; - if (selectors.value.empty()) { - add_error(peek(), "unable to parse case selectors"); - return nullptr; - } + if (selectors.errored) + return Failure::kErrored; + stmt->set_selectors(std::move(selectors.value)); } const char* use = "case statement"; if (!expect(use, Token::Type::kColon)) - return nullptr; + return Failure::kErrored; - auto body = expect_brace_block_old(use, [&] { return case_body(); }); + auto body = expect_brace_block(use, [&] { return case_body(); }); - if (body == nullptr) - return nullptr; + if (body.errored) + return Failure::kErrored; + if (!body.matched) + return add_error(body.source, "expected case body"); - stmt->set_body(std::move(body)); + stmt->set_body(std::move(body.value)); return stmt; } @@ -1657,14 +1651,14 @@ Expect ParserImpl::expect_case_selectors() { for (;;) { auto t = peek(); auto cond = const_literal(); - if (has_error()) + if (cond.errored) return Failure::kErrored; - if (cond == nullptr) + if (!cond.matched) break; - if (!cond->IsInt()) + if (!cond.value->IsInt()) return add_error(t, "invalid case selector must be an integer value"); - std::unique_ptr selector(cond.release()->AsInt()); + std::unique_ptr selector(cond.value.release()->AsInt()); selectors.push_back(std::move(selector)); } @@ -1678,7 +1672,7 @@ Expect ParserImpl::expect_case_selectors() { // : // | statement case_body // | FALLTHROUGH SEMICOLON -std::unique_ptr ParserImpl::case_body() { +Maybe> ParserImpl::case_body() { auto ret = std::make_unique(); for (;;) { auto t = peek(); @@ -1687,19 +1681,19 @@ std::unique_ptr ParserImpl::case_body() { next(); // Consume the peek if (!expect("fallthrough statement", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; ret->append(std::make_unique(source)); break; } auto stmt = statement(); - if (has_error()) - return {}; - if (stmt == nullptr) + if (stmt.errored) + return Failure::kErrored; + if (!stmt.matched) break; - ret->append(std::move(stmt)); + ret->append(std::move(stmt.value)); } return ret; @@ -1707,23 +1701,23 @@ std::unique_ptr ParserImpl::case_body() { // loop_stmt // : LOOP BRACKET_LEFT statements continuing_stmt? BRACKET_RIGHT -std::unique_ptr ParserImpl::loop_stmt() { +Maybe> ParserImpl::loop_stmt() { Source source; if (!match(Token::Type::kLoop, &source)) - return nullptr; + return Failure::kNoMatch; - return expect_brace_block_old( - "loop", [&]() -> std::unique_ptr { + return expect_brace_block( + "loop", [&]() -> Maybe> { auto body = expect_statements(); if (body.errored) - return nullptr; + return Failure::kErrored; auto continuing = continuing_stmt(); - if (has_error()) - return nullptr; + if (continuing.errored) + return Failure::kErrored; return std::make_unique( - source, std::move(body.value), std::move(continuing)); + source, std::move(body.value), std::move(continuing.value)); }); } @@ -1736,78 +1730,91 @@ ForHeader::ForHeader(std::unique_ptr init, ForHeader::~ForHeader() = default; +// (variable_stmt | assignment_stmt | func_call_stmt)? +Maybe> ParserImpl::for_header_initializer() { + auto call = func_call_stmt(); + if (call.errored) + return Failure::kErrored; + if (call.matched) + return std::move(call.value); + + auto var = variable_stmt(); + if (var.errored) + return Failure::kErrored; + if (var.matched) + return std::move(var.value); + + auto assign = assignment_stmt(); + if (assign.errored) + return Failure::kErrored; + if (assign.matched) + return std::move(assign.value); + + return Failure::kNoMatch; +} + +// (assignment_stmt | func_call_stmt)? +Maybe> ParserImpl::for_header_continuing() { + auto call_stmt = func_call_stmt(); + if (call_stmt.errored) + return Failure::kErrored; + if (call_stmt.matched) + return std::move(call_stmt.value); + + auto assign = assignment_stmt(); + if (assign.errored) + return Failure::kErrored; + if (assign.matched) + return std::move(assign.value); + + return Failure::kNoMatch; +} + // for_header // : (variable_stmt | assignment_stmt | func_call_stmt)? // SEMICOLON // logical_or_expression? SEMICOLON // (assignment_stmt | func_call_stmt)? Expect> ParserImpl::expect_for_header() { - std::unique_ptr initializer = nullptr; - if (initializer == nullptr) { - initializer = func_call_stmt(); - if (has_error()) { - return Failure::kErrored; - } - } - if (initializer == nullptr) { - initializer = variable_stmt(); - if (has_error()) { - return Failure::kErrored; - } - } - if (initializer == nullptr) { - initializer = assignment_stmt(); - if (has_error()) { - return Failure::kErrored; - } - } + auto initializer = for_header_initializer(); + if (initializer.errored) + return Failure::kErrored; if (!expect("initializer in for loop", Token::Type::kSemicolon)) return Failure::kErrored; auto condition = logical_or_expression(); - if (has_error()) { + if (condition.errored) return Failure::kErrored; - } if (!expect("condition in for loop", Token::Type::kSemicolon)) return Failure::kErrored; - std::unique_ptr continuing = nullptr; - if (continuing == nullptr) { - continuing = func_call_stmt(); - if (has_error()) { - return Failure::kErrored; - } - } - if (continuing == nullptr) { - continuing = assignment_stmt(); - if (has_error()) { - return Failure::kErrored; - } - } + auto continuing = for_header_continuing(); + if (continuing.errored) + return Failure::kErrored; - return std::make_unique( - std::move(initializer), std::move(condition), std::move(continuing)); + return std::make_unique(std::move(initializer.value), + std::move(condition.value), + std::move(continuing.value)); } // for_statement // : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT -std::unique_ptr ParserImpl::for_stmt() { +Maybe> ParserImpl::for_stmt() { Source source; if (!match(Token::Type::kFor, &source)) - return nullptr; + return Failure::kNoMatch; auto header = expect_paren_block("for loop", [&] { return expect_for_header(); }); if (header.errored) - return nullptr; + return Failure::kErrored; auto body = expect_brace_block("for loop", [&] { return expect_statements(); }); - if (body.errored) - return nullptr; + return Failure::kErrored; // The for statement is a syntactic sugar on top of the loop statement. // We create corresponding nodes in ast with the exact same behaviour @@ -1852,11 +1859,11 @@ std::unique_ptr ParserImpl::for_stmt() { // func_call_stmt // : IDENT PAREN_LEFT argument_expression_list* PAREN_RIGHT -std::unique_ptr ParserImpl::func_call_stmt() { +Maybe> ParserImpl::func_call_stmt() { auto t = peek(); auto t2 = peek(1); if (!t.IsIdentifier() || !t2.IsParenLeft()) - return nullptr; + return Failure::kNoMatch; auto source = t.source(); @@ -1871,12 +1878,12 @@ std::unique_ptr ParserImpl::func_call_stmt() { if (!t.IsParenRight() && !t.IsEof()) { auto list = expect_argument_expression_list(); if (list.errored) - return nullptr; + return Failure::kErrored; params = std::move(list.value); } if (!expect("call statement", Token::Type::kParenRight)) - return nullptr; + return Failure::kErrored; return std::make_unique( std::make_unique( @@ -1886,31 +1893,31 @@ std::unique_ptr ParserImpl::func_call_stmt() { // break_stmt // : BREAK -std::unique_ptr ParserImpl::break_stmt() { +Maybe> ParserImpl::break_stmt() { Source source; if (!match(Token::Type::kBreak, &source)) - return nullptr; + return Failure::kNoMatch; return std::make_unique(source); } // continue_stmt // : CONTINUE -std::unique_ptr ParserImpl::continue_stmt() { +Maybe> ParserImpl::continue_stmt() { Source source; if (!match(Token::Type::kContinue, &source)) - return nullptr; + return Failure::kNoMatch; return std::make_unique(source); } // continuing_stmt // : CONTINUING body_stmt -std::unique_ptr ParserImpl::continuing_stmt() { +Maybe> ParserImpl::continuing_stmt() { if (!match(Token::Type::kContinuing)) return std::make_unique(); - return expect_body_stmt().value; + return expect_body_stmt(); } // primary_expression @@ -1919,90 +1926,78 @@ std::unique_ptr ParserImpl::continuing_stmt() { // | const_literal // | paren_rhs_stmt // | BITCAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt -std::unique_ptr ParserImpl::primary_expression() { +Maybe> ParserImpl::primary_expression() { auto t = peek(); auto source = t.source(); auto lit = const_literal(); - if (has_error()) - return nullptr; - if (lit != nullptr) { - return std::make_unique(source, - std::move(lit)); - } + if (lit.errored) + return Failure::kErrored; + if (lit.matched) + return std::make_unique( + source, std::move(lit.value)); - t = peek(); if (t.IsParenLeft()) { auto paren = expect_paren_rhs_stmt(); if (paren.errored) - return nullptr; + return Failure::kErrored; return std::move(paren.value); } - if (t.IsBitcast()) { - auto src = t; + if (match(Token::Type::kBitcast)) { + const char* use = "bitcast expression"; - next(); // Consume the peek + if (!expect(use, Token::Type::kLessThan)) + return Failure::kErrored; - t = next(); - if (!t.IsLessThan()) { - add_error(t, "missing < for bitcast expression"); - return nullptr; - } + auto type = type_decl(); + if (type.errored) + return Failure::kErrored; + if (!type.matched) + return add_error(peek().source(), "missing type", use); - auto* type = type_decl(); - if (has_error()) - return nullptr; - if (type == nullptr) { - add_error(peek(), "missing type for bitcast expression"); - return nullptr; - } - - t = next(); - if (!t.IsGreaterThan()) { - add_error(t, "missing > for bitcast expression"); - return nullptr; - } + if (!expect(use, Token::Type::kGreaterThan)) + return Failure::kErrored; auto params = expect_paren_rhs_stmt(); if (params.errored) - return nullptr; + return Failure::kErrored; - return std::make_unique(source, type, + return std::make_unique(source, type.value, std::move(params.value)); - } else if (t.IsIdentifier()) { - next(); // Consume the peek - - return std::make_unique(source, t.to_str()); } - auto* type = type_decl(); - if (has_error()) - return nullptr; - if (type != nullptr) { + if (match(Token::Type::kIdentifier)) + return std::make_unique(t.source(), t.to_str()); + + auto type = type_decl(); + if (type.errored) + return Failure::kErrored; + if (type.matched) { auto expr = expect_paren_block( "type constructor", [&]() -> Expect> { t = peek(); if (t.IsParenRight() || t.IsEof()) return std::make_unique( - source, type, ast::ExpressionList{}); + source, type.value, ast::ExpressionList{}); auto params = expect_argument_expression_list(); if (params.errored) return Failure::kErrored; return std::make_unique( - source, type, std::move(params.value)); + source, type.value, std::move(params.value)); }); if (expr.errored) - return nullptr; + return Failure::kErrored; return std::move(expr.value); } - return nullptr; + + return Failure::kNoMatch; } // postfix_expr @@ -2010,98 +2005,88 @@ std::unique_ptr ParserImpl::primary_expression() { // | BRACE_LEFT logical_or_expression BRACE_RIGHT postfix_expr // | PAREN_LEFT argument_expression_list* PAREN_RIGHT postfix_expr // | PERIOD IDENTIFIER postfix_expr -std::unique_ptr ParserImpl::postfix_expr( +Maybe> ParserImpl::postfix_expr( std::unique_ptr prefix) { - std::unique_ptr expr = nullptr; - - auto t = peek(); - auto source = t.source(); - if (t.IsBracketLeft()) { - next(); // Consume the peek - + Source source; + if (match(Token::Type::kBracketLeft, &source)) { auto param = logical_or_expression(); - if (has_error()) - return nullptr; - if (param == nullptr) { - add_error(peek(), "unable to parse expression inside []"); - return nullptr; - } + if (param.errored) + return Failure::kErrored; + if (!param.matched) + return add_error(peek(), "unable to parse expression inside []"); - t = next(); - if (!t.IsBracketRight()) { - add_error(t, "missing ] for array accessor"); - return nullptr; - } - expr = std::make_unique( - source, std::move(prefix), std::move(param)); + if (!expect("array accessor", Token::Type::kBracketRight)) + return Failure::kErrored; - } else if (t.IsParenLeft()) { - next(); // Consume the peek + return postfix_expr(std::make_unique( + source, std::move(prefix), std::move(param.value))); + } + if (match(Token::Type::kParenLeft, &source)) { ast::ExpressionList params; - t = peek(); + auto t = peek(); if (!t.IsParenRight() && !t.IsEof()) { auto list = expect_argument_expression_list(); if (list.errored) - return nullptr; + return Failure::kErrored; params = std::move(list.value); } if (!expect("call expression", Token::Type::kParenRight)) - return nullptr; + return Failure::kErrored; - expr = std::make_unique(source, std::move(prefix), - std::move(params)); - } else if (t.IsPeriod()) { - next(); // Consume the peek + return postfix_expr(std::make_unique( + source, std::move(prefix), std::move(params))); + } + if (match(Token::Type::kPeriod)) { auto ident = expect_ident("member accessor"); if (ident.errored) - return nullptr; + return Failure::kErrored; - expr = std::make_unique( + return postfix_expr(std::make_unique( ident.source, std::move(prefix), - std::make_unique(ident.source, ident.value)); - } else { - return prefix; + std::make_unique(ident.source, + ident.value))); } - return postfix_expr(std::move(expr)); + + return prefix; } // postfix_expression // : primary_expression postfix_expr -std::unique_ptr ParserImpl::postfix_expression() { +Maybe> ParserImpl::postfix_expression() { auto prefix = primary_expression(); - if (has_error()) - return nullptr; - if (prefix == nullptr) - return nullptr; + if (prefix.errored) + return Failure::kErrored; + if (!prefix.matched) + return Failure::kNoMatch; - return postfix_expr(std::move(prefix)); + return postfix_expr(std::move(prefix.value)); } // argument_expression_list // : (logical_or_expression COMMA)* logical_or_expression Expect ParserImpl::expect_argument_expression_list() { auto arg = logical_or_expression(); - if (has_error()) + if (arg.errored) return Failure::kErrored; - if (arg == nullptr) + if (!arg.matched) return add_error(peek(), "unable to parse argument expression"); ast::ExpressionList ret; - ret.push_back(std::move(arg)); + ret.push_back(std::move(arg.value)); while (match(Token::Type::kComma)) { arg = logical_or_expression(); - if (has_error()) + if (arg.errored) return Failure::kErrored; - if (arg == nullptr) { + if (!arg.matched) { return add_error(peek(), "unable to parse argument expression after comma"); } - ret.push_back(std::move(arg)); + ret.push_back(std::move(arg.value)); } return ret; } @@ -2110,7 +2095,7 @@ Expect ParserImpl::expect_argument_expression_list() { // : postfix_expression // | MINUS unary_expression // | BANG unary_expression -std::unique_ptr ParserImpl::unary_expression() { +Maybe> ParserImpl::unary_expression() { auto t = peek(); auto source = t.source(); if (t.IsMinus() || t.IsBang()) { @@ -2123,15 +2108,14 @@ std::unique_ptr ParserImpl::unary_expression() { op = ast::UnaryOp::kNot; auto expr = unary_expression(); - if (has_error()) - return nullptr; - if (expr == nullptr) { - add_error(peek(), - "unable to parse right side of " + name + " expression"); - return nullptr; - } + if (expr.errored) + return Failure::kErrored; + if (!expr.matched) + return add_error(peek(), + "unable to parse right side of " + name + " expression"); + return std::make_unique(source, op, - std::move(expr)); + std::move(expr.value)); } return postfix_expression(); } @@ -2160,26 +2144,28 @@ Expect> ParserImpl::expect_multiplicative_expr( next(); // Consume the peek auto rhs = unary_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) { + if (!rhs.matched) { return add_error(peek(), "unable to parse right side of " + name + " expression"); } + return expect_multiplicative_expr(std::make_unique( - source, op, std::move(lhs), std::move(rhs))); + source, op, std::move(lhs), std::move(rhs.value))); } // multiplicative_expression // : unary_expression multiplicative_expr -std::unique_ptr ParserImpl::multiplicative_expression() { +Maybe> +ParserImpl::multiplicative_expression() { auto lhs = unary_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_multiplicative_expr(std::move(lhs)).value; + return expect_multiplicative_expr(std::move(lhs.value)); } // additive_expr @@ -2202,24 +2188,25 @@ Expect> ParserImpl::expect_additive_expr( next(); // Consume the peek auto rhs = multiplicative_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of + expression"); + return expect_additive_expr(std::make_unique( - source, op, std::move(lhs), std::move(rhs))); + source, op, std::move(lhs), std::move(rhs.value))); } // additive_expression // : multiplicative_expression additive_expr -std::unique_ptr ParserImpl::additive_expression() { +Maybe> ParserImpl::additive_expression() { auto lhs = multiplicative_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_additive_expr(std::move(lhs)).value; + return expect_additive_expr(std::move(lhs.value)); } // shift_expr @@ -2249,26 +2236,26 @@ Expect> ParserImpl::expect_shift_expr( } auto rhs = additive_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) { + if (!rhs.matched) { return add_error(peek(), std::string("unable to parse right side of ") + name + " expression"); } return expect_shift_expr(std::make_unique( - source, op, std::move(lhs), std::move(rhs))); -} + source, op, std::move(lhs), std::move(rhs.value))); +} // namespace wgsl // shift_expression // : additive_expression shift_expr -std::unique_ptr ParserImpl::shift_expression() { +Maybe> ParserImpl::shift_expression() { auto lhs = additive_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_shift_expr(std::move(lhs)).value; + return expect_shift_expr(std::move(lhs.value)); } // relational_expr @@ -2297,27 +2284,27 @@ Expect> ParserImpl::expect_relational_expr( next(); // Consume the peek auto rhs = shift_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) { + if (!rhs.matched) { return add_error(peek(), "unable to parse right side of " + name + " expression"); } return expect_relational_expr(std::make_unique( - source, op, std::move(lhs), std::move(rhs))); + source, op, std::move(lhs), std::move(rhs.value))); } // relational_expression // : shift_expression relational_expr -std::unique_ptr ParserImpl::relational_expression() { +Maybe> ParserImpl::relational_expression() { auto lhs = shift_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_relational_expr(std::move(lhs)).value; + return expect_relational_expr(std::move(lhs.value)); } // equality_expr @@ -2340,27 +2327,27 @@ Expect> ParserImpl::expect_equality_expr( next(); // Consume the peek auto rhs = relational_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) { + if (!rhs.matched) { return add_error(peek(), "unable to parse right side of " + name + " expression"); } return expect_equality_expr(std::make_unique( - source, op, std::move(lhs), std::move(rhs))); + source, op, std::move(lhs), std::move(rhs.value))); } // equality_expression // : relational_expression equality_expr -std::unique_ptr ParserImpl::equality_expression() { +Maybe> ParserImpl::equality_expression() { auto lhs = relational_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_equality_expr(std::move(lhs)).value; + return expect_equality_expr(std::move(lhs.value)); } // and_expr @@ -2376,25 +2363,25 @@ Expect> ParserImpl::expect_and_expr( next(); // Consume the peek auto rhs = equality_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of & expression"); return expect_and_expr(std::make_unique( - source, ast::BinaryOp::kAnd, std::move(lhs), std::move(rhs))); + source, ast::BinaryOp::kAnd, std::move(lhs), std::move(rhs.value))); } // and_expression // : equality_expression and_expr -std::unique_ptr ParserImpl::and_expression() { +Maybe> ParserImpl::and_expression() { auto lhs = equality_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_and_expr(std::move(lhs)).value; + return expect_and_expr(std::move(lhs.value)); } // exclusive_or_expr @@ -2402,33 +2389,30 @@ std::unique_ptr ParserImpl::and_expression() { // | XOR and_expression exclusive_or_expr Expect> ParserImpl::expect_exclusive_or_expr( std::unique_ptr lhs) { - auto t = peek(); - if (!t.IsXor()) + Source source; + if (!match(Token::Type::kXor, &source)) return lhs; - auto source = t.source(); - next(); // Consume the peek - auto rhs = and_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of ^ expression"); return expect_exclusive_or_expr(std::make_unique( - source, ast::BinaryOp::kXor, std::move(lhs), std::move(rhs))); + source, ast::BinaryOp::kXor, std::move(lhs), std::move(rhs.value))); } // exclusive_or_expression // : and_expression exclusive_or_expr -std::unique_ptr ParserImpl::exclusive_or_expression() { +Maybe> ParserImpl::exclusive_or_expression() { auto lhs = and_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_exclusive_or_expr(std::move(lhs)).value; + return expect_exclusive_or_expr(std::move(lhs.value)); } // inclusive_or_expr @@ -2436,33 +2420,30 @@ std::unique_ptr ParserImpl::exclusive_or_expression() { // | OR exclusive_or_expression inclusive_or_expr Expect> ParserImpl::expect_inclusive_or_expr( std::unique_ptr lhs) { - auto t = peek(); - if (!t.IsOr()) + Source source; + if (!match(Token::Type::kOr)) return lhs; - auto source = t.source(); - next(); // Consume the peek - auto rhs = exclusive_or_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of | expression"); return expect_inclusive_or_expr(std::make_unique( - source, ast::BinaryOp::kOr, std::move(lhs), std::move(rhs))); + source, ast::BinaryOp::kOr, std::move(lhs), std::move(rhs.value))); } // inclusive_or_expression // : exclusive_or_expression inclusive_or_expr -std::unique_ptr ParserImpl::inclusive_or_expression() { +Maybe> ParserImpl::inclusive_or_expression() { auto lhs = exclusive_or_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_inclusive_or_expr(std::move(lhs)).value; + return expect_inclusive_or_expr(std::move(lhs.value)); } // logical_and_expr @@ -2478,25 +2459,26 @@ Expect> ParserImpl::expect_logical_and_expr( next(); // Consume the peek auto rhs = inclusive_or_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of && expression"); return expect_logical_and_expr(std::make_unique( - source, ast::BinaryOp::kLogicalAnd, std::move(lhs), std::move(rhs))); + source, ast::BinaryOp::kLogicalAnd, std::move(lhs), + std::move(rhs.value))); } // logical_and_expression // : inclusive_or_expression logical_and_expr -std::unique_ptr ParserImpl::logical_and_expression() { +Maybe> ParserImpl::logical_and_expression() { auto lhs = inclusive_or_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_logical_and_expr(std::move(lhs)).value; + return expect_logical_and_expr(std::move(lhs.value)); } // logical_or_expr @@ -2504,63 +2486,55 @@ std::unique_ptr ParserImpl::logical_and_expression() { // | OR_OR logical_and_expression logical_or_expr Expect> ParserImpl::expect_logical_or_expr( std::unique_ptr lhs) { - auto t = peek(); - if (!t.IsOrOr()) + Source source; + if (!match(Token::Type::kOrOr)) return lhs; - auto source = t.source(); - next(); // Consume the peek - auto rhs = logical_and_expression(); - if (has_error()) + if (rhs.errored) return Failure::kErrored; - if (rhs == nullptr) + if (!rhs.matched) return add_error(peek(), "unable to parse right side of || expression"); return expect_logical_or_expr(std::make_unique( - source, ast::BinaryOp::kLogicalOr, std::move(lhs), std::move(rhs))); + source, ast::BinaryOp::kLogicalOr, std::move(lhs), std::move(rhs.value))); } // logical_or_expression // : logical_and_expression logical_or_expr -std::unique_ptr ParserImpl::logical_or_expression() { +Maybe> ParserImpl::logical_or_expression() { auto lhs = logical_and_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - return expect_logical_or_expr(std::move(lhs)).value; + return expect_logical_or_expr(std::move(lhs.value)); } // assignment_stmt // : unary_expression EQUAL logical_or_expression -std::unique_ptr ParserImpl::assignment_stmt() { +Maybe> ParserImpl::assignment_stmt() { auto t = peek(); auto source = t.source(); auto lhs = unary_expression(); - if (has_error()) - return nullptr; - if (lhs == nullptr) - return nullptr; + if (lhs.errored) + return Failure::kErrored; + if (!lhs.matched) + return Failure::kNoMatch; - t = next(); - if (!t.IsEqual()) { - add_error(t, "missing = for assignment"); - return nullptr; - } + if (!expect("assignment", Token::Type::kEqual)) + return Failure::kErrored; auto rhs = logical_or_expression(); - if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of assignment"); - return nullptr; - } + if (rhs.errored) + return Failure::kErrored; + if (!rhs.matched) + return add_error(peek(), "unable to parse right side of assignment"); - return std::make_unique(source, std::move(lhs), - std::move(rhs)); + return std::make_unique( + source, std::move(lhs.value), std::move(rhs.value)); } // const_literal @@ -2569,7 +2543,7 @@ std::unique_ptr ParserImpl::assignment_stmt() { // | FLOAT_LITERAL // | TRUE // | FALSE -std::unique_ptr ParserImpl::const_literal() { +Maybe> ParserImpl::const_literal() { auto t = peek(); if (match(Token::Type::kTrue)) { auto* type = ctx_.type_mgr().Get(std::make_unique()); @@ -2591,7 +2565,7 @@ std::unique_ptr ParserImpl::const_literal() { auto* type = ctx_.type_mgr().Get(std::make_unique()); return std::make_unique(type, t.to_f32()); } - return nullptr; + return Failure::kNoMatch; } // const_expr @@ -2612,8 +2586,10 @@ ParserImpl::expect_const_expr_internal(uint32_t depth) { auto source = t.source(); - auto* type = type_decl(); - if (type != nullptr) { + auto type = type_decl(); + if (type.errored) + return Failure::kErrored; + if (type.matched) { auto params = expect_paren_block( "type constructor", [&]() -> Expect { ast::ExpressionList list; @@ -2634,42 +2610,52 @@ ParserImpl::expect_const_expr_internal(uint32_t depth) { return Failure::kErrored; return std::make_unique( - source, type, std::move(params.value)); + source, type.value, std::move(params.value)); } auto lit = const_literal(); - if (has_error()) + if (lit.errored) return Failure::kErrored; - if (lit == nullptr) { - add_error(peek(), "unable to parse const literal"); - return Failure::kErrored; - } - return std::make_unique(source, - std::move(lit)); + if (!lit.matched) + return add_error(peek(), "unable to parse const literal"); + + return std::make_unique( + source, std::move(lit.value)); } -ast::DecorationList ParserImpl::decoration_list() { +Maybe ParserImpl::decoration_list() { + bool matched = false; ast::DecorationList decos; - while (decoration_bracketed_list(decos)) { + + while (true) { + auto list = decoration_bracketed_list(decos); + if (list.errored) + return Failure::kErrored; + if (!list.matched) + break; + + matched = true; } + + if (!matched) + return Failure::kNoMatch; + return decos; } -bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { +Maybe ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { if (!match(Token::Type::kAttrLeft)) { - return false; + return Failure::kNoMatch; } Source source; - if (match(Token::Type::kAttrRight, &source)) { - add_error(source, "empty decoration list"); - return false; - } + if (match(Token::Type::kAttrRight, &source)) + return add_error(source, "empty decoration list"); while (true) { auto deco = expect_decoration(); if (deco.errored) - return false; + return Failure::kErrored; decos.emplace_back(std::move(deco.value)); @@ -2682,87 +2668,90 @@ bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { // e.g. [[location(1) set(2)]] // ^^^ expected comma expect("decoration list", Token::Type::kComma); - return false; + return Failure::kErrored; } - return expect("decoration list", Token::Type::kAttrRight); + if (!expect("decoration list", Token::Type::kAttrRight)) + return Failure::kErrored; + + return true; } } Expect> ParserImpl::expect_decoration() { auto t = peek(); auto deco = decoration(); - if (has_error()) + if (deco.errored) return Failure::kErrored; - if (deco == nullptr) - return add_error(t, "expected decoration"); - return std::move(deco); + if (deco.matched) + return std::move(deco.value); + return add_error(t, "expected decoration"); } -std::unique_ptr ParserImpl::decoration() { - using Result = std::unique_ptr; +Maybe> ParserImpl::decoration() { + using Result = Maybe>; auto t = next(); if (t.IsLocation()) { const char* use = "location decoration"; - return expect_paren_block_old(use, [&]() -> Result { + return expect_paren_block(use, [&]() -> Result { auto val = expect_positive_sint(use); if (val.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(val.value, val.source); }); } if (t.IsBinding()) { const char* use = "binding decoration"; - return expect_paren_block_old(use, [&]() -> Result { + return expect_paren_block(use, [&]() -> Result { auto val = expect_positive_sint(use); if (val.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(val.value, val.source); }); } if (t.IsSet()) { const char* use = "set decoration"; - return expect_paren_block_old(use, [&]() -> Result { + return expect_paren_block(use, [&]() -> Result { auto val = expect_positive_sint(use); if (val.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(val.value, val.source); }); } if (t.IsBuiltin()) { - return expect_paren_block_old("builtin decoration", [&]() -> Result { + return expect_paren_block("builtin decoration", [&]() -> Result { auto builtin = expect_builtin(); if (builtin.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(builtin.value, builtin.source); }); } if (t.IsWorkgroupSize()) { - return expect_paren_block_old("workgroup_size decoration", [&]() -> Result { + return expect_paren_block("workgroup_size decoration", [&]() -> Result { uint32_t x; uint32_t y = 1; uint32_t z = 1; auto val = expect_nonzero_positive_sint("workgroup_size x parameter"); if (val.errored) - return nullptr; + return Failure::kErrored; x = val.value; if (match(Token::Type::kComma)) { val = expect_nonzero_positive_sint("workgroup_size y parameter"); if (val.errored) - return nullptr; + return Failure::kErrored; y = val.value; if (match(Token::Type::kComma)) { val = expect_nonzero_positive_sint("workgroup_size z parameter"); if (val.errored) - return nullptr; + return Failure::kErrored; z = val.value; } } @@ -2771,10 +2760,10 @@ std::unique_ptr ParserImpl::decoration() { }); } if (t.IsStage()) { - return expect_paren_block_old("stage decoration", [&]() -> Result { + return expect_paren_block("stage decoration", [&]() -> Result { auto stage = expect_pipeline_stage(); if (stage.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(stage.value, stage.source); }); @@ -2784,26 +2773,26 @@ std::unique_ptr ParserImpl::decoration() { } if (t.IsStride()) { const char* use = "stride decoration"; - return expect_paren_block_old(use, [&]() -> Result { + return expect_paren_block(use, [&]() -> Result { auto val = expect_nonzero_positive_sint(use); if (val.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(val.value, t.source()); }); } if (t.IsOffset()) { const char* use = "offset decoration"; - return expect_paren_block_old(use, [&]() -> Result { + return expect_paren_block(use, [&]() -> Result { auto val = expect_positive_sint(use); if (val.errored) - return nullptr; + return Failure::kErrored; return std::make_unique(val.value, t.source()); }); } - return nullptr; + return Failure::kNoMatch; } template @@ -2908,24 +2897,6 @@ Expect ParserImpl::expect_ident(const std::string& use) { return {t.to_str(), t.source()}; } -template -T ParserImpl::expect_block_old(Token::Type start, - Token::Type end, - const std::string& use, - F&& body) { - if (!expect(use, start)) { - return {}; - } - auto res = body(); - if (has_error()) { - return {}; - } - if (!expect(use, end)) { - return {}; - } - return res; -} - template T ParserImpl::expect_block(Token::Type start, Token::Type end, @@ -2944,18 +2915,6 @@ T ParserImpl::expect_block(Token::Type start, return res; } -template -T ParserImpl::expect_paren_block_old(const std::string& use, F&& body) { - return expect_block_old(Token::Type::kParenLeft, Token::Type::kParenRight, - use, std::forward(body)); -} - -template -T ParserImpl::expect_brace_block_old(const std::string& use, F&& body) { - return expect_block_old(Token::Type::kBraceLeft, Token::Type::kBraceRight, - use, std::forward(body)); -} - template T ParserImpl::expect_paren_block(const std::string& use, F&& body) { return expect_block(Token::Type::kParenLeft, Token::Type::kParenRight, use, diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 5bddd68ae8..ab3efeaea1 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -80,10 +80,11 @@ struct ForHeader { /// ParserImpl for WGSL source data class ParserImpl { - /// Failure holds enumerator values used for the constructing an Expect in the - /// errored state. + /// Failure holds enumerator values used for the constructing an Expect and + /// Match in an errored state. struct Failure { enum Errored { kErrored }; + enum NoMatch { kNoMatch }; }; public: @@ -135,6 +136,74 @@ class ParserImpl { bool errored = false; }; + /// Maybe is the return type of the parser methods that attempts to match a + /// grammar and return a parsed value of type T, or may parse part of the + /// grammar and then hit a parse error. + /// In the case of a successful grammar match, the Maybe will have |matched| + /// set to true. + /// In the case of a parse error the called method will have called + /// |add_error()| and the Maybe will have |errored| set to true. + template + struct Maybe { + inline Maybe(std::nullptr_t) = delete; // NOLINT + + /// Constructor for a successful parse. + /// @param val the result value of the parse + /// @param s the optional source of the value + template + inline Maybe(U&& val, const Source& s = {}) // NOLINT + : value(std::forward(val)), source(s), matched(true) {} + + /// Constructor for parse error state. + inline Maybe(Failure::Errored) : errored(true) {} // NOLINT + + /// Constructor for the no-match state. + inline Maybe(Failure::NoMatch) {} // NOLINT + + /// Constructor from an Expect. + template + inline Maybe(const Expect& e) // NOLINT + : value(e.value), + source(e.value), + errored(e.errored), + matched(!e.errored) {} + + /// Move from an Expect. + template + inline Maybe(Expect&& e) // NOLINT + : value(std::move(e.value)), + source(std::move(e.source)), + errored(e.errored), + matched(!e.errored) {} + + /// Copy constructor + inline Maybe(const Maybe&) = default; + /// Move constructor + inline Maybe(Maybe&&) = default; + /// Assignment operator + /// @return this Maybe + inline Maybe& operator=(const Maybe&) = default; + /// Assignment move operator + /// @return this Maybe + inline Maybe& operator=(Maybe&&) = default; + + /// @return a pointer to |value|. |errored| must be false to call. + inline T* operator->() { + assert(!errored); + return &value; + } + + /// The value of a successful parse. + /// Zero-initialized when there was a parse error. + T value{}; + /// Optional source of the value. + Source source; + /// True if there was a error parsing. + bool errored = false; + /// True if there was a error parsing. + bool matched = false; + }; + /// TypedIdentifier holds a parsed identifier and type. Returned by /// variable_ident_decl(). struct TypedIdentifier { @@ -223,14 +292,14 @@ class ParserImpl { /// `variable_decoration_list*` provided as |decos|. /// @returns the variable parsed or nullptr /// @param decos the list of decorations for the variable declaration. - std::unique_ptr global_variable_decl( + Maybe> 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(); + Maybe> global_constant_decl(); /// Parses a `variable_decl` grammar element /// @returns the parsed variable or nullptr otherwise - std::unique_ptr variable_decl(); + Maybe> variable_decl(); /// Parses a `variable_ident_decl` grammar element, erroring on parse /// failure. /// @param use a description of what was being parsed if an error was raised. @@ -238,13 +307,13 @@ class ParserImpl { Expect expect_variable_ident_decl(const std::string& use); /// Parses a `variable_storage_decoration` grammar element /// @returns the storage class or StorageClass::kNone if none matched - ast::StorageClass variable_storage_decoration(); + Maybe variable_storage_decoration(); /// Parses a `type_alias` grammar element /// @returns the type alias or nullptr on error - ast::type::Type* type_alias(); + Maybe type_alias(); /// Parses a `type_decl` grammar element /// @returns the parsed Type or nullptr if none matched. - ast::type::Type* type_decl(); + Maybe type_decl(); /// Parses a `storage_class` grammar element, erroring on parse failure. /// @param use a description of what was being parsed if an error was raised. /// @returns the storage class or StorageClass::kNone if none matched @@ -253,7 +322,7 @@ class ParserImpl { /// `struct_decoration_decl*` provided as |decos|. /// @returns the struct type or nullptr on error /// @param decos the list of decorations for the struct declaration. - std::unique_ptr struct_decl( + Maybe> struct_decl( ast::DecorationList& decos); /// Parses a `struct_body_decl` grammar element, erroring on parse failure. /// @returns the struct members @@ -269,39 +338,40 @@ class ParserImpl { /// `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(ast::DecorationList& decos); + Maybe> 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(); + Maybe texture_sampler_types(); /// Parses a `sampler_type` grammar element /// @returns the parsed Type or nullptr if none matched. - ast::type::Type* sampler_type(); + Maybe sampler_type(); /// Parses a `multisampled_texture_type` grammar element /// @returns returns the multisample texture dimension or kNone if none /// matched. - ast::type::TextureDimension multisampled_texture_type(); + Maybe multisampled_texture_type(); /// Parses a `sampled_texture_type` grammar element /// @returns returns the sample texture dimension or kNone if none matched. - ast::type::TextureDimension sampled_texture_type(); + Maybe 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 + Maybe> 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(); + Maybe depth_texture_type(); /// Parses a `image_storage_type` grammar element - /// @param use a description of what was being parsed if an error was raised. + /// @param use a description of what was being parsed if an error was raised /// @returns returns the image format or kNone if none matched. Expect expect_image_storage_type( const std::string& use); /// Parses a `function_type_decl` grammar element /// @returns the parsed type or nullptr otherwise - ast::type::Type* function_type_decl(); + Maybe function_type_decl(); /// Parses a `function_header` grammar element /// @returns the parsed function nullptr otherwise - std::unique_ptr function_header(); + Maybe> function_header(); /// Parses a `param_list` grammar element, erroring on parse failure. /// @returns the parsed variables Expect expect_param_list(); @@ -324,64 +394,64 @@ class ParserImpl { Expect> expect_statements(); /// Parses a `statement` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr statement(); + Maybe> statement(); /// Parses a `break_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr break_stmt(); + Maybe> break_stmt(); /// Parses a `return_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr return_stmt(); + Maybe> return_stmt(); /// Parses a `continue_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr continue_stmt(); + Maybe> continue_stmt(); /// Parses a `variable_stmt` grammar element /// @returns the parsed variable or nullptr - std::unique_ptr variable_stmt(); + Maybe> variable_stmt(); /// Parses a `if_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr if_stmt(); + Maybe> if_stmt(); /// Parses a `elseif_stmt` grammar element /// @returns the parsed elements - ast::ElseStatementList elseif_stmt(); + Maybe elseif_stmt(); /// Parses a `else_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr else_stmt(); + Maybe> else_stmt(); /// Parses a `switch_stmt` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr switch_stmt(); + Maybe> switch_stmt(); /// Parses a `switch_body` grammar element /// @returns the parsed statement or nullptr - std::unique_ptr switch_body(); + Maybe> switch_body(); /// Parses a `case_selectors` grammar element /// @returns the list of literals Expect expect_case_selectors(); /// Parses a `case_body` grammar element /// @returns the parsed statements - std::unique_ptr case_body(); + Maybe> case_body(); /// Parses a `func_call_stmt` grammar element /// @returns the parsed function call or nullptr - std::unique_ptr func_call_stmt(); + Maybe> func_call_stmt(); /// Parses a `loop_stmt` grammar element /// @returns the parsed loop or nullptr - std::unique_ptr loop_stmt(); + Maybe> loop_stmt(); /// Parses a `for_header` grammar element, erroring on parse failure. /// @returns the parsed for header or nullptr Expect> expect_for_header(); /// Parses a `for_stmt` grammar element /// @returns the parsed for loop or nullptr - std::unique_ptr for_stmt(); + Maybe> for_stmt(); /// Parses a `continuing_stmt` grammar element /// @returns the parsed statements - std::unique_ptr continuing_stmt(); + Maybe> continuing_stmt(); /// Parses a `const_literal` grammar element /// @returns the const literal parsed or nullptr if none found - std::unique_ptr const_literal(); + Maybe> const_literal(); /// Parses a `const_expr` grammar element, erroring on parse failure. /// @returns the parsed constructor expression or nullptr on error Expect> expect_const_expr(); /// Parses a `primary_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr primary_expression(); + Maybe> primary_expression(); /// Parses a `argument_expression_list` grammar element, erroring on parse /// failure. /// @returns the list of arguments @@ -389,14 +459,14 @@ class ParserImpl { /// Parses the recursive portion of the postfix_expression /// @param prefix the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr postfix_expr( + Maybe> postfix_expr( std::unique_ptr prefix); /// Parses a `postfix_expression` grammar elment /// @returns the parsed expression or nullptr - std::unique_ptr postfix_expression(); + Maybe> postfix_expression(); /// Parses a `unary_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr unary_expression(); + Maybe> unary_expression(); /// Parses the recursive part of the `multiplicative_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -405,7 +475,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `multiplicative_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr multiplicative_expression(); + Maybe> multiplicative_expression(); /// Parses the recursive part of the `additive_expression`, erroring on parse /// failure. /// @param lhs the left side of the expression @@ -414,7 +484,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `additive_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr additive_expression(); + Maybe> additive_expression(); /// Parses the recursive part of the `shift_expression`, erroring on parse /// failure. /// @param lhs the left side of the expression @@ -423,7 +493,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `shift_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr shift_expression(); + Maybe> shift_expression(); /// Parses the recursive part of the `relational_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -432,7 +502,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `relational_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr relational_expression(); + Maybe> relational_expression(); /// Parses the recursive part of the `equality_expression`, erroring on parse /// failure. /// @param lhs the left side of the expression @@ -441,7 +511,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `equality_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr equality_expression(); + Maybe> equality_expression(); /// Parses the recursive part of the `and_expression`, erroring on parse /// failure. /// @param lhs the left side of the expression @@ -450,7 +520,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `and_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr and_expression(); + Maybe> and_expression(); /// Parses the recursive part of the `exclusive_or_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -459,7 +529,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `exclusive_or_expression` grammar elememnt /// @returns the parsed expression or nullptr - std::unique_ptr exclusive_or_expression(); + Maybe> exclusive_or_expression(); /// Parses the recursive part of the `inclusive_or_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -468,7 +538,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses the `inclusive_or_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr inclusive_or_expression(); + Maybe> inclusive_or_expression(); /// Parses the recursive part of the `logical_and_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -477,7 +547,7 @@ class ParserImpl { std::unique_ptr lhs); /// Parses a `logical_and_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr logical_and_expression(); + Maybe> logical_and_expression(); /// Parses the recursive part of the `logical_or_expression`, erroring on /// parse failure. /// @param lhs the left side of the expression @@ -486,18 +556,18 @@ class ParserImpl { std::unique_ptr lhs); /// Parses a `logical_or_expression` grammar element /// @returns the parsed expression or nullptr - std::unique_ptr logical_or_expression(); + Maybe> logical_or_expression(); /// Parses a `assignment_stmt` grammar element /// @returns the parsed assignment or nullptr - std::unique_ptr assignment_stmt(); + Maybe> assignment_stmt(); /// Parses one or more bracketed decoration lists. /// @return the parsed decoration list, or an empty list on error. - ast::DecorationList decoration_list(); + Maybe 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); + Maybe decoration_bracketed_list(ast::DecorationList& decos); /// Parses a single decoration of the following types: /// * `struct_decoration` /// * `struct_member_decoration` @@ -506,7 +576,7 @@ class ParserImpl { /// * `global_const_decoration` /// * `function_decoration` /// @return the parsed decoration, or nullptr. - std::unique_ptr decoration(); + Maybe> 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. @@ -568,7 +638,7 @@ class ParserImpl { /// @param body a function or lambda that is called to parse the lexical block /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise - /// a zero-initialized |T|. + /// an Expect with error state. template > T expect_block(Token::Type start, Token::Type end, @@ -581,7 +651,7 @@ class ParserImpl { /// @param body a function or lambda that is called to parse the lexical block /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise - /// a zero-initialized |T|. + /// an Expect with error state. template > T expect_paren_block(const std::string& use, F&& body); /// A convenience function that calls |expect_block| passing @@ -591,24 +661,10 @@ class ParserImpl { /// @param body a function or lambda that is called to parse the lexical block /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise - /// a zero-initialized |T|. + /// an Expect with error state. template > T expect_brace_block(const std::string& use, F&& body); - // Versions of expect_block(), expect_paren_block_old(), - // expect_brace_block_old() that do not take an Expect for T. - // These will be removed in the near future. - // TODO(ben-clayton) - migrate remaining uses of these. - template > - T expect_block_old(Token::Type start, - Token::Type end, - const std::string& use, - F&& body); - template > - T expect_paren_block_old(const std::string& use, F&& body); - template > - T expect_brace_block_old(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 @@ -627,6 +683,9 @@ class ParserImpl { Expect> expect_const_expr_internal(uint32_t depth); + Maybe> for_header_initializer(); + Maybe> for_header_continuing(); + Context& ctx_; diag::List diags_; std::unique_ptr lexer_; diff --git a/src/reader/wgsl/parser_impl_additive_expression_test.cc b/src/reader/wgsl/parser_impl_additive_expression_test.cc index a80ab600a9..7a939753bc 100644 --- a/src/reader/wgsl/parser_impl_additive_expression_test.cc +++ b/src/reader/wgsl/parser_impl_additive_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) { auto* p = parser("a + true"); auto e = p->additive_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kAdd, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,11 +51,13 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) { TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) { auto* p = parser("a - true"); auto e = p->additive_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -70,24 +74,30 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) { TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) { auto* p = parser("if (a) {} + true"); auto e = p->additive_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) { auto* p = parser("true + if (a) {}"); auto e = p->additive_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression"); } TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->additive_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_and_expression_test.cc b/src/reader/wgsl/parser_impl_and_expression_test.cc index 6bd1039383..2b85958696 100644 --- a/src/reader/wgsl/parser_impl_and_expression_test.cc +++ b/src/reader/wgsl/parser_impl_and_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, AndExpression_Parses) { auto* p = parser("a & true"); auto e = p->and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kAnd, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,24 +51,30 @@ TEST_F(ParserImplTest, AndExpression_Parses) { TEST_F(ParserImplTest, AndExpression_InvalidLHS) { auto* p = parser("if (a) {} & true"); auto e = p->and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, AndExpression_InvalidRHS) { auto* p = parser("true & if (a) {}"); auto e = p->and_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression"); } TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc index fd7778f863..304781efb4 100644 --- a/src/reader/wgsl/parser_impl_assignment_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_assignment_stmt_test.cc @@ -31,21 +31,23 @@ namespace { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) { auto* p = parser("a = 123"); auto e = p->assignment_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsAssign()); - ASSERT_NE(e->lhs(), nullptr); - ASSERT_NE(e->rhs(), nullptr); + ASSERT_TRUE(e.value->IsAssign()); + ASSERT_NE(e.value->lhs(), nullptr); + ASSERT_NE(e.value->rhs(), nullptr); - ASSERT_TRUE(e->lhs()->IsIdentifier()); - auto* ident = e->lhs()->AsIdentifier(); + ASSERT_TRUE(e.value->lhs()->IsIdentifier()); + auto* ident = e.value->lhs()->AsIdentifier(); EXPECT_EQ(ident->name(), "a"); - ASSERT_TRUE(e->rhs()->IsConstructor()); - ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor()); + ASSERT_TRUE(e.value->rhs()->IsConstructor()); + ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor()); - auto* init = e->rhs()->AsConstructor()->AsScalarConstructor(); + auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor(); ASSERT_NE(init->literal(), nullptr); ASSERT_TRUE(init->literal()->IsSint()); EXPECT_EQ(init->literal()->AsSint()->value(), 123); @@ -54,22 +56,24 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) { auto* p = parser("a.b.c[2].d = 123"); auto e = p->assignment_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsAssign()); - ASSERT_NE(e->lhs(), nullptr); - ASSERT_NE(e->rhs(), nullptr); + ASSERT_TRUE(e.value->IsAssign()); + ASSERT_NE(e.value->lhs(), nullptr); + ASSERT_NE(e.value->rhs(), nullptr); - ASSERT_TRUE(e->rhs()->IsConstructor()); - ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor()); - auto* init = e->rhs()->AsConstructor()->AsScalarConstructor(); + ASSERT_TRUE(e.value->rhs()->IsConstructor()); + ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor()); + auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor(); ASSERT_NE(init->literal(), nullptr); ASSERT_TRUE(init->literal()->IsSint()); EXPECT_EQ(init->literal()->AsSint()->value(), 123); - ASSERT_TRUE(e->lhs()->IsMemberAccessor()); - auto* mem = e->lhs()->AsMemberAccessor(); + ASSERT_TRUE(e.value->lhs()->IsMemberAccessor()); + auto* mem = e.value->lhs()->AsMemberAccessor(); ASSERT_TRUE(mem->member()->IsIdentifier()); auto* ident = mem->member()->AsIdentifier(); @@ -106,23 +110,29 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) { TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) { auto* p = parser("a.b.c[2].d 123"); auto e = p->assignment_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); - EXPECT_EQ(p->error(), "1:12: missing = for assignment"); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); + EXPECT_EQ(p->error(), "1:12: expected '=' for assignment"); } TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) { auto* p = parser("if (true) {} = 123"); auto e = p->assignment_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) { auto* p = parser("a.b.c[2].d = if (true) {}"); auto e = p->assignment_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment"); } diff --git a/src/reader/wgsl/parser_impl_break_stmt_test.cc b/src/reader/wgsl/parser_impl_break_stmt_test.cc index 4eba1591b5..8fd49c36fa 100644 --- a/src/reader/wgsl/parser_impl_break_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_break_stmt_test.cc @@ -25,9 +25,10 @@ namespace { TEST_F(ParserImplTest, BreakStmt) { auto* p = parser("break"); auto e = p->break_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsBreak()); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsBreak()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_call_stmt_test.cc b/src/reader/wgsl/parser_impl_call_stmt_test.cc index 2ab8b19550..ded8f509bc 100644 --- a/src/reader/wgsl/parser_impl_call_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_call_stmt_test.cc @@ -28,10 +28,12 @@ TEST_F(ParserImplTest, Statement_Call) { auto* p = parser("a();"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + ASSERT_NE(e.value, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); - ASSERT_TRUE(e->IsCall()); - auto* c = e->AsCall()->expr(); + ASSERT_TRUE(e.value->IsCall()); + auto* c = e.value->AsCall()->expr(); ASSERT_TRUE(c->func()->IsIdentifier()); auto* func = c->func()->AsIdentifier(); @@ -44,10 +46,12 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) { auto* p = parser("a(1, b, 2 + 3 / b);"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + ASSERT_NE(e.value, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); - ASSERT_TRUE(e->IsCall()); - auto* c = e->AsCall()->expr(); + ASSERT_TRUE(e.value->IsCall()); + auto* c = e.value->AsCall()->expr(); ASSERT_TRUE(c->func()->IsIdentifier()); auto* func = c->func()->AsIdentifier(); @@ -62,21 +66,27 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) { TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) { auto* p = parser("a("); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); EXPECT_EQ(p->error(), "1:3: expected ')' for call statement"); } TEST_F(ParserImplTest, Statement_Call_Missing_Semi) { auto* p = parser("a()"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); EXPECT_EQ(p->error(), "1:4: expected ';' for function call"); } TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) { auto* p = parser("a(b c);"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); EXPECT_EQ(p->error(), "1:5: expected ')' for call statement"); } diff --git a/src/reader/wgsl/parser_impl_case_body_test.cc b/src/reader/wgsl/parser_impl_case_body_test.cc index b878037126..b840d70beb 100644 --- a/src/reader/wgsl/parser_impl_case_body_test.cc +++ b/src/reader/wgsl/parser_impl_case_body_test.cc @@ -25,7 +25,9 @@ TEST_F(ParserImplTest, CaseBody_Empty) { auto* p = parser(""); auto e = p->case_body(); ASSERT_FALSE(p->has_error()) << p->error(); - EXPECT_EQ(e->size(), 0u); + EXPECT_FALSE(e.errored); + EXPECT_TRUE(e.matched); + EXPECT_EQ(e.value->size(), 0u); } TEST_F(ParserImplTest, CaseBody_Statements) { @@ -35,31 +37,39 @@ TEST_F(ParserImplTest, CaseBody_Statements) { auto e = p->case_body(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 2u); - EXPECT_TRUE(e->get(0)->IsVariableDecl()); - EXPECT_TRUE(e->get(1)->IsAssign()); + EXPECT_FALSE(e.errored); + EXPECT_TRUE(e.matched); + ASSERT_EQ(e.value->size(), 2u); + EXPECT_TRUE(e.value->get(0)->IsVariableDecl()); + EXPECT_TRUE(e.value->get(1)->IsAssign()); } TEST_F(ParserImplTest, CaseBody_InvalidStatement) { auto* p = parser("a ="); auto e = p->case_body(); - ASSERT_TRUE(p->has_error()); - EXPECT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, CaseBody_Fallthrough) { auto* p = parser("fallthrough;"); auto e = p->case_body(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 1u); - EXPECT_TRUE(e->get(0)->IsFallthrough()); + EXPECT_FALSE(e.errored); + EXPECT_TRUE(e.matched); + ASSERT_EQ(e.value->size(), 1u); + EXPECT_TRUE(e.value->get(0)->IsFallthrough()); } TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) { auto* p = parser("fallthrough"); auto e = p->case_body(); - ASSERT_TRUE(p->has_error()); - EXPECT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement"); } diff --git a/src/reader/wgsl/parser_impl_const_literal_test.cc b/src/reader/wgsl/parser_impl_const_literal_test.cc index 3a5420a909..28b0771f5b 100644 --- a/src/reader/wgsl/parser_impl_const_literal_test.cc +++ b/src/reader/wgsl/parser_impl_const_literal_test.cc @@ -28,59 +28,73 @@ namespace { TEST_F(ParserImplTest, ConstLiteral_Int) { auto* p = parser("-234"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(c, nullptr); - ASSERT_TRUE(c->IsSint()); - EXPECT_EQ(c->AsSint()->value(), -234); + EXPECT_TRUE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(c.value, nullptr); + ASSERT_TRUE(c.value->IsSint()); + EXPECT_EQ(c.value->AsSint()->value(), -234); } TEST_F(ParserImplTest, ConstLiteral_Uint) { auto* p = parser("234u"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(c, nullptr); - ASSERT_TRUE(c->IsUint()); - EXPECT_EQ(c->AsUint()->value(), 234u); + EXPECT_TRUE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(c.value, nullptr); + ASSERT_TRUE(c.value->IsUint()); + EXPECT_EQ(c.value->AsUint()->value(), 234u); } TEST_F(ParserImplTest, ConstLiteral_Float) { auto* p = parser("234.e12"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(c, nullptr); - ASSERT_TRUE(c->IsFloat()); - EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12f); + EXPECT_TRUE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(c.value, nullptr); + ASSERT_TRUE(c.value->IsFloat()); + EXPECT_FLOAT_EQ(c.value->AsFloat()->value(), 234e12f); } TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) { auto* p = parser("1.2e+256"); auto c = p->const_literal(); - ASSERT_EQ(c, nullptr); + EXPECT_FALSE(c.matched); + EXPECT_FALSE(c.errored); + ASSERT_EQ(c.value, nullptr); } TEST_F(ParserImplTest, ConstLiteral_True) { auto* p = parser("true"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(c, nullptr); - ASSERT_TRUE(c->IsBool()); - EXPECT_TRUE(c->AsBool()->IsTrue()); + EXPECT_TRUE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(c.value, nullptr); + ASSERT_TRUE(c.value->IsBool()); + EXPECT_TRUE(c.value->AsBool()->IsTrue()); } TEST_F(ParserImplTest, ConstLiteral_False) { auto* p = parser("false"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(c, nullptr); - ASSERT_TRUE(c->IsBool()); - EXPECT_TRUE(c->AsBool()->IsFalse()); + EXPECT_TRUE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(c.value, nullptr); + ASSERT_TRUE(c.value->IsBool()); + EXPECT_TRUE(c.value->AsBool()->IsFalse()); } TEST_F(ParserImplTest, ConstLiteral_NoMatch) { auto* p = parser("another-token"); auto c = p->const_literal(); - ASSERT_FALSE(p->has_error()); - ASSERT_EQ(c, nullptr); + EXPECT_FALSE(c.matched); + EXPECT_FALSE(c.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_EQ(c.value, nullptr); } } // namespace diff --git a/src/reader/wgsl/parser_impl_continue_stmt_test.cc b/src/reader/wgsl/parser_impl_continue_stmt_test.cc index 8207e5763e..1a7f644ab4 100644 --- a/src/reader/wgsl/parser_impl_continue_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_continue_stmt_test.cc @@ -25,9 +25,10 @@ namespace { TEST_F(ParserImplTest, ContinueStmt) { auto* p = parser("continue"); auto e = p->continue_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsContinue()); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsContinue()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_continuing_stmt_test.cc b/src/reader/wgsl/parser_impl_continuing_stmt_test.cc index 9f2ab58143..e29b1d405f 100644 --- a/src/reader/wgsl/parser_impl_continuing_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_continuing_stmt_test.cc @@ -24,16 +24,20 @@ namespace { TEST_F(ParserImplTest, ContinuingStmt) { auto* p = parser("continuing { discard; }"); auto e = p->continuing_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 1u); - ASSERT_TRUE(e->get(0)->IsDiscard()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value->size(), 1u); + ASSERT_TRUE(e.value->get(0)->IsDiscard()); } TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) { auto* p = parser("continuing { discard }"); auto e = p->continuing_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement"); } diff --git a/src/reader/wgsl/parser_impl_depth_texture_type_test.cc b/src/reader/wgsl/parser_impl_depth_texture_type_test.cc index d86c03c932..35119bbfce 100644 --- a/src/reader/wgsl/parser_impl_depth_texture_type_test.cc +++ b/src/reader/wgsl/parser_impl_depth_texture_type_test.cc @@ -24,48 +24,58 @@ namespace { TEST_F(ParserImplTest, DepthTextureType_Invalid) { auto* p = parser("1234"); - auto* t = p->depth_texture_type(); - EXPECT_EQ(t, nullptr); + auto t = p->depth_texture_type(); + EXPECT_FALSE(t.matched); + EXPECT_FALSE(t.errored); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, DepthTextureType_2d) { auto* p = parser("texture_depth_2d"); - auto* t = p->depth_texture_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsDepth()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + auto t = p->depth_texture_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsDepth()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, DepthTextureType_2dArray) { auto* p = parser("texture_depth_2d_array"); - auto* t = p->depth_texture_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsDepth()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2dArray); + auto t = p->depth_texture_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsDepth()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2dArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, DepthTextureType_Cube) { auto* p = parser("texture_depth_cube"); - auto* t = p->depth_texture_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsDepth()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCube); + auto t = p->depth_texture_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsDepth()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::kCube); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, DepthTextureType_CubeArray) { auto* p = parser("texture_depth_cube_array"); - auto* t = p->depth_texture_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsDepth()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCubeArray); + auto t = p->depth_texture_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsDepth()); + EXPECT_EQ(t.value->AsTexture()->dim(), + ast::type::TextureDimension::kCubeArray); EXPECT_FALSE(p->has_error()); } diff --git a/src/reader/wgsl/parser_impl_else_stmt_test.cc b/src/reader/wgsl/parser_impl_else_stmt_test.cc index f83fa4a957..08313f2d1e 100644 --- a/src/reader/wgsl/parser_impl_else_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_else_stmt_test.cc @@ -25,26 +25,32 @@ namespace { TEST_F(ParserImplTest, ElseStmt) { auto* p = parser("else { a = b; c = d; }"); auto e = p->else_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsElse()); - ASSERT_EQ(e->condition(), nullptr); - EXPECT_EQ(e->body()->size(), 2u); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsElse()); + ASSERT_EQ(e.value->condition(), nullptr); + EXPECT_EQ(e.value->body()->size(), 2u); } TEST_F(ParserImplTest, ElseStmt_InvalidBody) { auto* p = parser("else { fn main() -> void {}}"); auto e = p->else_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected '}'"); } TEST_F(ParserImplTest, ElseStmt_MissingBody) { auto* p = parser("else"); auto e = p->else_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:5: expected '{'"); } diff --git a/src/reader/wgsl/parser_impl_elseif_stmt_test.cc b/src/reader/wgsl/parser_impl_elseif_stmt_test.cc index 93ce334e24..dd1ae17891 100644 --- a/src/reader/wgsl/parser_impl_elseif_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_elseif_stmt_test.cc @@ -25,43 +25,51 @@ namespace { TEST_F(ParserImplTest, ElseIfStmt) { auto* p = parser("elseif (a == 4) { a = b; c = d; }"); auto e = p->elseif_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e.size(), 1u); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value.size(), 1u); - ASSERT_TRUE(e[0]->IsElse()); - ASSERT_NE(e[0]->condition(), nullptr); - ASSERT_TRUE(e[0]->condition()->IsBinary()); - EXPECT_EQ(e[0]->body()->size(), 2u); + ASSERT_TRUE(e.value[0]->IsElse()); + ASSERT_NE(e.value[0]->condition(), nullptr); + ASSERT_TRUE(e.value[0]->condition()->IsBinary()); + EXPECT_EQ(e.value[0]->body()->size(), 2u); } TEST_F(ParserImplTest, ElseIfStmt_Multiple) { auto* p = parser("elseif (a == 4) { a = b; c = d; } elseif(c) { d = 2; }"); auto e = p->elseif_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e.size(), 2u); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value.size(), 2u); - ASSERT_TRUE(e[0]->IsElse()); - ASSERT_NE(e[0]->condition(), nullptr); - ASSERT_TRUE(e[0]->condition()->IsBinary()); - EXPECT_EQ(e[0]->body()->size(), 2u); + ASSERT_TRUE(e.value[0]->IsElse()); + ASSERT_NE(e.value[0]->condition(), nullptr); + ASSERT_TRUE(e.value[0]->condition()->IsBinary()); + EXPECT_EQ(e.value[0]->body()->size(), 2u); - ASSERT_TRUE(e[1]->IsElse()); - ASSERT_NE(e[1]->condition(), nullptr); - ASSERT_TRUE(e[1]->condition()->IsIdentifier()); - EXPECT_EQ(e[1]->body()->size(), 1u); + ASSERT_TRUE(e.value[1]->IsElse()); + ASSERT_NE(e.value[1]->condition(), nullptr); + ASSERT_TRUE(e.value[1]->condition()->IsIdentifier()); + EXPECT_EQ(e.value[1]->body()->size(), 1u); } TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) { auto* p = parser("elseif (true) { fn main() -> void {}}"); auto e = p->elseif_stmt(); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:17: expected '}'"); } TEST_F(ParserImplTest, ElseIfStmt_MissingBody) { auto* p = parser("elseif (true)"); auto e = p->elseif_stmt(); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:14: expected '{'"); } diff --git a/src/reader/wgsl/parser_impl_equality_expression_test.cc b/src/reader/wgsl/parser_impl_equality_expression_test.cc index c3fefe12e1..9801d006aa 100644 --- a/src/reader/wgsl/parser_impl_equality_expression_test.cc +++ b/src/reader/wgsl/parser_impl_equality_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) { auto* p = parser("a == true"); auto e = p->equality_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kEqual, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,11 +51,13 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) { TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) { auto* p = parser("a != true"); auto e = p->equality_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -70,24 +74,30 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) { TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) { auto* p = parser("if (a) {} == true"); auto e = p->equality_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) { auto* p = parser("true == if (a) {}"); auto e = p->equality_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression"); } TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->equality_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc index 222134e368..08d84ebdd1 100644 --- a/src/reader/wgsl/parser_impl_error_msg_test.cc +++ b/src/reader/wgsl/parser_impl_error_msg_test.cc @@ -56,21 +56,21 @@ TEST_F(ParserImplErrorTest, ArrayIndexExprInvalidExpr) { TEST_F(ParserImplErrorTest, ArrayIndexExprMissingRBracket) { EXPECT("fn f() -> void { x = y[1; }", - "test.wgsl:1:25 error: missing ] for array accessor\n" + "test.wgsl:1:25 error: expected ']' for array accessor\n" "fn f() -> void { x = y[1; }\n" " ^\n"); } TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment) { EXPECT("fn f() -> void { a; }", - "test.wgsl:1:19 error: missing = for assignment\n" + "test.wgsl:1:19 error: expected '=' for assignment\n" "fn f() -> void { a; }\n" " ^\n"); } TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) { EXPECT("fn f() -> void { a : i32; }", - "test.wgsl:1:20 error: missing = for assignment\n" + "test.wgsl:1:20 error: expected '=' for assignment\n" "fn f() -> void { a : i32; }\n" " ^\n"); } @@ -91,14 +91,14 @@ TEST_F(ParserImplErrorTest, AssignmentStmtInvalidRHS) { TEST_F(ParserImplErrorTest, BitcastExprMissingLessThan) { EXPECT("fn f() -> void { x = bitcast(y); }", - "test.wgsl:1:29 error: missing < for bitcast expression\n" + "test.wgsl:1:29 error: expected '<' for bitcast expression\n" "fn f() -> void { x = bitcast(y); }\n" " ^\n"); } TEST_F(ParserImplErrorTest, BitcastExprMissingGreaterThan) { EXPECT("fn f() -> void { x = bitcast for bitcast expression\n" + "test.wgsl:1:33 error: expected '>' for bitcast expression\n" "fn f() -> void { x = bitcast for function declaration\n" + "test.wgsl:1:8 error: expected '->' for function declaration\n" "fn f() void {}\n" " ^^^^\n"); } @@ -995,14 +995,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) { TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingLessThan) { EXPECT("var i : mat4x4;", - "test.wgsl:1:15 error: missing < for matrix\n" + "test.wgsl:1:15 error: expected '<' for matrix\n" "var i : mat4x4;\n" " ^\n"); } TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) { EXPECT("var i : mat4x4 for matrix\n" + "test.wgsl:1:19 error: expected '>' for matrix\n" "var i : mat4x4exclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kXor, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,24 +51,30 @@ TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) { TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) { auto* p = parser("if (a) {} ^ true"); auto e = p->exclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) { auto* p = parser("true ^ if (a) {}"); auto e = p->exclusive_or_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression"); } TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->exclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_for_stmt_test.cc b/src/reader/wgsl/parser_impl_for_stmt_test.cc index 3520a58ad2..fe9b63f051 100644 --- a/src/reader/wgsl/parser_impl_for_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_for_stmt_test.cc @@ -161,8 +161,10 @@ class ForStmtErrorTest : public ParserImplTest { auto* p_for = parser(for_str); auto e_for = p_for->for_stmt(); - ASSERT_TRUE(p_for->has_error()); - ASSERT_EQ(e_for, nullptr); + EXPECT_FALSE(e_for.matched); + EXPECT_TRUE(e_for.errored); + EXPECT_TRUE(p_for->has_error()); + ASSERT_EQ(e_for.value, nullptr); EXPECT_EQ(p_for->error(), error_str); } }; diff --git a/src/reader/wgsl/parser_impl_function_decl_test.cc b/src/reader/wgsl/parser_impl_function_decl_test.cc index 2de8075c85..68ba11a6f1 100644 --- a/src/reader/wgsl/parser_impl_function_decl_test.cc +++ b/src/reader/wgsl/parser_impl_function_decl_test.cc @@ -26,56 +26,64 @@ namespace { TEST_F(ParserImplTest, FunctionDecl) { auto* p = parser("fn main(a : i32, b : f32) -> void { return; }"); - 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(f.errored); + EXPECT_TRUE(f.matched); + ASSERT_NE(f.value, nullptr); - EXPECT_EQ(f->name(), "main"); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); + EXPECT_EQ(f.value->name(), "main"); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); - ASSERT_EQ(f->params().size(), 2u); - EXPECT_EQ(f->params()[0]->name(), "a"); - EXPECT_EQ(f->params()[1]->name(), "b"); + ASSERT_EQ(f.value->params().size(), 2u); + EXPECT_EQ(f.value->params()[0]->name(), "a"); + EXPECT_EQ(f.value->params()[1]->name(), "b"); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); - auto* body = f->body(); + auto* body = f.value->body(); ASSERT_EQ(body->size(), 1u); EXPECT_TRUE(body->get(0)->IsReturn()); } TEST_F(ParserImplTest, FunctionDecl_DecorationList) { auto* p = parser("[[workgroup_size(2, 3, 4)]] fn main() -> void { return; }"); - 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + ASSERT_TRUE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(f.errored); + EXPECT_TRUE(f.matched); + ASSERT_NE(f.value, nullptr); - EXPECT_EQ(f->name(), "main"); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); - ASSERT_EQ(f->params().size(), 0u); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); + EXPECT_EQ(f.value->name(), "main"); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); + ASSERT_EQ(f.value->params().size(), 0u); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); - auto& decos = f->decorations(); - ASSERT_EQ(decos.size(), 1u); - ASSERT_TRUE(decos[0]->IsWorkgroup()); + auto& decorations = f.value->decorations(); + ASSERT_EQ(decorations.size(), 1u); + ASSERT_TRUE(decorations[0]->IsWorkgroup()); uint32_t x = 0; uint32_t y = 0; uint32_t z = 0; - std::tie(x, y, z) = decos[0]->AsWorkgroup()->values(); + std::tie(x, y, z) = decorations[0]->AsWorkgroup()->values(); EXPECT_EQ(x, 2u); EXPECT_EQ(y, 3u); EXPECT_EQ(z, 4u); - auto* body = f->body(); + auto* body = f.value->body(); ASSERT_EQ(body->size(), 1u); EXPECT_TRUE(body->get(0)->IsReturn()); } @@ -84,38 +92,42 @@ 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 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + ASSERT_TRUE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(f.errored); + EXPECT_TRUE(f.matched); + ASSERT_NE(f.value, nullptr); - EXPECT_EQ(f->name(), "main"); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); - ASSERT_EQ(f->params().size(), 0u); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); + EXPECT_EQ(f.value->name(), "main"); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); + ASSERT_EQ(f.value->params().size(), 0u); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); - auto& decos = f->decorations(); - ASSERT_EQ(decos.size(), 2u); + auto& decorations = f.value->decorations(); + ASSERT_EQ(decorations.size(), 2u); 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(decorations[0]->IsWorkgroup()); + std::tie(x, y, z) = decorations[0]->AsWorkgroup()->values(); EXPECT_EQ(x, 2u); EXPECT_EQ(y, 3u); EXPECT_EQ(z, 4u); - ASSERT_TRUE(decos[1]->IsWorkgroup()); - std::tie(x, y, z) = decos[1]->AsWorkgroup()->values(); + ASSERT_TRUE(decorations[1]->IsWorkgroup()); + std::tie(x, y, z) = decorations[1]->AsWorkgroup()->values(); EXPECT_EQ(x, 5u); EXPECT_EQ(y, 6u); EXPECT_EQ(z, 7u); - auto* body = f->body(); + auto* body = f.value->body(); ASSERT_EQ(body->size(), 1u); EXPECT_TRUE(body->get(0)->IsReturn()); } @@ -126,19 +138,23 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList_MultipleLists) { [[workgroup_size(5, 6, 7)]] fn main() -> void { return; })"); 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); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decorations.errored); + ASSERT_TRUE(decorations.matched); + auto f = p->function_decl(decorations.value); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(f.errored); + EXPECT_TRUE(f.matched); + ASSERT_NE(f.value, nullptr); - EXPECT_EQ(f->name(), "main"); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); - ASSERT_EQ(f->params().size(), 0u); - ASSERT_NE(f->return_type(), nullptr); - EXPECT_TRUE(f->return_type()->IsVoid()); + EXPECT_EQ(f.value->name(), "main"); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); + ASSERT_EQ(f.value->params().size(), 0u); + ASSERT_NE(f.value->return_type(), nullptr); + EXPECT_TRUE(f.value->return_type()->IsVoid()); - auto& decos = f->decorations(); + auto& decos = f.value->decorations(); ASSERT_EQ(decos.size(), 2u); uint32_t x = 0; @@ -156,38 +172,50 @@ fn main() -> void { return; })"); EXPECT_EQ(y, 6u); EXPECT_EQ(z, 7u); - auto* body = f->body(); + auto* body = f.value->body(); ASSERT_EQ(body->size(), 1u); EXPECT_TRUE(body->get(0)->IsReturn()); } TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { auto* p = parser("fn main() -> { }"); - 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_TRUE(f.errored); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:14: unable to determine function return type"); } TEST_F(ParserImplTest, FunctionDecl_InvalidBody) { auto* p = parser("fn main() -> void { return }"); - 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_TRUE(f.errored); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:28: expected ';' for return statement"); } TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) { auto* p = parser("fn main() -> void return; }"); - 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); + auto decos = p->decoration_list(); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto f = p->function_decl(decos.value); + EXPECT_TRUE(f.errored); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, 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 3010a46f82..325049041e 100644 --- a/src/reader/wgsl/parser_impl_function_decoration_list_test.cc +++ b/src/reader/wgsl/parser_impl_function_decoration_list_test.cc @@ -25,11 +25,13 @@ namespace { TEST_F(ParserImplTest, FunctionDecorationList_Parses) { auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)]]"); auto decos = p->decoration_list(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(decos.size(), 2u); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 2u); - auto deco_0 = ast::As(std::move(decos[0])); - auto deco_1 = ast::As(std::move(decos[1])); + auto deco_0 = ast::As(std::move(decos.value[0])); + auto deco_1 = ast::As(std::move(decos.value[1])); ASSERT_NE(deco_0, nullptr); ASSERT_NE(deco_1, nullptr); @@ -49,47 +51,59 @@ TEST_F(ParserImplTest, FunctionDecorationList_Parses) { TEST_F(ParserImplTest, FunctionDecorationList_Empty) { auto* p = parser("[[]]"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:3: empty decoration list"); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, FunctionDecorationList_Invalid) { auto* p = parser("[[invalid]]"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_TRUE(decos.empty()); - ASSERT_EQ(p->error(), "1:3: expected decoration"); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:3: expected decoration"); } TEST_F(ParserImplTest, FunctionDecorationList_ExtraComma) { auto* p = parser("[[workgroup_size(2), ]]"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:22: expected decoration"); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(p->error(), "1:22: expected decoration"); } TEST_F(ParserImplTest, FunctionDecorationList_MissingComma) { auto* p = parser("[[workgroup_size(2) workgroup_size(2)]]"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:21: expected ',' for decoration list"); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(p->error(), "1:21: expected ',' for decoration list"); } TEST_F(ParserImplTest, FunctionDecorationList_BadDecoration) { auto* p = parser("[[workgroup_size()]]"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ( + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ( p->error(), "1:18: expected signed integer literal for workgroup_size x parameter"); } TEST_F(ParserImplTest, FunctionDecorationList_MissingRightAttr) { auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)"); - ast::DecorationList decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:45: expected ']]' for decoration list"); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_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 90c9344cde..05185693f7 100644 --- a/src/reader/wgsl/parser_impl_function_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_function_decoration_test.cc @@ -26,9 +26,11 @@ namespace { TEST_F(ParserImplTest, FunctionDecoration_Workgroup) { auto* p = parser("workgroup_size(4)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr) << p->error(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - auto func_deco = ast::As(std::move(deco)); + auto func_deco = ast::As(std::move(deco.value)); ASSERT_NE(func_deco, nullptr); ASSERT_TRUE(func_deco->IsWorkgroup()); @@ -44,9 +46,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) { auto* p = parser("workgroup_size(4, 5)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr) << p->error(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - auto func_deco = ast::As(std::move(deco)); + auto func_deco = ast::As(std::move(deco.value)); ASSERT_NE(func_deco, nullptr) << p->error(); ASSERT_TRUE(func_deco->IsWorkgroup()); @@ -62,9 +66,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) { auto* p = parser("workgroup_size(4, 5, 6)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr) << p->error(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - auto func_deco = ast::As(std::move(deco)); + auto func_deco = ast::As(std::move(deco.value)); ASSERT_NE(func_deco, nullptr); ASSERT_TRUE(func_deco->IsWorkgroup()); @@ -80,16 +86,20 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_TooManyValues) { auto* p = parser("workgroup_size(1, 2, 3, 4)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) { auto* p = parser("workgroup_size(-2, 5, 6)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: workgroup_size x parameter must be greater than 0"); } @@ -97,8 +107,10 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:19: workgroup_size y parameter must be greater than 0"); } @@ -106,8 +118,10 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:22: workgroup_size z parameter must be greater than 0"); } @@ -115,24 +129,30 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingRightParam) { auto* p = parser("workgroup_size(4, 5, 6"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) { auto* p = parser("workgroup_size()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:16: expected signed integer literal for workgroup_size x parameter"); @@ -141,8 +161,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) { auto* p = parser("workgroup_size(, 2, 3)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:16: expected signed integer literal for workgroup_size x parameter"); @@ -151,16 +173,20 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) { auto* p = parser("workgroup_size(1, , 3)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:19: expected signed integer literal for workgroup_size y parameter"); @@ -169,16 +195,20 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) { auto* p = parser("workgroup_size(1, 2, )"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:22: expected signed integer literal for workgroup_size z parameter"); @@ -187,8 +217,10 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:16: expected signed integer literal for workgroup_size x parameter"); @@ -197,8 +229,10 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:19: expected signed integer literal for workgroup_size y parameter"); @@ -207,8 +241,10 @@ 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->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ( p->error(), "1:22: expected signed integer literal for workgroup_size z parameter"); @@ -217,9 +253,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Stage) { auto* p = parser("stage(compute)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr) << p->error(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - auto func_deco = ast::As(std::move(deco)); + auto func_deco = ast::As(std::move(deco.value)); ASSERT_NE(func_deco, nullptr); ASSERT_TRUE(func_deco->IsStage()); EXPECT_EQ(func_deco->AsStage()->value(), ast::PipelineStage::kCompute); @@ -228,32 +266,40 @@ TEST_F(ParserImplTest, FunctionDecoration_Stage) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) { auto* p = parser("stage()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) { auto* p = parser("stage(nan)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) { auto* p = parser("stage compute)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: expected '(' for stage decoration"); } TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingRightParen) { auto* p = parser("stage(compute"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:14: expected ')' for stage decoration"); } diff --git a/src/reader/wgsl/parser_impl_function_header_test.cc b/src/reader/wgsl/parser_impl_function_header_test.cc index 20a94ff60d..a7f000b321 100644 --- a/src/reader/wgsl/parser_impl_function_header_test.cc +++ b/src/reader/wgsl/parser_impl_function_header_test.cc @@ -27,76 +27,94 @@ TEST_F(ParserImplTest, FunctionHeader) { auto* p = parser("fn main(a : i32, b: f32) -> void"); auto f = p->function_header(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(f, nullptr); + EXPECT_TRUE(f.matched); + EXPECT_FALSE(f.errored); + ASSERT_NE(f.value, nullptr); - EXPECT_EQ(f->name(), "main"); - ASSERT_EQ(f->params().size(), 2u); - EXPECT_EQ(f->params()[0]->name(), "a"); - EXPECT_EQ(f->params()[1]->name(), "b"); - EXPECT_TRUE(f->return_type()->IsVoid()); + EXPECT_EQ(f.value->name(), "main"); + ASSERT_EQ(f.value->params().size(), 2u); + EXPECT_EQ(f.value->params()[0]->name(), "a"); + EXPECT_EQ(f.value->params()[1]->name(), "b"); + EXPECT_TRUE(f.value->return_type()->IsVoid()); } TEST_F(ParserImplTest, FunctionHeader_MissingIdent) { auto* p = parser("fn () ->"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration"); } TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) { auto* p = parser("fn 133main() -> i32"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration"); } TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) { auto* p = parser("fn main) -> i32"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:8: expected '(' for function declaration"); } TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) { auto* p = parser("fn main(a :i32,) -> i32"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:16: expected identifier for parameter"); } TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) { auto* p = parser("fn main( -> i32"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:10: expected ')' for function declaration"); } TEST_F(ParserImplTest, FunctionHeader_MissingArrow) { auto* p = parser("fn main() i32"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); - EXPECT_EQ(p->error(), "1:11: missing -> for function declaration"); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); + EXPECT_EQ(p->error(), "1:11: expected '->' for function declaration"); } TEST_F(ParserImplTest, FunctionHeader_InvalidReturnType) { auto* p = parser("fn main() -> invalid"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:14: unknown constructed type 'invalid'"); } TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) { auto* p = parser("fn main() ->"); auto f = p->function_header(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(f, nullptr); + EXPECT_FALSE(f.matched); + EXPECT_TRUE(f.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(f.value, nullptr); EXPECT_EQ(p->error(), "1:13: unable to determine function return type"); } diff --git a/src/reader/wgsl/parser_impl_function_type_decl_test.cc b/src/reader/wgsl/parser_impl_function_type_decl_test.cc index 30bc6059ab..14bf09d7d8 100644 --- a/src/reader/wgsl/parser_impl_function_type_decl_test.cc +++ b/src/reader/wgsl/parser_impl_function_type_decl_test.cc @@ -31,9 +31,11 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Void) { auto* v = tm()->Get(std::make_unique()); auto* p = parser("void"); - auto* e = p->function_type_decl(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, v); + auto e = p->function_type_decl(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value, v); } TEST_F(ParserImplTest, FunctionTypeDecl_Type) { @@ -41,16 +43,20 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Type) { auto* vec2 = tm()->Get(std::make_unique(f32, 2)); auto* p = parser("vec2"); - auto* e = p->function_type_decl(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, vec2); + auto e = p->function_type_decl(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value, vec2); } TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) { auto* p = parser("vec2"); - auto* e = p->function_type_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + auto e = p->function_type_decl(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: unknown constructed type 'invalid'"); } 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 fd2719b97c..929be791b8 100644 --- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc +++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc @@ -26,52 +26,62 @@ namespace { TEST_F(ParserImplTest, GlobalConstantDecl) { auto* p = parser("const a : f32 = 1."); auto e = p->global_constant_decl(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + 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->name(), "a"); - ASSERT_NE(e->type(), nullptr); - EXPECT_TRUE(e->type()->IsF32()); + EXPECT_TRUE(e.value->is_const()); + EXPECT_EQ(e.value->name(), "a"); + ASSERT_NE(e.value->type(), nullptr); + EXPECT_TRUE(e.value->type()->IsF32()); - EXPECT_EQ(e->source().range.begin.line, 1u); - EXPECT_EQ(e->source().range.begin.column, 7u); - EXPECT_EQ(e->source().range.end.line, 1u); - EXPECT_EQ(e->source().range.end.column, 8u); + EXPECT_EQ(e.value->source().range.begin.line, 1u); + EXPECT_EQ(e.value->source().range.begin.column, 7u); + EXPECT_EQ(e.value->source().range.end.line, 1u); + EXPECT_EQ(e.value->source().range.end.column, 8u); - ASSERT_NE(e->constructor(), nullptr); - EXPECT_TRUE(e->constructor()->IsConstructor()); + ASSERT_NE(e.value->constructor(), nullptr); + EXPECT_TRUE(e.value->constructor()->IsConstructor()); } TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) { auto* p = parser("const a: f32 1."); auto e = p->global_constant_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:14: expected '=' for constant declaration"); } TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { auto* p = parser("const a: invalid = 1."); auto e = p->global_constant_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'"); } TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) { auto* p = parser("const a: f32 = if (a) {}"); auto e = p->global_constant_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:16: unable to parse const literal"); } TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) { auto* p = parser("const a: f32 ="); auto e = p->global_constant_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:15: unable to parse const literal"); } 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 49494c1256..d6dbcbd544 100644 --- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc +++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc @@ -25,130 +25,161 @@ namespace { TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) { auto* p = parser("var a : f32"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_variable_decl(decos.value); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); - EXPECT_EQ(e->name(), "a"); - EXPECT_TRUE(e->type()->IsF32()); - EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); + EXPECT_EQ(e.value->name(), "a"); + EXPECT_TRUE(e.value->type()->IsF32()); + EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput); - EXPECT_EQ(e->source().range.begin.line, 1u); - EXPECT_EQ(e->source().range.begin.column, 10u); - EXPECT_EQ(e->source().range.end.line, 1u); - EXPECT_EQ(e->source().range.end.column, 11u); + EXPECT_EQ(e.value->source().range.begin.line, 1u); + EXPECT_EQ(e.value->source().range.begin.column, 10u); + EXPECT_EQ(e.value->source().range.end.line, 1u); + EXPECT_EQ(e.value->source().range.end.column, 11u); - ASSERT_EQ(e->constructor(), nullptr); - ASSERT_FALSE(e->IsDecorated()); + ASSERT_EQ(e.value->constructor(), nullptr); + ASSERT_FALSE(e.value->IsDecorated()); } TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) { auto* p = parser("var a : f32 = 1."); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_variable_decl(decos.value); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); - EXPECT_EQ(e->name(), "a"); - EXPECT_TRUE(e->type()->IsF32()); - EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); + EXPECT_EQ(e.value->name(), "a"); + EXPECT_TRUE(e.value->type()->IsF32()); + EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput); - EXPECT_EQ(e->source().range.begin.line, 1u); - EXPECT_EQ(e->source().range.begin.column, 10u); - EXPECT_EQ(e->source().range.end.line, 1u); - EXPECT_EQ(e->source().range.end.column, 11u); + EXPECT_EQ(e.value->source().range.begin.line, 1u); + EXPECT_EQ(e.value->source().range.begin.column, 10u); + EXPECT_EQ(e.value->source().range.end.line, 1u); + EXPECT_EQ(e.value->source().range.end.column, 11u); - ASSERT_NE(e->constructor(), nullptr); - ASSERT_TRUE(e->constructor()->IsConstructor()); - ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor()); + ASSERT_NE(e.value->constructor(), nullptr); + ASSERT_TRUE(e.value->constructor()->IsConstructor()); + ASSERT_TRUE(e.value->constructor()->AsConstructor()->IsScalarConstructor()); - ASSERT_FALSE(e->IsDecorated()); + ASSERT_FALSE(e.value->IsDecorated()); } TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) { auto* p = parser("[[binding(2), set(1)]] var a : f32"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + auto e = p->global_variable_decl(decos.value); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsDecorated()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsDecorated()); - EXPECT_EQ(e->name(), "a"); - ASSERT_NE(e->type(), nullptr); - EXPECT_TRUE(e->type()->IsF32()); - EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); + EXPECT_EQ(e.value->name(), "a"); + ASSERT_NE(e.value->type(), nullptr); + EXPECT_TRUE(e.value->type()->IsF32()); + EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput); - EXPECT_EQ(e->source().range.begin.line, 1u); - EXPECT_EQ(e->source().range.begin.column, 33u); - EXPECT_EQ(e->source().range.end.line, 1u); - EXPECT_EQ(e->source().range.end.column, 34u); + EXPECT_EQ(e.value->source().range.begin.line, 1u); + EXPECT_EQ(e.value->source().range.begin.column, 33u); + EXPECT_EQ(e.value->source().range.end.line, 1u); + EXPECT_EQ(e.value->source().range.end.column, 34u); - ASSERT_EQ(e->constructor(), nullptr); + ASSERT_EQ(e.value->constructor(), nullptr); - ASSERT_TRUE(e->IsDecorated()); - auto* v = e->AsDecorated(); + ASSERT_TRUE(e.value->IsDecorated()); + auto* v = e.value->AsDecorated(); - auto& decos = v->decorations(); - ASSERT_EQ(decos.size(), 2u); - ASSERT_TRUE(decos[0]->IsBinding()); - ASSERT_TRUE(decos[1]->IsSet()); + auto& decorations = v->decorations(); + ASSERT_EQ(decorations.size(), 2u); + ASSERT_TRUE(decorations[0]->IsBinding()); + ASSERT_TRUE(decorations[1]->IsSet()); } TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) { auto* p = parser("[[binding(2)]] [[set(1)]] var a : f32"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + + auto e = p->global_variable_decl(decos.value); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsDecorated()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsDecorated()); - EXPECT_EQ(e->name(), "a"); - ASSERT_NE(e->type(), nullptr); - EXPECT_TRUE(e->type()->IsF32()); - EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); + EXPECT_EQ(e.value->name(), "a"); + ASSERT_NE(e.value->type(), nullptr); + EXPECT_TRUE(e.value->type()->IsF32()); + EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput); - EXPECT_EQ(e->source().range.begin.line, 1u); - EXPECT_EQ(e->source().range.begin.column, 36u); - EXPECT_EQ(e->source().range.end.line, 1u); - EXPECT_EQ(e->source().range.end.column, 37u); + EXPECT_EQ(e.value->source().range.begin.line, 1u); + EXPECT_EQ(e.value->source().range.begin.column, 36u); + EXPECT_EQ(e.value->source().range.end.line, 1u); + EXPECT_EQ(e.value->source().range.end.column, 37u); - ASSERT_EQ(e->constructor(), nullptr); + ASSERT_EQ(e.value->constructor(), nullptr); - ASSERT_TRUE(e->IsDecorated()); - auto* v = e->AsDecorated(); + ASSERT_TRUE(e.value->IsDecorated()); + auto* v = e.value->AsDecorated(); - auto& decos = v->decorations(); - ASSERT_EQ(decos.size(), 2u); - ASSERT_TRUE(decos[0]->IsBinding()); - ASSERT_TRUE(decos[1]->IsSet()); + auto& decorations = v->decorations(); + ASSERT_EQ(decorations.size(), 2u); + ASSERT_TRUE(decorations[0]->IsBinding()); + ASSERT_TRUE(decorations[1]->IsSet()); } TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) { auto* p = parser("[[binding()]] var a : f32"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + auto decos = p->decoration_list(); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto e = p->global_variable_decl(decos.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); + + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: expected signed integer literal for binding decoration"); } TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) { auto* p = parser("var a : f32 = if (a) {}"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_variable_decl(decos.value); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:20: unable to parse const literal"); } TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) { auto* p = parser("var a : f32;"); - auto decorations = p->decoration_list(); - auto e = p->global_variable_decl(decorations); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + auto decos = p->decoration_list(); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + auto e = p->global_variable_decl(decos.value); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration"); } diff --git a/src/reader/wgsl/parser_impl_if_stmt_test.cc b/src/reader/wgsl/parser_impl_if_stmt_test.cc index 50c3827e23..8dea243046 100644 --- a/src/reader/wgsl/parser_impl_if_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_if_stmt_test.cc @@ -26,82 +26,98 @@ namespace { TEST_F(ParserImplTest, IfStmt) { auto* p = parser("if (a == 4) { a = b; c = d; }"); auto e = p->if_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsIf()); - ASSERT_NE(e->condition(), nullptr); - ASSERT_TRUE(e->condition()->IsBinary()); - EXPECT_EQ(e->body()->size(), 2u); - EXPECT_EQ(e->else_statements().size(), 0u); + ASSERT_TRUE(e.value->IsIf()); + ASSERT_NE(e.value->condition(), nullptr); + ASSERT_TRUE(e.value->condition()->IsBinary()); + EXPECT_EQ(e.value->body()->size(), 2u); + EXPECT_EQ(e.value->else_statements().size(), 0u); } TEST_F(ParserImplTest, IfStmt_WithElse) { auto* p = parser("if (a == 4) { a = b; c = d; } elseif(c) { d = 2; } else {}"); auto e = p->if_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsIf()); - ASSERT_NE(e->condition(), nullptr); - ASSERT_TRUE(e->condition()->IsBinary()); - EXPECT_EQ(e->body()->size(), 2u); + ASSERT_TRUE(e.value->IsIf()); + ASSERT_NE(e.value->condition(), nullptr); + ASSERT_TRUE(e.value->condition()->IsBinary()); + EXPECT_EQ(e.value->body()->size(), 2u); - ASSERT_EQ(e->else_statements().size(), 2u); - ASSERT_NE(e->else_statements()[0]->condition(), nullptr); - ASSERT_TRUE(e->else_statements()[0]->condition()->IsIdentifier()); - EXPECT_EQ(e->else_statements()[0]->body()->size(), 1u); + ASSERT_EQ(e.value->else_statements().size(), 2u); + ASSERT_NE(e.value->else_statements()[0]->condition(), nullptr); + ASSERT_TRUE(e.value->else_statements()[0]->condition()->IsIdentifier()); + EXPECT_EQ(e.value->else_statements()[0]->body()->size(), 1u); - ASSERT_EQ(e->else_statements()[1]->condition(), nullptr); - EXPECT_EQ(e->else_statements()[1]->body()->size(), 0u); + ASSERT_EQ(e.value->else_statements()[1]->condition(), nullptr); + EXPECT_EQ(e.value->else_statements()[1]->body()->size(), 0u); } TEST_F(ParserImplTest, IfStmt_InvalidCondition) { auto* p = parser("if (a = 3) {}"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: expected ')'"); } TEST_F(ParserImplTest, IfStmt_MissingCondition) { auto* p = parser("if {}"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:4: expected '('"); } TEST_F(ParserImplTest, IfStmt_InvalidBody) { auto* p = parser("if (a) { fn main() -> void {}}"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected '}'"); } TEST_F(ParserImplTest, IfStmt_MissingBody) { auto* p = parser("if (a)"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:7: expected '{'"); } TEST_F(ParserImplTest, IfStmt_InvalidElseif) { auto* p = parser("if (a) {} elseif (a) { fn main() -> a{}}"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:24: expected '}'"); } TEST_F(ParserImplTest, IfStmt_InvalidElse) { auto* p = parser("if (a) {} else { fn main() -> a{}}"); auto e = p->if_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:18: expected '}'"); } diff --git a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc index e7451e77eb..073c2beac4 100644 --- a/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc +++ b/src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, InclusiveOrExpression_Parses) { auto* p = parser("a | true"); auto e = p->inclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kOr, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,24 +51,30 @@ TEST_F(ParserImplTest, InclusiveOrExpression_Parses) { TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) { auto* p = parser("if (a) {} | true"); auto e = p->inclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) { auto* p = parser("true | if (a) {}"); auto e = p->inclusive_or_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression"); } TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->inclusive_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc index 03b102bcd2..c11de2abcf 100644 --- a/src/reader/wgsl/parser_impl_logical_and_expression_test.cc +++ b/src/reader/wgsl/parser_impl_logical_and_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, LogicalAndExpression_Parses) { auto* p = parser("a && true"); auto e = p->logical_and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,24 +51,30 @@ TEST_F(ParserImplTest, LogicalAndExpression_Parses) { TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) { auto* p = parser("if (a) {} && true"); auto e = p->logical_and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) { auto* p = parser("true && if (a) {}"); auto e = p->logical_and_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression"); } TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->logical_and_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc index 444e871471..3925590817 100644 --- a/src/reader/wgsl/parser_impl_logical_or_expression_test.cc +++ b/src/reader/wgsl/parser_impl_logical_or_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, LogicalOrExpression_Parses) { auto* p = parser("a || true"); auto e = p->logical_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,24 +51,30 @@ TEST_F(ParserImplTest, LogicalOrExpression_Parses) { TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) { auto* p = parser("if (a) {} || true"); auto e = p->logical_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) { auto* p = parser("true || if (a) {}"); auto e = p->logical_or_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression"); } TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->logical_or_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_loop_stmt_test.cc b/src/reader/wgsl/parser_impl_loop_stmt_test.cc index 41aea2fb9d..6b4aa2fe20 100644 --- a/src/reader/wgsl/parser_impl_loop_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_loop_stmt_test.cc @@ -24,76 +24,92 @@ namespace { TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) { auto* p = parser("loop { discard; }"); auto e = p->loop_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_EQ(e->body()->size(), 1u); - EXPECT_TRUE(e->body()->get(0)->IsDiscard()); + ASSERT_EQ(e.value->body()->size(), 1u); + EXPECT_TRUE(e.value->body()->get(0)->IsDiscard()); - EXPECT_EQ(e->continuing()->size(), 0u); + EXPECT_EQ(e.value->continuing()->size(), 0u); } TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) { auto* p = parser("loop { discard; continuing { discard; }}"); auto e = p->loop_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_EQ(e->body()->size(), 1u); - EXPECT_TRUE(e->body()->get(0)->IsDiscard()); + ASSERT_EQ(e.value->body()->size(), 1u); + EXPECT_TRUE(e.value->body()->get(0)->IsDiscard()); - EXPECT_EQ(e->continuing()->size(), 1u); - EXPECT_TRUE(e->continuing()->get(0)->IsDiscard()); + EXPECT_EQ(e.value->continuing()->size(), 1u); + EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard()); } TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) { auto* p = parser("loop { }"); auto e = p->loop_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_EQ(e->body()->size(), 0u); - ASSERT_EQ(e->continuing()->size(), 0u); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_EQ(e.value->body()->size(), 0u); + ASSERT_EQ(e.value->continuing()->size(), 0u); } TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) { auto* p = parser("loop { continuing { discard; }}"); auto e = p->loop_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_EQ(e->body()->size(), 0u); - ASSERT_EQ(e->continuing()->size(), 1u); - EXPECT_TRUE(e->continuing()->get(0)->IsDiscard()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_EQ(e.value->body()->size(), 0u); + ASSERT_EQ(e.value->continuing()->size(), 1u); + EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard()); } TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) { auto* p = parser("loop discard; }"); auto e = p->loop_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:6: expected '{' for loop"); } TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) { auto* p = parser("loop { discard; "); auto e = p->loop_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:17: expected '}' for loop"); } TEST_F(ParserImplTest, LoopStmt_InvalidStatements) { auto* p = parser("loop { discard }"); auto e = p->loop_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement"); } TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) { auto* p = parser("loop { continuing { discard }}"); auto e = p->loop_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement"); } diff --git a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc index 3c6c1faaa2..d3110202d6 100644 --- a/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc +++ b/src/reader/wgsl/parser_impl_multiplicative_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) { auto* p = parser("a * true"); auto e = p->multiplicative_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,11 +51,13 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) { auto* p = parser("a / true"); auto e = p->multiplicative_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kDivide, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -70,11 +74,13 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) { auto* p = parser("a % true"); auto e = p->multiplicative_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kModulo, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -91,24 +97,30 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) { TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) { auto* p = parser("if (a) {} * true"); auto e = p->multiplicative_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) { auto* p = parser("true * if (a) {}"); auto e = p->multiplicative_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression"); } TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->multiplicative_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_postfix_expression_test.cc b/src/reader/wgsl/parser_impl_postfix_expression_test.cc index 31ca9c6be6..952103b51f 100644 --- a/src/reader/wgsl/parser_impl_postfix_expression_test.cc +++ b/src/reader/wgsl/parser_impl_postfix_expression_test.cc @@ -31,11 +31,13 @@ namespace { TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) { auto* p = parser("a[1]"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsArrayAccessor()); - auto* ary = e->AsArrayAccessor(); + ASSERT_TRUE(e.value->IsArrayAccessor()); + auto* ary = e.value->AsArrayAccessor(); ASSERT_TRUE(ary->array()->IsIdentifier()); auto* ident = ary->array()->AsIdentifier(); @@ -51,11 +53,13 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) { auto* p = parser("a[1 + b / 4]"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsArrayAccessor()); - auto* ary = e->AsArrayAccessor(); + ASSERT_TRUE(e.value->IsArrayAccessor()); + auto* ary = e.value->AsArrayAccessor(); ASSERT_TRUE(ary->array()->IsIdentifier()); auto* ident = ary->array()->AsIdentifier(); @@ -67,35 +71,43 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) { auto* p = parser("a[]"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []"); } TEST_F(ParserImplTest, PostfixExpression_Array_MissingRightBrace) { auto* p = parser("a[1"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); - EXPECT_EQ(p->error(), "1:4: missing ] for array accessor"); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:4: expected ']' for array accessor"); } TEST_F(ParserImplTest, PostfixExpression_Array_InvalidIndex) { auto* p = parser("a[if(a() {})]"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []"); } TEST_F(ParserImplTest, PostfixExpression_Call_Empty) { auto* p = parser("a()"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsCall()); - auto* c = e->AsCall(); + ASSERT_TRUE(e.value->IsCall()); + auto* c = e.value->AsCall(); ASSERT_TRUE(c->func()->IsIdentifier()); auto* func = c->func()->AsIdentifier(); @@ -107,11 +119,13 @@ TEST_F(ParserImplTest, PostfixExpression_Call_Empty) { TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) { auto* p = parser("test(1, b, 2 + 3 / b)"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsCall()); - auto* c = e->AsCall(); + ASSERT_TRUE(e.value->IsCall()); + auto* c = e.value->AsCall(); ASSERT_TRUE(c->func()->IsIdentifier()); auto* func = c->func()->AsIdentifier(); @@ -126,35 +140,43 @@ TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) { TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) { auto* p = parser("a(if(a) {})"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: unable to parse argument expression"); } TEST_F(ParserImplTest, PostfixExpression_Call_HangingComma) { auto* p = parser("a(b, )"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:6: unable to parse argument expression after comma"); } TEST_F(ParserImplTest, PostfixExpression_Call_MissingRightParen) { auto* p = parser("a("); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: expected ')' for call expression"); } TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) { auto* p = parser("a.b"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsMemberAccessor()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsMemberAccessor()); - auto* m = e->AsMemberAccessor(); + auto* m = e.value->AsMemberAccessor(); ASSERT_TRUE(m->structure()->IsIdentifier()); EXPECT_EQ(m->structure()->AsIdentifier()->name(), "a"); @@ -165,25 +187,31 @@ TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) { TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) { auto* p = parser("a.if"); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor"); } TEST_F(ParserImplTest, PostfixExpression_MemberAccessor_MissingIdent) { auto* p = parser("a."); auto e = p->postfix_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor"); } TEST_F(ParserImplTest, PostfixExpression_NonMatch_returnLHS) { auto* p = parser("a b"); auto e = p->postfix_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc index 41c218c582..3ef055daf9 100644 --- a/src/reader/wgsl/parser_impl_primary_expression_test.cc +++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc @@ -35,21 +35,25 @@ namespace { TEST_F(ParserImplTest, PrimaryExpression_Ident) { auto* p = parser("a"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); - auto* ident = e->AsIdentifier(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); + auto* ident = e.value->AsIdentifier(); EXPECT_EQ(ident->name(), "a"); } TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) { auto* p = parser("vec4(1, 2, 3, 4))"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); - auto* ty = e->AsConstructor()->AsTypeConstructor(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor()); + auto* ty = e.value->AsConstructor()->AsTypeConstructor(); ASSERT_EQ(ty->values().size(), 4u); const auto& val = ty->values(); @@ -81,11 +85,13 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) { auto* p = parser("vec4()"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); - auto* ty = e->AsConstructor()->AsTypeConstructor(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor()); + auto* ty = e.value->AsConstructor()->AsTypeConstructor(); ASSERT_EQ(ty->values().size(), 0u); } @@ -93,43 +99,53 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) { auto* p = parser("vec4(2., 3., 4., 5.)"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:6: unable to determine subtype for vector"); } TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) { auto* p = parser("vec4 2., 3., 4., 5.)"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor"); } TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) { auto* p = parser("vec4(2., 3., 4., 5."); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:25: expected ')' for type constructor"); } TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) { auto* p = parser("i32(if(a) {})"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:5: unable to parse argument expression"); } TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) { auto* p = parser("true"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor()); - auto* init = e->AsConstructor()->AsScalarConstructor(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor()); + auto* init = e.value->AsConstructor()->AsScalarConstructor(); ASSERT_TRUE(init->literal()->IsBool()); EXPECT_TRUE(init->literal()->AsBool()->IsTrue()); } @@ -137,32 +153,40 @@ TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) { auto* p = parser("(a == b)"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsBinary()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsBinary()); } TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) { auto* p = parser("(a == b"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:8: expected ')'"); } TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) { auto* p = parser("()"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:2: unable to parse expression"); } TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) { auto* p = parser("(if (a) {})"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:2: unable to parse expression"); } @@ -171,12 +195,14 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) { auto* p = parser("f32(1)"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor()); - auto* c = e->AsConstructor()->AsTypeConstructor(); + auto* c = e.value->AsConstructor()->AsTypeConstructor(); ASSERT_EQ(c->type(), f32_type); ASSERT_EQ(c->values().size(), 1u); @@ -189,11 +215,13 @@ TEST_F(ParserImplTest, PrimaryExpression_Bitcast) { auto* p = parser("bitcast(1)"); auto e = p->primary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsBitcast()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsBitcast()); - auto* c = e->AsBitcast(); + auto* c = e.value->AsBitcast(); ASSERT_EQ(c->type(), f32_type); ASSERT_TRUE(c->expr()->IsConstructor()); @@ -203,56 +231,70 @@ TEST_F(ParserImplTest, PrimaryExpression_Bitcast) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingGreaterThan) { auto* p = parser("bitcastprimary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); - EXPECT_EQ(p->error(), "1:12: missing > for bitcast expression"); + EXPECT_EQ(p->error(), "1:12: expected '>' for bitcast expression"); } TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingType) { auto* p = parser("bitcast<>(1)"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:9: missing type for bitcast expression"); } TEST_F(ParserImplTest, PrimaryExpression_Bitcast_InvalidType) { auto* p = parser("bitcast(1)"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'"); } TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingLeftParen) { auto* p = parser("bitcast1)"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:13: expected '('"); } TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingRightParen) { auto* p = parser("bitcast(1"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:15: expected ')'"); } TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingExpression) { auto* p = parser("bitcast()"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:14: unable to parse expression"); } TEST_F(ParserImplTest, PrimaryExpression_bitcast_InvalidExpression) { auto* p = parser("bitcast(if (a) {})"); auto e = p->primary_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:14: unable to parse expression"); } diff --git a/src/reader/wgsl/parser_impl_relational_expression_test.cc b/src/reader/wgsl/parser_impl_relational_expression_test.cc index 982f496398..be712b961d 100644 --- a/src/reader/wgsl/parser_impl_relational_expression_test.cc +++ b/src/reader/wgsl/parser_impl_relational_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { auto* p = parser("a < true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,11 +51,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { auto* p = parser("a > true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -70,11 +74,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { auto* p = parser("a <= true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -91,11 +97,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { auto* p = parser("a >= true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -112,24 +120,28 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { auto* p = parser("if (a) {} < true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { auto* p = parser("true < if (a) {}"); auto e = p->relational_expression(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression"); } TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->relational_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc b/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc index c0d689586f..9406bdcd67 100644 --- a/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc +++ b/src/reader/wgsl/parser_impl_sampled_texture_type_test.cc @@ -25,105 +25,134 @@ namespace { TEST_F(ParserImplTest, SampledTextureType_Invalid) { auto* p = parser("1234"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::kNone); + EXPECT_FALSE(t.matched); + EXPECT_FALSE(t.errored); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_1d_Old) { auto* p = parser("texture_sampled_1d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k1d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k1d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_1dArray_Old) { auto* p = parser("texture_sampled_1d_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k1dArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k1dArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_2d_Old) { auto* p = parser("texture_sampled_2d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k2d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_2dArray_Old) { auto* p = parser("texture_sampled_2d_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2dArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k2dArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_3d_Old) { auto* p = parser("texture_sampled_3d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k3d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k3d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_Cube_Old) { auto* p = parser("texture_sampled_cube"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::kCube); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::kCube); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_kCubeArray_Old) { auto* p = parser("texture_sampled_cube_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::kCubeArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::kCubeArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_1d) { auto* p = parser("texture_1d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k1d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k1d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_1dArray) { auto* p = parser("texture_1d_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k1dArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k1dArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_2d) { auto* p = parser("texture_2d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k2d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_2dArray) { auto* p = parser("texture_2d_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k2dArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k2dArray); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_3d) { auto* p = parser("texture_3d"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::k3d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::k3d); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_Cube) { auto* p = parser("texture_cube"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::kCube); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::kCube); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SampledTextureType_kCubeArray) { auto* p = parser("texture_cube_array"); auto t = p->sampled_texture_type(); - EXPECT_EQ(t, ast::type::TextureDimension::kCubeArray); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::TextureDimension::kCubeArray); EXPECT_FALSE(p->has_error()); } diff --git a/src/reader/wgsl/parser_impl_sampler_type_test.cc b/src/reader/wgsl/parser_impl_sampler_type_test.cc index db71a2067b..caf313ca67 100644 --- a/src/reader/wgsl/parser_impl_sampler_type_test.cc +++ b/src/reader/wgsl/parser_impl_sampler_type_test.cc @@ -24,26 +24,32 @@ namespace { TEST_F(ParserImplTest, SamplerType_Invalid) { auto* p = parser("1234"); - auto* t = p->sampler_type(); - EXPECT_EQ(t, nullptr); + auto t = p->sampler_type(); + EXPECT_FALSE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, nullptr); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SamplerType_Sampler) { auto* p = parser("sampler"); - auto* t = p->sampler_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsSampler()); - EXPECT_FALSE(t->AsSampler()->IsComparison()); + auto t = p->sampler_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsSampler()); + EXPECT_FALSE(t.value->AsSampler()->IsComparison()); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, SamplerType_ComparisonSampler) { auto* p = parser("sampler_comparison"); - auto* t = p->sampler_type(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsSampler()); - EXPECT_TRUE(t->AsSampler()->IsComparison()); + auto t = p->sampler_type(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsSampler()); + EXPECT_TRUE(t.value->AsSampler()->IsComparison()); EXPECT_FALSE(p->has_error()); } diff --git a/src/reader/wgsl/parser_impl_shift_expression_test.cc b/src/reader/wgsl/parser_impl_shift_expression_test.cc index 2acf06b075..2122bfd466 100644 --- a/src/reader/wgsl/parser_impl_shift_expression_test.cc +++ b/src/reader/wgsl/parser_impl_shift_expression_test.cc @@ -28,11 +28,13 @@ namespace { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { auto* p = parser("a << true"); auto e = p->shift_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -49,11 +51,13 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { auto* p = parser("a >> true"); auto e = p->shift_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsBinary()); - auto* rel = e->AsBinary(); + ASSERT_TRUE(e.value->IsBinary()); + auto* rel = e.value->AsBinary(); EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op()); ASSERT_TRUE(rel->lhs()->IsIdentifier()); @@ -70,24 +74,30 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) { auto* p = parser("if (a) {} << true"); auto e = p->shift_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); } TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { auto* p = parser("true << if (a) {}"); auto e = p->shift_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression"); } TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { auto* p = parser("a true"); auto e = p->shift_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIdentifier()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsIdentifier()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_statement_test.cc b/src/reader/wgsl/parser_impl_statement_test.cc index 2cebedfd9f..57c5cb17b0 100644 --- a/src/reader/wgsl/parser_impl_statement_test.cc +++ b/src/reader/wgsl/parser_impl_statement_test.cc @@ -27,25 +27,25 @@ TEST_F(ParserImplTest, Statement) { auto* p = parser("return;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - EXPECT_TRUE(e->IsReturn()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsReturn()); } TEST_F(ParserImplTest, Statement_Semicolon) { auto* p = parser(";"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e, nullptr); } TEST_F(ParserImplTest, Statement_Return_NoValue) { auto* p = parser("return;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - - ASSERT_TRUE(e->IsReturn()); - auto* ret = e->AsReturn(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsReturn()); + auto* ret = e.value->AsReturn(); ASSERT_EQ(ret->value(), nullptr); } @@ -53,10 +53,11 @@ TEST_F(ParserImplTest, Statement_Return_Value) { auto* p = parser("return a + b * (.1 - .2);"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsReturn()); - auto* ret = e->AsReturn(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsReturn()); + auto* ret = e.value->AsReturn(); ASSERT_NE(ret->value(), nullptr); EXPECT_TRUE(ret->value()->IsBinary()); } @@ -64,16 +65,20 @@ TEST_F(ParserImplTest, Statement_Return_Value) { TEST_F(ParserImplTest, Statement_Return_MissingSemi) { auto* p = parser("return"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:7: expected ';' for return statement"); } TEST_F(ParserImplTest, Statement_Return_Invalid) { auto* p = parser("return if(a) {};"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:8: expected ';' for return statement"); } @@ -81,15 +86,18 @@ TEST_F(ParserImplTest, Statement_If) { auto* p = parser("if (a) {}"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsIf()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsIf()); } TEST_F(ParserImplTest, Statement_If_Invalid) { auto* p = parser("if (a) { fn main() -> {}}"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:10: expected '}'"); } @@ -97,23 +105,28 @@ TEST_F(ParserImplTest, Statement_Variable) { auto* p = parser("var a : i32 = 1;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsVariableDecl()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsVariableDecl()); } TEST_F(ParserImplTest, Statement_Variable_Invalid) { auto* p = parser("var a : i32 =;"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration"); } TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) { auto* p = parser("var a : i32"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration"); } @@ -121,15 +134,18 @@ TEST_F(ParserImplTest, Statement_Switch) { auto* p = parser("switch (a) {}"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsSwitch()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsSwitch()); } TEST_F(ParserImplTest, Statement_Switch_Invalid) { auto* p = parser("switch (a) { case: {}}"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:18: unable to parse case selectors"); } @@ -137,15 +153,18 @@ TEST_F(ParserImplTest, Statement_Loop) { auto* p = parser("loop {}"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsLoop()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsLoop()); } TEST_F(ParserImplTest, Statement_Loop_Invalid) { auto* p = parser("loop discard; }"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected '{' for loop"); } @@ -153,23 +172,28 @@ TEST_F(ParserImplTest, Statement_Assignment) { auto* p = parser("a = b;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - EXPECT_TRUE(e->IsAssign()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsAssign()); } TEST_F(ParserImplTest, Statement_Assignment_Invalid) { auto* p = parser("a = if(b) {};"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment"); } TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) { auto* p = parser("a = b"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement"); } @@ -177,15 +201,18 @@ TEST_F(ParserImplTest, Statement_Break) { auto* p = parser("break;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - EXPECT_TRUE(e->IsBreak()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsBreak()); } TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) { auto* p = parser("break"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected ';' for break statement"); } @@ -193,15 +220,18 @@ TEST_F(ParserImplTest, Statement_Continue) { auto* p = parser("continue;"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - EXPECT_TRUE(e->IsContinue()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsContinue()); } TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) { auto* p = parser("continue"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement"); } @@ -209,15 +239,19 @@ 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()); + ASSERT_NE(e.value, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->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_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement"); } @@ -225,16 +259,19 @@ TEST_F(ParserImplTest, Statement_Body) { auto* p = parser("{ var i: i32; }"); auto e = p->statement(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsBlock()); - EXPECT_TRUE(e->AsBlock()->get(0)->IsVariableDecl()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsBlock()); + EXPECT_TRUE(e.value->AsBlock()->get(0)->IsVariableDecl()); } TEST_F(ParserImplTest, Statement_Body_Invalid) { auto* p = parser("{ fn main() -> {}}"); auto e = p->statement(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:3: expected '}'"); } diff --git a/src/reader/wgsl/parser_impl_storage_texture_type_test.cc b/src/reader/wgsl/parser_impl_storage_texture_type_test.cc index fd9ba94d86..2f6df88c96 100644 --- a/src/reader/wgsl/parser_impl_storage_texture_type_test.cc +++ b/src/reader/wgsl/parser_impl_storage_texture_type_test.cc @@ -25,168 +25,208 @@ namespace { TEST_F(ParserImplTest, StorageTextureType_Invalid) { auto* p = parser("abc"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::kNone); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_FALSE(t.matched); + EXPECT_FALSE(t.errored); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Readonly1d_Old) { auto* p = parser("texture_ro_1d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Readonly1dArray_Old) { auto* p = parser("texture_ro_1d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Readonly2d_Old) { auto* p = parser("texture_ro_2d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Readonly2dArray_Old) { auto* p = parser("texture_ro_2d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Readonly3d_Old) { auto* p = parser("texture_ro_3d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Writeonly1d_Old) { auto* p = parser("texture_wo_1d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Writeonly1dArray_Old) { auto* p = parser("texture_wo_1d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Writeonly2d_Old) { auto* p = parser("texture_wo_2d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Writeonly2dArray_Old) { auto* p = parser("texture_wo_2d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_Writeonly3d_Old) { auto* p = parser("texture_wo_3d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_ro_1d) { auto* p = parser("texture_storage_ro_1d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_ro_1dArray) { auto* p = parser("texture_storage_ro_1d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_ro_2d) { auto* p = parser("texture_storage_ro_2d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_ro_2dArray) { auto* p = parser("texture_storage_ro_2d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_ro_3d) { auto* p = parser("texture_storage_ro_3d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_wo_1d) { auto* p = parser("texture_storage_wo_1d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_wo_1dArray) { auto* p = parser("texture_storage_wo_1d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_wo_2d) { auto* p = parser("texture_storage_wo_2d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_wo_2dArray) { auto* p = parser("texture_storage_wo_2d_array"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, StorageTextureType_wo_3d) { auto* p = parser("texture_storage_wo_3d"); auto t = p->storage_texture_type(); - EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); - EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d); + EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly); EXPECT_FALSE(p->has_error()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_struct_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decl_test.cc index 78aafaad5f..81fac22f61 100644 --- a/src/reader/wgsl/parser_impl_struct_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decl_test.cc @@ -29,14 +29,19 @@ struct S { [[offset(4)]] b : f32; })"); 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"); - ASSERT_EQ(s->impl()->members().size(), 2u); - EXPECT_EQ(s->impl()->members()[0]->name(), "a"); - EXPECT_EQ(s->impl()->members()[1]->name(), "b"); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + ASSERT_EQ(decos.value.size(), 0u); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(s.errored); + EXPECT_TRUE(s.matched); + ASSERT_NE(s.value, nullptr); + ASSERT_EQ(s.value->name(), "S"); + ASSERT_EQ(s.value->impl()->members().size(), 2u); + EXPECT_EQ(s.value->impl()->members()[0]->name(), "a"); + EXPECT_EQ(s.value->impl()->members()[1]->name(), "b"); } TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) { @@ -46,16 +51,21 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) { b : f32; })"); 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"); - ASSERT_EQ(s->impl()->members().size(), 2u); - EXPECT_EQ(s->impl()->members()[0]->name(), "a"); - EXPECT_EQ(s->impl()->members()[1]->name(), "b"); - ASSERT_EQ(s->impl()->decorations().size(), 1u); - EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock()); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 1u); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(s.errored); + EXPECT_TRUE(s.matched); + ASSERT_NE(s.value, nullptr); + ASSERT_EQ(s.value->name(), "B"); + ASSERT_EQ(s.value->impl()->members().size(), 2u); + EXPECT_EQ(s.value->impl()->members()[0]->name(), "a"); + EXPECT_EQ(s.value->impl()->members()[1]->name(), "b"); + ASSERT_EQ(s.value->impl()->decorations().size(), 1u); + EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock()); } TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) { @@ -66,75 +76,115 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) { b : f32; })"); 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"); - ASSERT_EQ(s->impl()->members().size(), 2u); - EXPECT_EQ(s->impl()->members()[0]->name(), "a"); - EXPECT_EQ(s->impl()->members()[1]->name(), "b"); - ASSERT_EQ(s->impl()->decorations().size(), 2u); - EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock()); - EXPECT_TRUE(s->impl()->decorations()[1]->IsBlock()); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 2u); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(s.errored); + EXPECT_TRUE(s.matched); + ASSERT_NE(s.value, nullptr); + ASSERT_EQ(s.value->name(), "S"); + ASSERT_EQ(s.value->impl()->members().size(), 2u); + EXPECT_EQ(s.value->impl()->members()[0]->name(), "a"); + EXPECT_EQ(s.value->impl()->members()[1]->name(), "b"); + ASSERT_EQ(s.value->impl()->decorations().size(), 2u); + EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock()); + EXPECT_TRUE(s.value->impl()->decorations()[1]->IsBlock()); } TEST_F(ParserImplTest, StructDecl_EmptyMembers) { auto* p = parser("struct S {}"); 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); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + ASSERT_EQ(decos.value.size(), 0u); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(s.errored); + EXPECT_TRUE(s.matched); + ASSERT_NE(s.value, nullptr); + ASSERT_EQ(s.value->impl()->members().size(), 0u); } TEST_F(ParserImplTest, StructDecl_MissingIdent) { auto* p = parser("struct {}"); 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_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + ASSERT_EQ(decos.value.size(), 0u); + + auto s = p->struct_decl(decos.value); + EXPECT_TRUE(s.errored); + EXPECT_FALSE(s.matched); + EXPECT_EQ(s.value, nullptr); + + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration"); } TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) { auto* p = parser("struct S }"); 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_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + ASSERT_EQ(decos.value.size(), 0u); + + auto s = p->struct_decl(decos.value); + EXPECT_TRUE(s.errored); + EXPECT_FALSE(s.matched); + EXPECT_EQ(s.value, nullptr); + + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration"); } TEST_F(ParserImplTest, StructDecl_InvalidStructBody) { auto* p = parser("struct S { a : B; }"); 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_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + ASSERT_EQ(decos.value.size(), 0u); + + auto s = p->struct_decl(decos.value); + EXPECT_TRUE(s.errored); + EXPECT_FALSE(s.matched); + EXPECT_EQ(s.value, nullptr); + + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: unknown constructed type 'B'"); } TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) { auto* p = parser("[[block struct S { a : i32; }"); auto decos = p->decoration_list(); - auto s = p->struct_decl(decos); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(s, nullptr); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(s.errored); + EXPECT_FALSE(s.matched); + EXPECT_EQ(s.value, nullptr); + + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected ']]' for decoration list"); } TEST_F(ParserImplTest, StructDecl_MissingStruct) { auto* p = parser("[[block]] S {}"); 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_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 1u); + + auto s = p->struct_decl(decos.value); + EXPECT_FALSE(s.errored); + EXPECT_FALSE(s.matched); + EXPECT_EQ(s.value, nullptr); + + EXPECT_FALSE(p->has_error()); } } // 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 0549a2908c..f33356d446 100644 --- a/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decoration_decl_test.cc @@ -24,25 +24,31 @@ namespace { TEST_F(ParserImplTest, StructDecorationDecl_Parses) { auto* p = parser("[[block]]"); auto decos = p->decoration_list(); - ASSERT_FALSE(p->has_error()); - ASSERT_EQ(decos.size(), 1u); - auto struct_deco = ast::As(std::move(decos[0])); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 1u); + auto struct_deco = ast::As(std::move(decos.value[0])); EXPECT_TRUE(struct_deco->IsBlock()); } TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) { auto* p = parser("[[block"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); EXPECT_EQ(p->error(), "1:8: expected ']]' for decoration list"); } TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) { auto* p = parser("[[invalid]]"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - EXPECT_EQ(decos.size(), 0u); - EXPECT_TRUE(decos.empty()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_struct_decoration_test.cc b/src/reader/wgsl/parser_impl_struct_decoration_test.cc index 84c6e22a1d..f04658e35d 100644 --- a/src/reader/wgsl/parser_impl_struct_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_struct_decoration_test.cc @@ -40,8 +40,10 @@ TEST_P(StructDecorationTest, Parses) { auto deco = p->decoration(); ASSERT_FALSE(p->has_error()); - ASSERT_NE(deco, nullptr); - auto struct_deco = ast::As(std::move(deco)); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto struct_deco = ast::As(std::move(deco.value)); ASSERT_NE(struct_deco, nullptr); EXPECT_EQ(struct_deco->IsBlock(), params.is_block); } @@ -52,7 +54,9 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest, TEST_F(ParserImplTest, StructDecoration_NoMatch) { auto* p = parser("not-a-stage"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); + EXPECT_FALSE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_EQ(deco.value, nullptr); } } // 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 36cc93d237..df92f11a0d 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 @@ -25,40 +25,50 @@ namespace { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) { auto* p = parser(""); auto decos = p->decoration_list(); - ASSERT_FALSE(p->has_error()); - EXPECT_EQ(decos.size(), 0u); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(decos.value.size(), 0u); } TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) { auto* p = parser("[[]]"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - EXPECT_EQ(decos.size(), 0u); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(decos.value.size(), 0u); EXPECT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) { auto* p = parser("[[offset(4)]]"); auto decos = p->decoration_list(); - ASSERT_FALSE(p->has_error()); - ASSERT_EQ(decos.size(), 1u); - auto deco = ast::As(std::move(decos[0])); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 1u); + auto deco = ast::As(std::move(decos.value[0])); ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco->IsOffset()); } TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) { auto* p = parser("[[offset(nan)]]"); - p->decoration_list(); - ASSERT_TRUE(p->has_error()) << p->error(); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()) << p->error(); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for offset decoration"); } TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) { auto* p = parser("[[offset(4)"); - p->decoration_list(); - ASSERT_TRUE(p->has_error()) << p->error(); + auto decos = p->decoration_list(); + EXPECT_TRUE(p->has_error()) << p->error(); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); EXPECT_EQ(p->error(), "1:12: expected ']]' for decoration list"); } 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 ec257333a8..8872c8eac6 100644 --- a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc @@ -25,10 +25,13 @@ namespace { TEST_F(ParserImplTest, StructMemberDecoration_Offset) { auto* p = parser("offset(4)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); ASSERT_FALSE(p->has_error()); - auto member_deco = ast::As(std::move(deco)); + auto member_deco = + ast::As(std::move(deco.value)); ASSERT_NE(member_deco, nullptr); ASSERT_TRUE(member_deco->IsOffset()); @@ -39,24 +42,30 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) { auto* p = parser("offset 4)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected '(' for offset decoration"); } TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) { auto* p = parser("offset(4"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected ')' for offset decoration"); } TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { auto* p = parser("offset()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected signed integer literal for offset decoration"); } @@ -64,8 +73,10 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) { auto* p = parser("offset(nan)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected signed integer literal for offset decoration"); } diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc index 563ece6a87..b63ee50fcd 100644 --- a/src/reader/wgsl/parser_impl_struct_member_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_test.cc @@ -29,8 +29,11 @@ TEST_F(ParserImplTest, StructMember_Parses) { auto* p = parser("a : i32;"); auto decos = p->decoration_list(); - EXPECT_EQ(decos.size(), 0u); - auto m = p->expect_struct_member(decos); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_EQ(decos.value.size(), 0u); + + auto m = p->expect_struct_member(decos.value); ASSERT_FALSE(p->has_error()); ASSERT_FALSE(m.errored); ASSERT_NE(m.value, nullptr); @@ -50,8 +53,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { auto* p = parser("[[offset(2)]] a : i32;"); auto decos = p->decoration_list(); - EXPECT_EQ(decos.size(), 1u); - auto m = p->expect_struct_member(decos); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + EXPECT_EQ(decos.value.size(), 1u); + + auto m = p->expect_struct_member(decos.value); ASSERT_FALSE(p->has_error()); ASSERT_FALSE(m.errored); ASSERT_NE(m.value, nullptr); @@ -74,8 +80,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { auto* p = parser(R"([[offset(2)]] [[offset(4)]] a : i32;)"); auto decos = p->decoration_list(); - EXPECT_EQ(decos.size(), 2u); - auto m = p->expect_struct_member(decos); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + EXPECT_EQ(decos.value.size(), 2u); + + auto m = p->expect_struct_member(decos.value); ASSERT_FALSE(p->has_error()); ASSERT_FALSE(m.errored); ASSERT_NE(m.value, nullptr); @@ -97,7 +106,10 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) { auto* p = parser("[[offset(nan)]] a : i32;"); auto decos = p->decoration_list(); - auto m = p->expect_struct_member(decos); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto m = p->expect_struct_member(decos.value); ASSERT_TRUE(p->has_error()); ASSERT_TRUE(m.errored); ASSERT_EQ(m.value, nullptr); @@ -108,7 +120,10 @@ TEST_F(ParserImplTest, StructMember_InvalidDecoration) { TEST_F(ParserImplTest, StructMember_InvalidVariable) { auto* p = parser("[[offset(4)]] a : B;"); auto decos = p->decoration_list(); - auto m = p->expect_struct_member(decos); + EXPECT_FALSE(decos.errored); + EXPECT_TRUE(decos.matched); + + auto m = p->expect_struct_member(decos.value); ASSERT_TRUE(p->has_error()); ASSERT_TRUE(m.errored); ASSERT_EQ(m.value, nullptr); @@ -118,7 +133,10 @@ TEST_F(ParserImplTest, StructMember_InvalidVariable) { TEST_F(ParserImplTest, StructMember_MissingSemicolon) { auto* p = parser("a : i32"); auto decos = p->decoration_list(); - auto m = p->expect_struct_member(decos); + EXPECT_FALSE(decos.errored); + EXPECT_FALSE(decos.matched); + + auto m = p->expect_struct_member(decos.value); ASSERT_TRUE(p->has_error()); ASSERT_TRUE(m.errored); ASSERT_EQ(m.value, nullptr); diff --git a/src/reader/wgsl/parser_impl_switch_body_test.cc b/src/reader/wgsl/parser_impl_switch_body_test.cc index 6b4078ced0..69af79f323 100644 --- a/src/reader/wgsl/parser_impl_switch_body_test.cc +++ b/src/reader/wgsl/parser_impl_switch_body_test.cc @@ -25,110 +25,136 @@ namespace { TEST_F(ParserImplTest, SwitchBody_Case) { auto* p = parser("case 1: { a = 4; }"); auto e = p->switch_body(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsCase()); - EXPECT_FALSE(e->IsDefault()); - ASSERT_EQ(e->body()->size(), 1u); - EXPECT_TRUE(e->body()->get(0)->IsAssign()); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsCase()); + EXPECT_FALSE(e.value->IsDefault()); + ASSERT_EQ(e.value->body()->size(), 1u); + EXPECT_TRUE(e.value->body()->get(0)->IsAssign()); } TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) { auto* p = parser("case a == 4: { a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: unable to parse case selectors"); } TEST_F(ParserImplTest, SwitchBody_Case_InvalidSelector_bool) { auto* p = parser("case true: { a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value"); } TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) { auto* p = parser("case: { a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:5: unable to parse case selectors"); } TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) { auto* p = parser("case 1 { a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:8: expected ':' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) { auto* p = parser("case 1: a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:9: expected '{' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) { auto* p = parser("case 1: { a = 4; "); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:18: expected '}' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) { auto* p = parser("case 1: { fn main() -> void {} }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:11: expected '}' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Default) { auto* p = parser("default: { a = 4; }"); auto e = p->switch_body(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsCase()); - EXPECT_TRUE(e->IsDefault()); - ASSERT_EQ(e->body()->size(), 1u); - EXPECT_TRUE(e->body()->get(0)->IsAssign()); + EXPECT_FALSE(p->has_error()) << p->error(); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsCase()); + EXPECT_TRUE(e.value->IsDefault()); + ASSERT_EQ(e.value->body()->size(), 1u); + EXPECT_TRUE(e.value->body()->get(0)->IsAssign()); } TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) { auto* p = parser("default { a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:9: expected ':' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) { auto* p = parser("default: a = 4; }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:10: expected '{' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) { auto* p = parser("default: { a = 4; "); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:19: expected '}' for case statement"); } TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) { auto* p = parser("default: { fn main() -> void {} }"); auto e = p->switch_body(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(e.errored); + EXPECT_FALSE(e.matched); + EXPECT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:12: expected '}' for case statement"); } diff --git a/src/reader/wgsl/parser_impl_switch_stmt_test.cc b/src/reader/wgsl/parser_impl_switch_stmt_test.cc index 15b6a5c78e..d0ea352979 100644 --- a/src/reader/wgsl/parser_impl_switch_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_switch_stmt_test.cc @@ -29,21 +29,25 @@ TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) { case 2: {} })"); auto e = p->switch_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsSwitch()); - ASSERT_EQ(e->body().size(), 2u); - EXPECT_FALSE(e->body()[0]->IsDefault()); - EXPECT_FALSE(e->body()[1]->IsDefault()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsSwitch()); + ASSERT_EQ(e.value->body().size(), 2u); + EXPECT_FALSE(e.value->body()[0]->IsDefault()); + EXPECT_FALSE(e.value->body()[1]->IsDefault()); } TEST_F(ParserImplTest, SwitchStmt_Empty) { auto* p = parser("switch(a) { }"); auto e = p->switch_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsSwitch()); - ASSERT_EQ(e->body().size(), 0u); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsSwitch()); + ASSERT_EQ(e.value->body().size(), 0u); } TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) { @@ -53,45 +57,55 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) { case 2: {} })"); auto e = p->switch_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsSwitch()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsSwitch()); - ASSERT_EQ(e->body().size(), 3u); - ASSERT_FALSE(e->body()[0]->IsDefault()); - ASSERT_TRUE(e->body()[1]->IsDefault()); - ASSERT_FALSE(e->body()[2]->IsDefault()); + ASSERT_EQ(e.value->body().size(), 3u); + ASSERT_FALSE(e.value->body()[0]->IsDefault()); + ASSERT_TRUE(e.value->body()[1]->IsDefault()); + ASSERT_FALSE(e.value->body()[2]->IsDefault()); } TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) { auto* p = parser("switch(a=b) {}"); auto e = p->switch_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected ')'"); } TEST_F(ParserImplTest, SwitchStmt_MissingExpression) { auto* p = parser("switch {}"); auto e = p->switch_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:8: expected '('"); } TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) { auto* p = parser("switch(a) }"); auto e = p->switch_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: expected '{' for switch statement"); } TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) { auto* p = parser("switch(a) {"); auto e = p->switch_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:12: expected '}' for switch statement"); } @@ -100,8 +114,10 @@ TEST_F(ParserImplTest, SwitchStmt_InvalidBody) { case: {} })"); auto e = p->switch_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "2:7: unable to parse case selectors"); } 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 0e82af06dd..b040fadcd6 100644 --- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc +++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc @@ -26,325 +26,395 @@ namespace { TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) { auto* p = parser("1234"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_FALSE(t.errored); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) { auto* p = parser("sampler"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsSampler()); - ASSERT_FALSE(t->AsSampler()->IsComparison()); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsSampler()); + ASSERT_FALSE(t.value->AsSampler()->IsComparison()); } TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) { auto* p = parser("sampler_comparison"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsSampler()); - ASSERT_TRUE(t->AsSampler()->IsComparison()); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsSampler()); + ASSERT_TRUE(t.value->AsSampler()->IsComparison()); } TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) { auto* p = parser("texture_depth_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsDepth()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsDepth()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32_Old) { auto* p = parser("texture_sampled_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32_Old) { auto* p = parser("texture_sampled_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32_Old) { auto* p = parser("texture_sampled_3d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid_Old) { auto* p = parser("texture_sampled_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:20: unknown constructed type 'abc'"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType_Old) { auto* p = parser("texture_sampled_1d<>"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:20: invalid subtype for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan_Old) { auto* p = parser("texture_sampled_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:19: expected '<' for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan_Old) { auto* p = parser("texture_sampled_1dtexture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:23: expected '>' for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) { auto* p = parser("texture_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) { auto* p = parser("texture_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) { auto* p = parser("texture_3d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) { auto* p = parser("texture_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:12: unknown constructed type 'abc'"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) { auto* p = parser("texture_1d<>"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:12: invalid subtype for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) { auto* p = parser("texture_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:11: expected '<' for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) { auto* p = parser("texture_1dtexture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:15: expected '>' for sampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) { auto* p = parser("texture_multisampled_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsMultisampled()); - ASSERT_TRUE(t->AsTexture()->AsMultisampled()->type()->IsI32()); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsMultisampled()); + ASSERT_TRUE(t.value->AsTexture()->AsMultisampled()->type()->IsI32()); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) { auto* p = parser("texture_multisampled_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:25: unknown constructed type 'abc'"); } TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) { auto* p = parser("texture_multisampled_2d<>"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_TRUE(p->has_error()); - EXPECT_EQ(t, nullptr); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:25: invalid subtype for multisampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingLessThan) { auto* p = parser("texture_multisampled_2d"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) { auto* p = parser("texture_multisampled_2dtexture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:28: expected '>' for multisampled texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm_Old) { auto* p = parser("texture_ro_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsStorage()); - EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsStorage()); + EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(), ast::type::ImageFormat::kR8Unorm); - EXPECT_EQ(t->AsTexture()->AsStorage()->access(), + EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(), ast::AccessControl::kReadOnly); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float_Old) { auto* p = parser("texture_wo_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsStorage()); - EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsStorage()); + EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(), ast::type::ImageFormat::kR16Float); - EXPECT_EQ(t->AsTexture()->AsStorage()->access(), + EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(), ast::AccessControl::kWriteOnly); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType_Old) { auto* p = parser("texture_ro_1d"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType_Old) { auto* p = parser("texture_wo_1d<>"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan_Old) { auto* p = parser("texture_ro_1d"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:14: expected '<' for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan_Old) { auto* p = parser("texture_wo_1dtexture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:22: expected '>' for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) { auto* p = parser("texture_storage_ro_1d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsStorage()); - EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsStorage()); + EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(), ast::type::ImageFormat::kR8Unorm); - EXPECT_EQ(t->AsTexture()->AsStorage()->access(), + EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(), ast::AccessControl::kReadOnly); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) { auto* p = parser("texture_storage_wo_2d"); - auto* t = p->texture_sampler_types(); + auto t = p->texture_sampler_types(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsStorage()); - EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsStorage()); + EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(), ast::type::ImageFormat::kR16Float); - EXPECT_EQ(t->AsTexture()->AsStorage()->access(), + EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(), ast::AccessControl::kWriteOnly); - EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); + EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) { auto* p = parser("texture_storage_ro_1d"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) { auto* p = parser("texture_storage_ro_1d<>"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) { auto* p = parser("texture_storage_ro_1d"); - auto* t = p->texture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:22: expected '<' for storage texture type"); } TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) { auto* p = parser("texture_storage_ro_1dtexture_sampler_types(); - EXPECT_EQ(t, nullptr); + auto t = p->texture_sampler_types(); + EXPECT_EQ(t.value, nullptr); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(t.errored); EXPECT_EQ(p->error(), "1:30: expected '>' for storage texture type"); } diff --git a/src/reader/wgsl/parser_impl_type_alias_test.cc b/src/reader/wgsl/parser_impl_type_alias_test.cc index c580729076..df97a4cca1 100644 --- a/src/reader/wgsl/parser_impl_type_alias_test.cc +++ b/src/reader/wgsl/parser_impl_type_alias_test.cc @@ -30,11 +30,13 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) { auto* i32 = tm()->Get(std::make_unique()); auto* p = parser("type a = i32"); - auto* t = p->type_alias(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsAlias()); - auto* alias = t->AsAlias(); + auto t = p->type_alias(); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(t.errored); + EXPECT_TRUE(t.matched); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsAlias()); + auto* alias = t.value->AsAlias(); ASSERT_TRUE(alias->type()->IsI32()); ASSERT_EQ(alias->type(), i32); } @@ -45,11 +47,13 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) { auto* p = parser("type a = B"); p->register_constructed("B", &str); - auto* t = p->type_alias(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(t, nullptr); - ASSERT_TRUE(t->IsAlias()); - auto* alias = t->AsAlias(); + auto t = p->type_alias(); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(t.errored); + EXPECT_TRUE(t.matched); + ASSERT_NE(t.value, nullptr); + ASSERT_TRUE(t.value->IsAlias()); + auto* alias = t.value->AsAlias(); EXPECT_EQ(alias->name(), "a"); ASSERT_TRUE(alias->type()->IsStruct()); @@ -59,33 +63,41 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) { TEST_F(ParserImplTest, TypeDecl_MissingIdent) { auto* p = parser("type = i32"); - auto* t = p->type_alias(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(t, nullptr); + auto t = p->type_alias(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(t.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected identifier for type alias"); } TEST_F(ParserImplTest, TypeDecl_InvalidIdent) { auto* p = parser("type 123 = i32"); - auto* t = p->type_alias(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(t, nullptr); + auto t = p->type_alias(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(t.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected identifier for type alias"); } TEST_F(ParserImplTest, TypeDecl_MissingEqual) { auto* p = parser("type a i32"); - auto* t = p->type_alias(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(t, nullptr); + auto t = p->type_alias(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(t.value, nullptr); EXPECT_EQ(p->error(), "1:8: expected '=' for type alias"); } TEST_F(ParserImplTest, TypeDecl_InvalidType) { auto* p = parser("type a = B"); - auto* t = p->type_alias(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(t, nullptr); + auto t = p->type_alias(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(t.value, nullptr); EXPECT_EQ(p->error(), "1:10: unknown constructed type 'B'"); } diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc index 20e6b2f730..f0cc10df52 100644 --- a/src/reader/wgsl/parser_impl_type_decl_test.cc +++ b/src/reader/wgsl/parser_impl_type_decl_test.cc @@ -37,8 +37,10 @@ namespace { TEST_F(ParserImplTest, TypeDecl_Invalid) { auto* p = parser("1234"); - auto* t = p->type_decl(); - EXPECT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_EQ(t.errored, false); + EXPECT_EQ(t.matched, false); + EXPECT_EQ(t.value, nullptr); EXPECT_FALSE(p->has_error()); } @@ -52,12 +54,14 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) { p->register_constructed("A", alias_type); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, alias_type); - ASSERT_TRUE(t->IsAlias()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, alias_type); + ASSERT_TRUE(t.value->IsAlias()); - auto* alias = t->AsAlias(); + auto* alias = t.value->AsAlias(); EXPECT_EQ(alias->name(), "A"); EXPECT_EQ(alias->type(), int_type); } @@ -65,8 +69,10 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) { TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) { auto* p = parser("B"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:1: unknown constructed type 'B'"); } @@ -76,10 +82,12 @@ TEST_F(ParserImplTest, TypeDecl_Bool) { auto* bool_type = tm()->Get(std::make_unique()); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, bool_type); - ASSERT_TRUE(t->IsBool()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, bool_type); + ASSERT_TRUE(t.value->IsBool()); } TEST_F(ParserImplTest, TypeDecl_F32) { @@ -87,10 +95,12 @@ TEST_F(ParserImplTest, TypeDecl_F32) { auto* float_type = tm()->Get(std::make_unique()); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, float_type); - ASSERT_TRUE(t->IsF32()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, float_type); + ASSERT_TRUE(t.value->IsF32()); } TEST_F(ParserImplTest, TypeDecl_I32) { @@ -98,10 +108,12 @@ TEST_F(ParserImplTest, TypeDecl_I32) { auto* int_type = tm()->Get(std::make_unique()); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, int_type); - ASSERT_TRUE(t->IsI32()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, int_type); + ASSERT_TRUE(t.value->IsI32()); } TEST_F(ParserImplTest, TypeDecl_U32) { @@ -109,10 +121,12 @@ TEST_F(ParserImplTest, TypeDecl_U32) { auto* uint_type = tm()->Get(std::make_unique()); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, uint_type); - ASSERT_TRUE(t->IsU32()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, uint_type); + ASSERT_TRUE(t.value->IsU32()); } struct VecData { @@ -129,11 +143,13 @@ class VecTest : public ParserImplTestWithParam {}; TEST_P(VecTest, Parse) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - EXPECT_TRUE(t->IsVector()); - EXPECT_EQ(t->AsVector()->size(), params.count); + EXPECT_TRUE(t.value->IsVector()); + EXPECT_EQ(t.value->AsVector()->size(), params.count); } INSTANTIATE_TEST_SUITE_P(ParserImplTest, VecTest, @@ -146,8 +162,10 @@ class VecMissingGreaterThanTest : public ParserImplTestWithParam {}; TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:9: expected '>' for vector"); } @@ -162,8 +180,10 @@ class VecMissingLessThanTest : public ParserImplTestWithParam {}; TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:5: expected '<' for vector"); } @@ -178,8 +198,10 @@ class VecBadType : public ParserImplTestWithParam {}; TEST_P(VecBadType, Handles_Unknown_Type) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:6: unknown constructed type 'unknown'"); } @@ -194,8 +216,10 @@ class VecMissingType : public ParserImplTestWithParam {}; TEST_P(VecMissingType, Handles_Missing_Type) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:6: unable to determine subtype for vector"); } @@ -207,24 +231,28 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest, TEST_F(ParserImplTest, TypeDecl_Ptr) { auto* p = parser("ptr"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsPointer()); + ASSERT_TRUE(t.value->IsPointer()); - auto* ptr = t->AsPointer(); + auto* ptr = t.value->AsPointer(); ASSERT_TRUE(ptr->type()->IsF32()); ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction); } TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) { auto* p = parser("ptr>"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsPointer()); + ASSERT_TRUE(t.value->IsPointer()); - auto* ptr = t->AsPointer(); + auto* ptr = t.value->AsPointer(); ASSERT_TRUE(ptr->type()->IsVector()); ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction); @@ -235,76 +263,94 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) { auto* p = parser("ptr private, f32>"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) { auto* p = parser("ptrtype_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) { auto* p = parser("ptr"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) { auto* p = parser("ptr<, f32>"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) { auto* p = parser("ptr<>"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) { auto* p = parser("ptr"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:14: missing type for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) { auto* p = parser("ptr"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); } TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) { auto* p = parser("ptr"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:15: unknown constructed type 'unknown'"); } TEST_F(ParserImplTest, TypeDecl_Array) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_FALSE(a->IsRuntimeArray()); ASSERT_EQ(a->size(), 5u); ASSERT_TRUE(a->type()->IsF32()); @@ -313,12 +359,14 @@ TEST_F(ParserImplTest, TypeDecl_Array) { TEST_F(ParserImplTest, TypeDecl_Array_Stride) { auto* p = parser("[[stride(16)]] array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_FALSE(a->IsRuntimeArray()); ASSERT_EQ(a->size(), 5u); ASSERT_TRUE(a->type()->IsF32()); @@ -328,12 +376,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride) { TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) { auto* p = parser("[[stride(16)]] array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->has_array_stride()); @@ -342,12 +392,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) { TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) { auto* p = parser("[[stride(16), stride(32)]] array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->type()->IsF32()); @@ -361,12 +413,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) { TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) { auto* p = parser("[[stride(16)]] [[stride(32)]] array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->type()->IsF32()); @@ -380,48 +434,60 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) { TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) { auto* p = parser("[[stride(16)]] f32"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: unexpected decorations"); } TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) { auto* p = parser("[[stride(16) array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:14: expected ']]' for decoration list"); } TEST_F(ParserImplTest, TypeDecl_Array_Decoration_UnknownDecoration) { auto* p = parser("[[unknown 16]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:3: expected decoration"); } TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) { auto* p = parser("[[stride 4)]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected '(' for stride decoration"); } TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) { auto* p = parser("[[stride(4]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: expected ')' for stride decoration"); } TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) { auto* p = parser("[[stride()]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for stride decoration"); @@ -429,8 +495,10 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) { auto* p = parser("[[stride(invalid)]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for stride decoration"); @@ -438,76 +506,94 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) { auto* p = parser("[[stride(-1)]] array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: stride decoration must be greater than 0"); } TEST_F(ParserImplTest, TypeDecl_Array_Runtime) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - ASSERT_TRUE(t->IsArray()); + ASSERT_TRUE(t.value->IsArray()); - auto* a = t->AsArray(); + auto* a = t.value->AsArray(); ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->type()->IsU32()); } TEST_F(ParserImplTest, TypeDecl_Array_BadType) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:7: unknown constructed type 'unknown'"); } TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:12: array size must be greater than 0"); } TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:12: array size must be greater than 0"); } TEST_F(ParserImplTest, TypeDecl_Array_BadSize) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size"); } TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) { auto* p = parser("array f32>"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration"); } TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) { auto* p = parser("arraytype_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration"); } TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) { auto* p = parser("array"); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration"); } @@ -527,11 +613,13 @@ class MatrixTest : public ParserImplTestWithParam {}; TEST_P(MatrixTest, Parse) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); ASSERT_FALSE(p->has_error()); - EXPECT_TRUE(t->IsMatrix()); - auto* mat = t->AsMatrix(); + EXPECT_TRUE(t.value->IsMatrix()); + auto* mat = t.value->AsMatrix(); EXPECT_EQ(mat->rows(), params.rows); EXPECT_EQ(mat->columns(), params.columns); } @@ -553,10 +641,12 @@ class MatrixMissingGreaterThanTest TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:11: missing > for matrix"); + ASSERT_EQ(p->error(), "1:11: expected '>' for matrix"); } INSTANTIATE_TEST_SUITE_P(ParserImplTest, MatrixMissingGreaterThanTest, @@ -575,10 +665,12 @@ class MatrixMissingLessThanTest : public ParserImplTestWithParam {}; TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:8: missing < for matrix"); + ASSERT_EQ(p->error(), "1:8: expected '<' for matrix"); } INSTANTIATE_TEST_SUITE_P(ParserImplTest, MatrixMissingLessThanTest, @@ -597,8 +689,10 @@ class MatrixBadType : public ParserImplTestWithParam {}; TEST_P(MatrixBadType, Handles_Unknown_Type) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:8: unknown constructed type 'unknown'"); } @@ -619,8 +713,10 @@ class MatrixMissingType : public ParserImplTestWithParam {}; TEST_P(MatrixMissingType, Handles_Missing_Type) { auto params = GetParam(); auto* p = parser(params.input); - auto* t = p->type_decl(); - ASSERT_EQ(t, nullptr); + auto t = p->type_decl(); + EXPECT_TRUE(t.errored); + EXPECT_FALSE(t.matched); + ASSERT_EQ(t.value, nullptr); ASSERT_TRUE(p->has_error()); ASSERT_EQ(p->error(), "1:8: unable to determine subtype for matrix"); } @@ -642,11 +738,13 @@ TEST_F(ParserImplTest, TypeDecl_Sampler) { auto* type = tm()->Get(std::make_unique( ast::type::SamplerKind::kSampler)); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, type); - ASSERT_TRUE(t->IsSampler()); - ASSERT_FALSE(t->AsSampler()->IsComparison()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, type); + ASSERT_TRUE(t.value->IsSampler()); + ASSERT_FALSE(t.value->AsSampler()->IsComparison()); } TEST_F(ParserImplTest, TypeDecl_Texture_Old) { @@ -656,12 +754,14 @@ TEST_F(ParserImplTest, TypeDecl_Texture_Old) { auto* type = tm()->Get(std::make_unique( ast::type::TextureDimension::kCube, &f32)); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr) << p->error(); - EXPECT_EQ(t, type); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr) << p->error(); + EXPECT_EQ(t.value, type); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32()); } TEST_F(ParserImplTest, TypeDecl_Texture) { @@ -671,12 +771,14 @@ TEST_F(ParserImplTest, TypeDecl_Texture) { auto* type = tm()->Get(std::make_unique( ast::type::TextureDimension::kCube, &f32)); - auto* t = p->type_decl(); - ASSERT_NE(t, nullptr); - EXPECT_EQ(t, type); - ASSERT_TRUE(t->IsTexture()); - ASSERT_TRUE(t->AsTexture()->IsSampled()); - ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); + auto t = p->type_decl(); + EXPECT_TRUE(t.matched); + EXPECT_FALSE(t.errored); + ASSERT_NE(t.value, nullptr); + EXPECT_EQ(t.value, type); + ASSERT_TRUE(t.value->IsTexture()); + ASSERT_TRUE(t.value->AsTexture()->IsSampled()); + ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32()); } } // namespace diff --git a/src/reader/wgsl/parser_impl_unary_expression_test.cc b/src/reader/wgsl/parser_impl_unary_expression_test.cc index 0484162d5f..d9c645cfeb 100644 --- a/src/reader/wgsl/parser_impl_unary_expression_test.cc +++ b/src/reader/wgsl/parser_impl_unary_expression_test.cc @@ -29,11 +29,13 @@ namespace { TEST_F(ParserImplTest, UnaryExpression_Postix) { auto* p = parser("a[2]"); auto e = p->unary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); - ASSERT_TRUE(e->IsArrayAccessor()); - auto* ary = e->AsArrayAccessor(); + ASSERT_TRUE(e.value->IsArrayAccessor()); + auto* ary = e.value->AsArrayAccessor(); ASSERT_TRUE(ary->array()->IsIdentifier()); auto* ident = ary->array()->AsIdentifier(); EXPECT_EQ(ident->name(), "a"); @@ -48,11 +50,13 @@ TEST_F(ParserImplTest, UnaryExpression_Postix) { TEST_F(ParserImplTest, UnaryExpression_Minus) { auto* p = parser("- 1"); auto e = p->unary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsUnaryOp()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsUnaryOp()); - auto* u = e->AsUnaryOp(); + auto* u = e.value->AsUnaryOp(); ASSERT_EQ(u->op(), ast::UnaryOp::kNegation); ASSERT_TRUE(u->expr()->IsConstructor()); @@ -66,19 +70,23 @@ TEST_F(ParserImplTest, UnaryExpression_Minus) { TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) { auto* p = parser("-if(a) {}"); auto e = p->unary_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression"); } TEST_F(ParserImplTest, UnaryExpression_Bang) { auto* p = parser("!1"); auto e = p->unary_expression(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsUnaryOp()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsUnaryOp()); - auto* u = e->AsUnaryOp(); + auto* u = e.value->AsUnaryOp(); ASSERT_EQ(u->op(), ast::UnaryOp::kNot); ASSERT_TRUE(u->expr()->IsConstructor()); @@ -92,8 +100,10 @@ TEST_F(ParserImplTest, UnaryExpression_Bang) { TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) { auto* p = parser("!if (a) {}"); auto e = p->unary_expression(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression"); } diff --git a/src/reader/wgsl/parser_impl_variable_decl_test.cc b/src/reader/wgsl/parser_impl_variable_decl_test.cc index 35edb242f0..3ff51ac1dc 100644 --- a/src/reader/wgsl/parser_impl_variable_decl_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decl_test.cc @@ -25,23 +25,27 @@ namespace { TEST_F(ParserImplTest, VariableDecl_Parses) { auto* p = parser("var my_var : f32"); auto var = p->variable_decl(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(var, nullptr); - ASSERT_EQ(var->name(), "my_var"); - ASSERT_NE(var->type(), nullptr); - ASSERT_TRUE(var->type()->IsF32()); + EXPECT_FALSE(p->has_error()); + EXPECT_TRUE(var.matched); + EXPECT_FALSE(var.errored); + ASSERT_NE(var.value, nullptr); + EXPECT_EQ(var.value->name(), "my_var"); + EXPECT_NE(var.value->type(), nullptr); + EXPECT_TRUE(var.value->type()->IsF32()); - ASSERT_EQ(var->source().range.begin.line, 1u); - ASSERT_EQ(var->source().range.begin.column, 5u); - ASSERT_EQ(var->source().range.end.line, 1u); - ASSERT_EQ(var->source().range.end.column, 11u); + EXPECT_EQ(var.value->source().range.begin.line, 1u); + EXPECT_EQ(var.value->source().range.begin.column, 5u); + EXPECT_EQ(var.value->source().range.end.line, 1u); + EXPECT_EQ(var.value->source().range.end.column, 11u); } TEST_F(ParserImplTest, VariableDecl_MissingVar) { auto* p = parser("my_var : f32"); auto v = p->variable_decl(); - ASSERT_EQ(v, nullptr); - ASSERT_FALSE(p->has_error()); + EXPECT_EQ(v.value, nullptr); + EXPECT_FALSE(v.matched); + EXPECT_FALSE(v.errored); + EXPECT_FALSE(p->has_error()); auto t = p->next(); ASSERT_TRUE(t.IsIdentifier()); @@ -50,31 +54,37 @@ TEST_F(ParserImplTest, VariableDecl_MissingVar) { TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) { auto* p = parser("var my_var f32"); auto v = p->variable_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(v, nullptr); - ASSERT_EQ(p->error(), "1:12: expected ':' for variable declaration"); + EXPECT_FALSE(v.matched); + EXPECT_TRUE(v.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(v.value, nullptr); + EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration"); } TEST_F(ParserImplTest, VariableDecl_WithStorageClass) { auto* p = parser("var my_var : f32"); auto v = p->variable_decl(); - ASSERT_FALSE(p->has_error()); - ASSERT_NE(v, nullptr); - EXPECT_EQ(v->name(), "my_var"); - EXPECT_TRUE(v->type()->IsF32()); - EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate); + EXPECT_TRUE(v.matched); + EXPECT_FALSE(v.errored); + EXPECT_FALSE(p->has_error()); + ASSERT_NE(v.value, nullptr); + EXPECT_EQ(v.value->name(), "my_var"); + EXPECT_TRUE(v.value->type()->IsF32()); + EXPECT_EQ(v.value->storage_class(), ast::StorageClass::kPrivate); - EXPECT_EQ(v->source().range.begin.line, 1u); - EXPECT_EQ(v->source().range.begin.column, 14u); - EXPECT_EQ(v->source().range.end.line, 1u); - EXPECT_EQ(v->source().range.end.column, 20u); + EXPECT_EQ(v.value->source().range.begin.line, 1u); + EXPECT_EQ(v.value->source().range.begin.column, 14u); + EXPECT_EQ(v.value->source().range.end.line, 1u); + EXPECT_EQ(v.value->source().range.end.column, 20u); } TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) { auto* p = parser("var my_var : f32"); auto v = p->variable_decl(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(v, nullptr); + EXPECT_FALSE(v.matched); + EXPECT_TRUE(v.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(v.value, nullptr); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration"); } 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 dcbac856e9..a9271b97a3 100644 --- a/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decoration_list_test.cc @@ -27,10 +27,12 @@ TEST_F(ParserImplTest, VariableDecorationList_Parses) { auto* p = parser(R"([[location(4), builtin(position)]])"); auto decos = p->decoration_list(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(decos.size(), 2u); + ASSERT_FALSE(decos.errored); + ASSERT_TRUE(decos.matched); + ASSERT_EQ(decos.value.size(), 2u); - auto deco_0 = ast::As(std::move(decos[0])); - auto deco_1 = ast::As(std::move(decos[1])); + auto deco_0 = ast::As(std::move(decos.value[0])); + auto deco_1 = ast::As(std::move(decos.value[1])); ASSERT_NE(deco_0, nullptr); ASSERT_NE(deco_1, nullptr); @@ -43,44 +45,62 @@ TEST_F(ParserImplTest, VariableDecorationList_Parses) { TEST_F(ParserImplTest, VariableDecorationList_Empty) { auto* p = parser(R"([[]])"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:3: empty decoration list"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:3: empty decoration list"); } TEST_F(ParserImplTest, VariableDecorationList_Invalid) { auto* p = parser(R"([[invalid]])"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_TRUE(decos.empty()); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:3: expected decoration"); } TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) { auto* p = parser(R"([[builtin(position), ]])"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:22: expected decoration"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:22: expected decoration"); } TEST_F(ParserImplTest, VariableDecorationList_MissingComma) { auto* p = parser(R"([[binding(4) location(5)]])"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:14: expected ',' for decoration list"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:14: expected ',' for decoration list"); } TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) { auto* p = parser(R"([[location(bad)]])"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:12: expected signed integer literal for location decoration"); } TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) { auto* p = parser("[[builtin(invalid)]]"); auto decos = p->decoration_list(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:11: invalid value for builtin decoration"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(decos.errored); + EXPECT_FALSE(decos.matched); + EXPECT_TRUE(decos.value.empty()); + EXPECT_EQ(p->error(), "1:11: invalid value for builtin decoration"); } } // namespace diff --git a/src/reader/wgsl/parser_impl_variable_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_test.cc index 5ada60c661..f99ae14d69 100644 --- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc @@ -28,8 +28,10 @@ namespace { TEST_F(ParserImplTest, VariableDecoration_Location) { auto* p = parser("location(4)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr); - auto var_deco = ast::As(std::move(deco)); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto var_deco = ast::As(std::move(deco.value)); ASSERT_NE(var_deco, nullptr); ASSERT_FALSE(p->has_error()); ASSERT_TRUE(var_deco->IsLocation()); @@ -41,24 +43,30 @@ TEST_F(ParserImplTest, VariableDecoration_Location) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) { auto* p = parser("location 4)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected '(' for location decoration"); } TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) { auto* p = parser("location(4"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: expected ')' for location decoration"); } TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { auto* p = parser("location()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for location decoration"); } @@ -66,8 +74,10 @@ TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) { auto* p = parser("location(nan)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for location decoration"); } @@ -88,8 +98,10 @@ TEST_P(BuiltinTest, VariableDecoration_Builtin) { auto* p = parser(std::string("builtin(") + params.input + ")"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr); - auto var_deco = ast::As(std::move(deco)); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto var_deco = ast::As(std::move(deco.value)); ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_NE(var_deco, nullptr); ASSERT_TRUE(var_deco->IsBuiltin()); @@ -115,48 +127,60 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) { auto* p = parser("builtin position)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected '(' for builtin decoration"); } TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) { auto* p = parser("builtin(position"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:17: expected ')' for builtin decoration"); } TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) { auto* p = parser("builtin()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); } TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) { auto* p = parser("builtin(other_thingy)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: invalid value for builtin decoration"); } TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) { auto* p = parser("builtin(3)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); } TEST_F(ParserImplTest, VariableDecoration_Binding) { auto* p = parser("binding(4)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr); - auto var_deco = ast::As(std::move(deco)); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto var_deco = ast::As(std::move(deco.value)); ASSERT_NE(var_deco, nullptr); ASSERT_FALSE(p->has_error()); ASSERT_TRUE(var_deco->IsBinding()); @@ -168,24 +192,30 @@ TEST_F(ParserImplTest, VariableDecoration_Binding) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) { auto* p = parser("binding 4)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected '(' for binding decoration"); } TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) { auto* p = parser("binding(4"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:10: expected ')' for binding decoration"); } TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { auto* p = parser("binding()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected signed integer literal for binding decoration"); } @@ -193,8 +223,10 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { auto* p = parser("binding(nan)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: expected signed integer literal for binding decoration"); } @@ -202,8 +234,10 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_set) { auto* p = parser("set(4)"); auto deco = p->decoration(); - ASSERT_NE(deco, nullptr); - auto var_deco = ast::As(std::move(deco)); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto var_deco = ast::As(std::move(deco.value)); ASSERT_FALSE(p->has_error()); ASSERT_NE(var_deco.get(), nullptr); ASSERT_TRUE(var_deco->IsSet()); @@ -215,24 +249,30 @@ TEST_F(ParserImplTest, VariableDecoration_set) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) { auto* p = parser("set 2)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:5: expected '(' for set decoration"); } TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) { auto* p = parser("set(2"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:6: expected ')' for set decoration"); } TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { auto* p = parser("set()"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:5: expected signed integer literal for set decoration"); } @@ -240,8 +280,10 @@ TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) { auto* p = parser("set(nan)"); auto deco = p->decoration(); - ASSERT_EQ(deco, nullptr); - ASSERT_TRUE(p->has_error()); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:5: expected signed integer literal for set decoration"); } diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc index 8a984c9163..a0fba9582d 100644 --- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc @@ -26,96 +26,114 @@ namespace { TEST_F(ParserImplTest, VariableStmt_VariableDecl) { auto* p = parser("var a : i32;"); auto e = p->variable_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsVariableDecl()); - ASSERT_NE(e->variable(), nullptr); - EXPECT_EQ(e->variable()->name(), "a"); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsVariableDecl()); + ASSERT_NE(e.value->variable(), nullptr); + EXPECT_EQ(e.value->variable()->name(), "a"); - ASSERT_EQ(e->source().range.begin.line, 1u); - ASSERT_EQ(e->source().range.begin.column, 5u); - ASSERT_EQ(e->source().range.end.line, 1u); - ASSERT_EQ(e->source().range.end.column, 6u); + ASSERT_EQ(e.value->source().range.begin.line, 1u); + ASSERT_EQ(e.value->source().range.begin.column, 5u); + ASSERT_EQ(e.value->source().range.end.line, 1u); + ASSERT_EQ(e.value->source().range.end.column, 6u); - EXPECT_EQ(e->variable()->constructor(), nullptr); + EXPECT_EQ(e.value->variable()->constructor(), nullptr); } TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) { auto* p = parser("var a : i32 = 1;"); auto e = p->variable_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsVariableDecl()); - ASSERT_NE(e->variable(), nullptr); - EXPECT_EQ(e->variable()->name(), "a"); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsVariableDecl()); + ASSERT_NE(e.value->variable(), nullptr); + EXPECT_EQ(e.value->variable()->name(), "a"); - ASSERT_EQ(e->source().range.begin.line, 1u); - ASSERT_EQ(e->source().range.begin.column, 5u); - ASSERT_EQ(e->source().range.end.line, 1u); - ASSERT_EQ(e->source().range.end.column, 6u); + ASSERT_EQ(e.value->source().range.begin.line, 1u); + ASSERT_EQ(e.value->source().range.begin.column, 5u); + ASSERT_EQ(e.value->source().range.end.line, 1u); + ASSERT_EQ(e.value->source().range.end.column, 6u); - ASSERT_NE(e->variable()->constructor(), nullptr); - EXPECT_TRUE(e->variable()->constructor()->IsConstructor()); + ASSERT_NE(e.value->variable()->constructor(), nullptr); + EXPECT_TRUE(e.value->variable()->constructor()->IsConstructor()); } TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) { auto* p = parser("var a : invalid;"); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'"); } TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) { auto* p = parser("var a : i32 = if(a) {}"); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration"); } TEST_F(ParserImplTest, VariableStmt_Const) { auto* p = parser("const a : i32 = 1"); auto e = p->variable_stmt(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsVariableDecl()); + EXPECT_TRUE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsVariableDecl()); - ASSERT_EQ(e->source().range.begin.line, 1u); - ASSERT_EQ(e->source().range.begin.column, 7u); - ASSERT_EQ(e->source().range.end.line, 1u); - ASSERT_EQ(e->source().range.end.column, 8u); + ASSERT_EQ(e.value->source().range.begin.line, 1u); + ASSERT_EQ(e.value->source().range.begin.column, 7u); + ASSERT_EQ(e.value->source().range.end.line, 1u); + ASSERT_EQ(e.value->source().range.end.column, 8u); } TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) { auto* p = parser("const a : invalid = 1"); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:11: unknown constructed type 'invalid'"); } TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) { auto* p = parser("const a : i32 1"); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:15: expected '=' for constant declaration"); } TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) { auto* p = parser("const a : i32 ="); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:16: missing constructor for const declaration"); } TEST_F(ParserImplTest, VariableStmt_Const_InvalidConstructor) { auto* p = parser("const a : i32 = if (a) {}"); auto e = p->variable_stmt(); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_EQ(e.value, nullptr); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:17: missing constructor for const declaration"); } diff --git a/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc index 70e7a633b6..75daebf2eb 100644 --- a/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc @@ -39,8 +39,10 @@ TEST_P(VariableStorageTest, Parses) { auto* p = parser(std::string("<") + params.input + ">"); auto sc = p->variable_storage_decoration(); - ASSERT_FALSE(p->has_error()); - EXPECT_EQ(sc, params.result); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(sc.errored); + EXPECT_TRUE(sc.matched); + EXPECT_EQ(sc.value, params.result); auto t = p->next(); EXPECT_TRUE(t.IsEof()); @@ -64,24 +66,27 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) { auto* p = parser(""); auto sc = p->variable_storage_decoration(); - ASSERT_EQ(sc, ast::StorageClass::kNone); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(sc.errored); + EXPECT_FALSE(sc.matched); + EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); } TEST_F(ParserImplTest, VariableStorageDecoration_Empty) { auto* p = parser("<>"); auto sc = p->variable_storage_decoration(); - ASSERT_EQ(sc, ast::StorageClass::kNone); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(sc.errored); + EXPECT_FALSE(sc.matched); + EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); } TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) { auto* p = parser("in>"); auto sc = p->variable_storage_decoration(); - ASSERT_EQ(sc, ast::StorageClass::kNone); - ASSERT_FALSE(p->has_error()); + EXPECT_FALSE(p->has_error()); + EXPECT_FALSE(sc.errored); + EXPECT_FALSE(sc.matched); auto t = p->next(); ASSERT_TRUE(t.IsIn()); @@ -90,9 +95,10 @@ TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) { TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) { auto* p = parser("variable_storage_decoration(); - ASSERT_EQ(sc, ast::StorageClass::kNone); - ASSERT_TRUE(p->has_error()); - ASSERT_EQ(p->error(), "1:4: expected '>' for variable decoration"); + EXPECT_TRUE(p->has_error()); + EXPECT_TRUE(sc.errored); + EXPECT_FALSE(sc.matched); + EXPECT_EQ(p->error(), "1:4: expected '>' for variable decoration"); } } // namespace