From 653c4042e27643fd13838e6f619397376e6d1e77 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 9 Nov 2020 19:39:34 +0000 Subject: [PATCH] wsgl parser: Add ParserImpl::Expect And use it for the ParserImpl::expect_xxx() methods. This is the first step towards supporting multiple error messages, as the caller can now test to see if the specific call errored, instead of using a global error state. Also cleans up a bunch of code. Bug: tint:282 Change-Id: I5e39fc33bd1e16620cee80d27fa728bc2af3387e Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32101 Commit-Queue: Ben Clayton Reviewed-by: dan sinclair --- src/reader/wgsl/parser_impl.cc | 1030 +++++++++-------- src/reader/wgsl/parser_impl.h | 213 ++-- ...rser_impl_argument_expression_list_test.cc | 16 +- src/reader/wgsl/parser_impl_body_stmt_test.cc | 12 +- .../wgsl/parser_impl_const_expr_test.cc | 41 +- src/reader/wgsl/parser_impl_for_stmt_test.cc | 16 +- .../parser_impl_image_storage_type_test.cc | 182 +-- .../wgsl/parser_impl_param_list_test.cc | 66 +- .../wgsl/parser_impl_paren_rhs_stmt_test.cc | 17 +- .../wgsl/parser_impl_pipeline_stage_test.cc | 25 +- .../wgsl/parser_impl_statements_test.cc | 18 +- .../wgsl/parser_impl_storage_class_test.cc | 9 +- .../wgsl/parser_impl_struct_body_decl_test.cc | 11 +- .../wgsl/parser_impl_struct_member_test.cc | 72 +- .../parser_impl_variable_ident_decl_test.cc | 26 +- 15 files changed, 966 insertions(+), 788 deletions(-) diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 52aba795c6..b04a509dde 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -74,6 +74,9 @@ namespace reader { namespace wgsl { namespace { +template +using Expect = ParserImpl::Expect; + /// 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. @@ -123,27 +126,32 @@ ParserImpl::ParserImpl(Context* ctx, Source::File const* file) ParserImpl::~ParserImpl() = default; -void ParserImpl::add_error(const Source& source, - const std::string& err, - const std::string& use) { +ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source, + const std::string& err, + const std::string& use) { std::stringstream msg; msg << err; if (!use.empty()) { msg << " for " << use; } add_error(source, msg.str()); + return Failure::kErrored; } -void ParserImpl::add_error(const Token& t, const std::string& err) { +ParserImpl::Failure::Errored ParserImpl::add_error(const Token& t, + const std::string& err) { add_error(t.source(), err); + return Failure::kErrored; } -void ParserImpl::add_error(const Source& source, const std::string& err) { +ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source, + const std::string& err) { diag::Diagnostic diagnostic; diagnostic.severity = diag::Severity::Error; diagnostic.message = err; diagnostic.source = source; diags_.add(std::move(diagnostic)); + return Failure::kErrored; } Token ParserImpl::next() { @@ -187,12 +195,9 @@ bool ParserImpl::Parse() { // translation_unit // : global_decl* EOF void ParserImpl::translation_unit() { - for (;;) { - expect_global_decl(); - if (has_error()) - return; - - if (peek().IsEof()) + while (!peek().IsEof()) { + auto decl = expect_global_decl(); + if (decl.errored) break; } @@ -206,84 +211,77 @@ void ParserImpl::translation_unit() { // | type_alias SEMICOLON // | struct_decl SEMICOLON // | function_decl -void ParserImpl::expect_global_decl() { - auto t = peek(); - if (t.IsEof()) { - return; - } - - if (t.IsSemicolon()) { - next(); // consume the peek - return; - } +Expect ParserImpl::expect_global_decl() { + if (match(Token::Type::kSemicolon) || match(Token::Type::kEOF)) + return true; auto decos = decoration_list(); auto gv = global_variable_decl(decos); - if (has_error()) { - return; - } + if (has_error()) + return Failure::kErrored; + if (gv != nullptr) { if (!expect("variable declaration", Token::Type::kSemicolon)) - return; + return Failure::kErrored; module_.AddGlobalVariable(std::move(gv)); - return; + return true; } auto gc = global_constant_decl(); - if (has_error()) { - return; - } + if (has_error()) + return Failure::kErrored; + if (gc != nullptr) { if (!expect("constant declaration", Token::Type::kSemicolon)) - return; + return Failure::kErrored; module_.AddGlobalVariable(std::move(gc)); - return; + return true; } auto* ta = type_alias(); - if (has_error()) { - return; - } + if (has_error()) + return Failure::kErrored; + if (ta != nullptr) { if (!expect("type alias", Token::Type::kSemicolon)) - return; + return Failure::kErrored; module_.AddConstructedType(ta); - return; + return true; } auto str = struct_decl(decos); - if (has_error()) { - return; - } + if (has_error()) + return Failure::kErrored; + if (str != nullptr) { if (!expect("struct declaration", Token::Type::kSemicolon)) - return; + return Failure::kErrored; auto* type = ctx_.type_mgr().Get(std::move(str)); register_constructed(type->AsStruct()->name(), type); module_.AddConstructedType(type); - return; + return true; } auto func = function_decl(decos); - if (has_error()) { - return; - } + if (has_error()) + return Failure::kErrored; + if (func != nullptr) { module_.AddFunction(std::move(func)); - return; + return true; } - t = peek(); if (decos.size() > 0) { - add_error(t, "expected declaration after decorations"); + add_error(peek(), "expected declaration after decorations"); } else { - add_error(t, "invalid token"); + add_error(peek(), "invalid token"); } + return Failure::kErrored; } // global_variable_decl @@ -296,17 +294,20 @@ std::unique_ptr ParserImpl::global_variable_decl( return nullptr; auto var_decos = cast_decorations(decos); - if (var_decos.size() > 0) { + if (var_decos.errored) + return nullptr; + + if (var_decos.value.size() > 0) { auto dv = std::make_unique(std::move(var)); - dv->set_decorations(std::move(var_decos)); + dv->set_decorations(std::move(var_decos.value)); var = std::move(dv); } if (match(Token::Type::kEqual)) { auto expr = expect_const_expr(); - if (has_error()) + if (expr.errored) return nullptr; - var->set_constructor(std::move(expr)); + var->set_constructor(std::move(expr.value)); } return var; } @@ -320,21 +321,21 @@ std::unique_ptr ParserImpl::global_constant_decl() { const char* use = "constant declaration"; auto decl = expect_variable_ident_decl(use); - if (has_error()) + if (decl.errored) return nullptr; auto var = std::make_unique( - decl.source, decl.name, ast::StorageClass::kNone, decl.type); + decl->source, decl->name, ast::StorageClass::kNone, decl->type); var->set_is_const(true); if (!expect(use, Token::Type::kEqual)) return nullptr; auto init = expect_const_expr(); - if (has_error()) + if (init.errored) return nullptr; - var->set_constructor(std::move(init)); + var->set_constructor(std::move(init.value)); return var; } @@ -350,10 +351,11 @@ std::unique_ptr ParserImpl::variable_decl() { return nullptr; auto decl = expect_variable_ident_decl("variable declaration"); - if (has_error()) + if (decl.errored) return nullptr; - return std::make_unique(decl.source, decl.name, sc, decl.type); + return std::make_unique(decl->source, decl->name, sc, + decl->type); } // texture_sampler_types @@ -426,19 +428,15 @@ ast::type::Type* ParserImpl::texture_sampler_types() { if (!expect(use, Token::Type::kLessThan)) return nullptr; - auto format = image_storage_type(); - if (has_error()) + auto format = expect_image_storage_type(use); + if (format.errored) return nullptr; - if (format == ast::type::ImageFormat::kNone) { - add_error(peek().source(), "invalid format", use); - return nullptr; - } if (!expect(use, Token::Type::kGreaterThan)) return nullptr; return ctx_.type_mgr().Get(std::make_unique( - storage_dim, access, format)); + storage_dim, access, format.value)); } return nullptr; @@ -622,7 +620,8 @@ ast::type::Type* ParserImpl::depth_texture_type() { // | RGBA32UINT // | RGBA32SINT // | RGBA32FLOAT -ast::type::ImageFormat ParserImpl::image_storage_type() { +Expect ParserImpl::expect_image_storage_type( + const std::string& use) { if (match(Token::Type::kFormatR8Unorm)) return ast::type::ImageFormat::kR8Unorm; @@ -728,31 +727,31 @@ ast::type::ImageFormat ParserImpl::image_storage_type() { if (match(Token::Type::kFormatRgba32Float)) return ast::type::ImageFormat::kRgba32Float; - return ast::type::ImageFormat::kNone; + return add_error(peek().source(), "invalid format", use); } // variable_ident_decl // : IDENT COLON type_decl -ParserImpl::TypedIdentifier ParserImpl::expect_variable_ident_decl( +Expect ParserImpl::expect_variable_ident_decl( const std::string& use) { - std::string name; - Source source; - if (!expect_ident(use, &name, &source)) - return {}; + auto ident = expect_ident(use); + if (ident.errored) + return Failure::kErrored; if (!expect(use, Token::Type::kColon)) - return {}; + return Failure::kErrored; auto t = peek(); auto* type = type_decl(); if (has_error()) - return {}; + return Failure::kErrored; + if (type == nullptr) { add_error(t.source(), "invalid type", use); - return {}; + return Failure::kErrored; } - return {type, name, source}; + return TypedIdentifier{type, ident.value, ident.source}; } // variable_storage_decoration @@ -764,13 +763,13 @@ ast::StorageClass ParserImpl::variable_storage_decoration() { const char* use = "variable decoration"; auto sc = expect_storage_class(use); - if (has_error()) - return sc; + if (sc.errored) + return ast::StorageClass::kNone; if (!expect(use, Token::Type::kGreaterThan)) return ast::StorageClass::kNone; - return sc; + return sc.value; } // type_alias @@ -784,8 +783,8 @@ ast::type::Type* ParserImpl::type_alias() { const char* use = "type alias"; - std::string name; - if (!expect_ident(use, &name)) + auto name = expect_ident(use); + if (name.errored) return nullptr; if (!expect(use, Token::Type::kEqual)) @@ -799,9 +798,9 @@ ast::type::Type* ParserImpl::type_alias() { return nullptr; } - auto* alias = - ctx_.type_mgr().Get(std::make_unique(name, type)); - register_constructed(name, alias); + auto* alias = ctx_.type_mgr().Get( + std::make_unique(name.value, type)); + register_constructed(name.value, alias); return alias->AsAlias(); } @@ -853,11 +852,12 @@ ast::type::Type* ParserImpl::type_decl() { if (match(Token::Type::kU32)) return ctx_.type_mgr().Get(std::make_unique()); - if (t.IsVec2() || t.IsVec3() || t.IsVec4()) - return expect_type_decl_vector(t); + if (t.IsVec2() || t.IsVec3() || t.IsVec4()) { + return expect_type_decl_vector(t).value; + } if (match(Token::Type::kPtr)) - return expect_type_decl_pointer(); + return expect_type_decl_pointer().value; auto decos = decoration_list(); if (has_error()) @@ -865,7 +865,9 @@ ast::type::Type* ParserImpl::type_decl() { if (match(Token::Type::kArray)) { auto array_decos = cast_decorations(decos); - return expect_type_decl_array(std::move(array_decos)); + if (array_decos.errored) + return nullptr; + return expect_type_decl_array(std::move(array_decos.value)).value; } expect_decorations_consumed(decos); @@ -873,7 +875,7 @@ ast::type::Type* ParserImpl::type_decl() { 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); + return expect_type_decl_matrix(t).value; } auto* texture_or_sampler = texture_sampler_types(); @@ -887,35 +889,33 @@ ast::type::Type* ParserImpl::type_decl() { return nullptr; } -ast::type::Type* ParserImpl::expect_type_decl_pointer() { +Expect ParserImpl::expect_type_decl_pointer() { const char* use = "ptr declaration"; if (!expect(use, Token::Type::kLessThan)) - return nullptr; + return Failure::kErrored; auto sc = expect_storage_class(use); - if (has_error()) - return nullptr; + if (sc.errored) + return Failure::kErrored; if (!expect(use, Token::Type::kComma)) - return nullptr; + return Failure::kErrored; auto* subtype = type_decl(); if (has_error()) - return nullptr; - if (subtype == nullptr) { - add_error(peek(), "missing type for ptr declaration"); - return nullptr; - } + return Failure::kErrored; + if (subtype == nullptr) + return add_error(peek().source(), "missing type", use); if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; return ctx_.type_mgr().Get( - std::make_unique(subtype, sc)); + std::make_unique(subtype, sc.value)); } -ast::type::Type* ParserImpl::expect_type_decl_vector(Token t) { +Expect ParserImpl::expect_type_decl_vector(Token t) { next(); // Consume the peek uint32_t count = 2; @@ -927,53 +927,52 @@ ast::type::Type* ParserImpl::expect_type_decl_vector(Token t) { const char* use = "vector"; if (!expect(use, Token::Type::kLessThan)) - return nullptr; + return Failure::kErrored; auto* subtype = type_decl(); if (has_error()) - return nullptr; + return Failure::kErrored; if (subtype == nullptr) { - add_error(peek().source(), "unable to determine subtype", use); - return nullptr; + return add_error(peek().source(), "unable to determine subtype", use); } if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; return ctx_.type_mgr().Get( std::make_unique(subtype, count)); } -ast::type::Type* ParserImpl::expect_type_decl_array( +Expect ParserImpl::expect_type_decl_array( ast::ArrayDecorationList decos) { const char* use = "array declaration"; 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(), "invalid type for array declaration"); - return nullptr; - } + return Failure::kErrored; + if (subtype == nullptr) + return add_error(peek(), "invalid type for array declaration"); uint32_t size = 0; if (match(Token::Type::kComma)) { - if (!expect_nonzero_positive_sint("array size", &size)) - return nullptr; + auto val = expect_nonzero_positive_sint("array size"); + if (val.errored) + return Failure::kErrored; + size = val.value; } if (!expect(use, Token::Type::kGreaterThan)) - return nullptr; + return Failure::kErrored; auto ty = std::make_unique(subtype, size); ty->set_decorations(std::move(decos)); return ctx_.type_mgr().Get(std::move(ty)); } -ast::type::Type* ParserImpl::expect_type_decl_matrix(Token t) { +Expect ParserImpl::expect_type_decl_matrix(Token t) { next(); // Consume the peek uint32_t rows = 2; @@ -990,24 +989,18 @@ ast::type::Type* ParserImpl::expect_type_decl_matrix(Token t) { } t = next(); - if (!t.IsLessThan()) { - add_error(t, "missing < for matrix"); - return nullptr; - } + if (!t.IsLessThan()) + return add_error(t, "missing < for matrix"); auto* subtype = type_decl(); if (has_error()) - return nullptr; - if (subtype == nullptr) { - add_error(peek(), "unable to determine subtype for matrix"); - return nullptr; - } + return Failure::kErrored; + if (subtype == nullptr) + return add_error(peek(), "unable to determine subtype for matrix"); t = next(); - if (!t.IsGreaterThan()) { - add_error(t, "missing > for matrix"); - return nullptr; - } + if (!t.IsGreaterThan()) + return add_error(t, "missing > for matrix"); return ctx_.type_mgr().Get( std::make_unique(subtype, rows, columns)); @@ -1023,7 +1016,8 @@ ast::type::Type* ParserImpl::expect_type_decl_matrix(Token t) { // | IMAGE // | PRIVATE // | FUNCTION -ast::StorageClass ParserImpl::expect_storage_class(const std::string& use) { +Expect ParserImpl::expect_storage_class( + const std::string& use) { if (match(Token::Type::kIn)) return ast::StorageClass::kInput; @@ -1051,8 +1045,7 @@ ast::StorageClass ParserImpl::expect_storage_class(const std::string& use) { if (match(Token::Type::kFunction)) return ast::StorageClass::kFunction; - add_error(peek().source(), "invalid storage class", use); - return ast::StorageClass::kNone; + return add_error(peek().source(), "invalid storage class", use); } // struct_decl @@ -1066,45 +1059,49 @@ std::unique_ptr ParserImpl::struct_decl( return nullptr; auto struct_decos = cast_decorations(decos); + if (struct_decos.errored) + return nullptr; - std::string name; - if (!expect_ident("struct declaration", &name)) + auto name = expect_ident("struct declaration"); + if (name.errored) return nullptr; auto body = expect_struct_body_decl(); - if (has_error()) + if (body.errored) return nullptr; return std::make_unique( - name, std::make_unique(source, std::move(struct_decos), - std::move(body))); + name.value, + std::make_unique(source, std::move(struct_decos.value), + std::move(body.value))); } // struct_body_decl // : BRACKET_LEFT struct_member* BRACKET_RIGHT -ast::StructMemberList ParserImpl::expect_struct_body_decl() { - return expect_brace_block("struct declaration", [&] { - ast::StructMemberList members; +Expect ParserImpl::expect_struct_body_decl() { + return expect_brace_block( + "struct declaration", [&]() -> Expect { + ast::StructMemberList members; - while (!peek().IsBraceRight() && !peek().IsEof()) { - auto decos = decoration_list(); - if (has_error()) - return ast::StructMemberList{}; + while (!peek().IsBraceRight() && !peek().IsEof()) { + auto decos = decoration_list(); + if (has_error()) + return Failure::kErrored; - auto mem = expect_struct_member(decos); - if (has_error()) - return ast::StructMemberList{}; + auto mem = expect_struct_member(decos); + if (mem.errored) + return Failure::kErrored; - members.push_back(std::move(mem)); - } + members.push_back(std::move(mem.value)); + } - return members; - }); + return members; + }); } // struct_member // : struct_member_decoration_decl+ variable_ident_decl SEMICOLON -std::unique_ptr ParserImpl::expect_struct_member( +Expect> ParserImpl::expect_struct_member( ast::DecorationList& decos) { // FUDGE - Abort early if we enter with an error state to avoid accumulating // multiple error messages. This is a work around for the unit tests that @@ -1118,19 +1115,19 @@ std::unique_ptr ParserImpl::expect_struct_member( // resynchronize at the ']]'. // TODO(ben-clayton) - remove this once resynchronization is implemented. if (has_error()) - return nullptr; + return Failure::kErrored; auto decl = expect_variable_ident_decl("struct member"); - if (has_error()) - return nullptr; + if (decl.errored) + return Failure::kErrored; auto member_decos = cast_decorations(decos); if (!expect("struct member", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; - return std::make_unique(decl.source, decl.name, decl.type, - std::move(member_decos)); + return std::make_unique( + decl->source, decl->name, decl->type, std::move(member_decos.value)); } // function_decl @@ -1142,13 +1139,15 @@ std::unique_ptr ParserImpl::function_decl( return nullptr; auto func_decos = cast_decorations(decos); - f->set_decorations(std::move(func_decos)); + if (func_decos.errored) + return nullptr; + f->set_decorations(std::move(func_decos.value)); auto body = expect_body_stmt(); - if (has_error()) + if (body.errored) return nullptr; - f->set_body(std::move(body)); + f->set_body(std::move(body.value)); return f; } @@ -1173,13 +1172,13 @@ std::unique_ptr ParserImpl::function_header() { const char* use = "function declaration"; - std::string name; - if (!expect_ident(use, &name)) + auto name = expect_ident(use); + if (name.errored) return nullptr; auto params = expect_paren_block(use, [&] { return expect_param_list(); }); - if (has_error()) + if (params.errored) return nullptr; auto t = next(); @@ -1196,24 +1195,25 @@ std::unique_ptr ParserImpl::function_header() { return nullptr; } - return std::make_unique(source, name, std::move(params), type); + return std::make_unique(source, name.value, + std::move(params.value), type); } // param_list // : // | (variable_ident_decl COMMA)* variable_ident_decl -ast::VariableList ParserImpl::expect_param_list() { +Expect ParserImpl::expect_param_list() { if (!peek().IsIdentifier()) // Empty list return ast::VariableList{}; auto decl = expect_variable_ident_decl("parameter"); - if (has_error()) - return {}; + if (decl.errored) + return Failure::kErrored; ast::VariableList ret; for (;;) { auto var = std::make_unique( - decl.source, decl.name, ast::StorageClass::kNone, decl.type); + decl->source, decl->name, ast::StorageClass::kNone, decl->type); // Formal parameters are treated like a const declaration where the // initializer value is provided by the call's argument. The key point is // that it's not updatable after intially set. This is unlike C or GLSL @@ -1225,8 +1225,8 @@ ast::VariableList ParserImpl::expect_param_list() { break; decl = expect_variable_ident_decl("parameter"); - if (has_error()) - return {}; + if (decl.errored) + return Failure::kErrored; } return ret; @@ -1236,7 +1236,7 @@ ast::VariableList ParserImpl::expect_param_list() { // : VERTEX // | FRAGMENT // | COMPUTE -std::pair ParserImpl::expect_pipeline_stage() { +Expect ParserImpl::expect_pipeline_stage() { Source source; if (match(Token::Type::kVertex, &source)) return {ast::PipelineStage::kVertex, source}; @@ -1247,57 +1247,53 @@ std::pair ParserImpl::expect_pipeline_stage() { if (match(Token::Type::kCompute, &source)) return {ast::PipelineStage::kCompute, source}; - auto t = peek(); - add_error(t, "invalid value for stage decoration"); - return {ast::PipelineStage::kNone, t.source()}; + return add_error(peek(), "invalid value for stage decoration"); } -std::pair ParserImpl::expect_builtin() { - Source source; - std::string ident; +Expect ParserImpl::expect_builtin() { + auto ident = expect_ident("builtin"); + if (ident.errored) + return Failure::kErrored; - if (!expect_ident("builtin", &ident, &source)) - return {ast::Builtin::kNone, source}; - - ast::Builtin builtin = ident_to_builtin(ident); + ast::Builtin builtin = ident_to_builtin(ident.value); if (builtin == ast::Builtin::kNone) - add_error(source, "invalid value for builtin decoration"); + return add_error(ident.source, "invalid value for builtin decoration"); - return {builtin, source}; + return {builtin, ident.source}; } // body_stmt // : BRACKET_LEFT statements BRACKET_RIGHT -std::unique_ptr ParserImpl::expect_body_stmt() { - return expect_brace_block("", [&] { return statements(); }); +Expect> ParserImpl::expect_body_stmt() { + return expect_brace_block("", [&] { return expect_statements(); }); } // paren_rhs_stmt // : PAREN_LEFT logical_or_expression PAREN_RIGHT -std::unique_ptr ParserImpl::expect_paren_rhs_stmt() { - return expect_paren_block("", [&]() -> std::unique_ptr { - auto expr = logical_or_expression(); - if (has_error()) - return nullptr; +Expect> ParserImpl::expect_paren_rhs_stmt() { + return expect_paren_block( + "", [&]() -> Expect> { + auto expr = logical_or_expression(); + if (has_error()) + return Failure::kErrored; - if (expr == nullptr) { - add_error(peek(), "unable to parse expression"); - return nullptr; - } - return expr; - }); + if (expr == nullptr) + return add_error(peek(), "unable to parse expression"); + + return expr; + }); } // statements // : statement* -std::unique_ptr ParserImpl::statements() { +Expect> ParserImpl::expect_statements() { auto ret = std::make_unique(); for (;;) { auto stmt = statement(); if (has_error()) - return {}; - if (stmt == nullptr) + return Failure::kErrored; + if (!stmt) break; ret->append(std::move(stmt)); @@ -1423,10 +1419,9 @@ std::unique_ptr ParserImpl::statement() { t = peek(); if (t.IsBraceLeft()) { auto body = expect_body_stmt(); - if (has_error()) + if (body.errored) return nullptr; - if (body != nullptr) - return body; + return std::move(body.value); } return nullptr; @@ -1473,11 +1468,11 @@ std::unique_ptr ParserImpl::variable_stmt() { } auto var = std::make_unique( - decl.source, decl.name, ast::StorageClass::kNone, decl.type); + decl->source, decl->name, ast::StorageClass::kNone, decl->type); var->set_is_const(true); var->set_constructor(std::move(constructor)); - return std::make_unique(decl.source, + return std::make_unique(decl->source, std::move(var)); } @@ -1510,11 +1505,11 @@ std::unique_ptr ParserImpl::if_stmt() { return nullptr; auto condition = expect_paren_rhs_stmt(); - if (has_error()) + if (condition.errored) return nullptr; auto body = expect_body_stmt(); - if (has_error()) + if (body.errored) return nullptr; auto elseif = elseif_stmt(); @@ -1525,8 +1520,8 @@ std::unique_ptr ParserImpl::if_stmt() { if (has_error()) return nullptr; - auto stmt = std::make_unique(source, std::move(condition), - std::move(body)); + auto stmt = std::make_unique( + source, std::move(condition.value), std::move(body.value)); if (el != nullptr) { elseif.push_back(std::move(el)); } @@ -1548,15 +1543,15 @@ ast::ElseStatementList ParserImpl::elseif_stmt() { next(); // Consume the peek auto condition = expect_paren_rhs_stmt(); - if (has_error()) + if (condition.errored) return {}; auto body = expect_body_stmt(); - if (has_error()) + if (body.errored) return {}; ret.push_back(std::make_unique( - source, std::move(condition), std::move(body))); + source, std::move(condition.value), std::move(body.value))); t = peek(); if (!t.IsElseIf()) @@ -1577,10 +1572,10 @@ std::unique_ptr ParserImpl::else_stmt() { next(); // Consume the peek auto body = expect_body_stmt(); - if (has_error()) + if (body.errored) return nullptr; - return std::make_unique(source, std::move(body)); + return std::make_unique(source, std::move(body.value)); } // switch_stmt @@ -1591,11 +1586,11 @@ std::unique_ptr ParserImpl::switch_stmt() { return nullptr; auto condition = expect_paren_rhs_stmt(); - if (has_error()) + if (condition.errored) return nullptr; ast::CaseStatementList body; - bool ok = expect_brace_block("switch statement", [&] { + bool ok = expect_brace_block_old("switch statement", [&] { for (;;) { auto stmt = switch_body(); if (has_error()) @@ -1611,8 +1606,8 @@ std::unique_ptr ParserImpl::switch_stmt() { if (!ok) return nullptr; - return std::make_unique(source, std::move(condition), - std::move(body)); + return std::make_unique( + source, std::move(condition.value), std::move(body)); } // switch_body @@ -1629,14 +1624,14 @@ std::unique_ptr ParserImpl::switch_body() { auto stmt = std::make_unique(); stmt->set_source(source); if (t.IsCase()) { - auto selectors = case_selectors(); + auto selectors = expect_case_selectors(); if (has_error()) return nullptr; - if (selectors.empty()) { + if (selectors.value.empty()) { add_error(peek(), "unable to parse case selectors"); return nullptr; } - stmt->set_selectors(std::move(selectors)); + stmt->set_selectors(std::move(selectors.value)); } const char* use = "case statement"; @@ -1644,7 +1639,7 @@ std::unique_ptr ParserImpl::switch_body() { if (!expect(use, Token::Type::kColon)) return nullptr; - auto body = expect_brace_block(use, [&] { return case_body(); }); + auto body = expect_brace_block_old(use, [&] { return case_body(); }); if (body == nullptr) return nullptr; @@ -1656,25 +1651,26 @@ std::unique_ptr ParserImpl::switch_body() { // case_selectors // : const_literal (COMMA const_literal)* -ast::CaseSelectorList ParserImpl::case_selectors() { +Expect ParserImpl::expect_case_selectors() { ast::CaseSelectorList selectors; for (;;) { auto t = peek(); auto cond = const_literal(); if (has_error()) - return {}; + return Failure::kErrored; if (cond == nullptr) break; - if (!cond->IsInt()) { - add_error(t, "invalid case selector must be an integer value"); - return {}; - } + if (!cond->IsInt()) + return add_error(t, "invalid case selector must be an integer value"); std::unique_ptr selector(cond.release()->AsInt()); selectors.push_back(std::move(selector)); } + if (selectors.empty()) + return add_error(peek(), "unable to parse case selectors"); + return selectors; } @@ -1716,18 +1712,18 @@ std::unique_ptr ParserImpl::loop_stmt() { if (!match(Token::Type::kLoop, &source)) return nullptr; - return expect_brace_block( + return expect_brace_block_old( "loop", [&]() -> std::unique_ptr { - auto body = statements(); - if (has_error()) + auto body = expect_statements(); + if (body.errored) return nullptr; auto continuing = continuing_stmt(); if (has_error()) return nullptr; - return std::make_unique(source, std::move(body), - std::move(continuing)); + return std::make_unique( + source, std::move(body.value), std::move(continuing)); }); } @@ -1745,49 +1741,49 @@ ForHeader::~ForHeader() = default; // SEMICOLON // logical_or_expression? SEMICOLON // (assignment_stmt | func_call_stmt)? -std::unique_ptr ParserImpl::expect_for_header() { +Expect> ParserImpl::expect_for_header() { std::unique_ptr initializer = nullptr; if (initializer == nullptr) { initializer = func_call_stmt(); if (has_error()) { - return nullptr; + return Failure::kErrored; } } if (initializer == nullptr) { initializer = variable_stmt(); if (has_error()) { - return nullptr; + return Failure::kErrored; } } if (initializer == nullptr) { initializer = assignment_stmt(); if (has_error()) { - return nullptr; + return Failure::kErrored; } } if (!expect("initializer in for loop", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; auto condition = logical_or_expression(); if (has_error()) { - return nullptr; + return Failure::kErrored; } if (!expect("condition in for loop", Token::Type::kSemicolon)) - return nullptr; + return Failure::kErrored; std::unique_ptr continuing = nullptr; if (continuing == nullptr) { continuing = func_call_stmt(); if (has_error()) { - return nullptr; + return Failure::kErrored; } } if (continuing == nullptr) { continuing = assignment_stmt(); if (has_error()) { - return nullptr; + return Failure::kErrored; } } @@ -1804,23 +1800,23 @@ std::unique_ptr ParserImpl::for_stmt() { auto header = expect_paren_block("for loop", [&] { return expect_for_header(); }); - if (header == nullptr) + if (header.errored) return nullptr; - auto body = expect_brace_block("for loop", [&] { return statements(); }); + auto body = + expect_brace_block("for loop", [&] { return expect_statements(); }); - if (body == nullptr) + if (body.errored) return nullptr; // The for statement is a syntactic sugar on top of the loop statement. // We create corresponding nodes in ast with the exact same behaviour // as we would expect from the loop statement. - - if (header->condition != nullptr) { + if (header.value->condition != nullptr) { // !condition auto not_condition = std::make_unique( - header->condition->source(), ast::UnaryOp::kNot, - std::move(header->condition)); + header.value->condition->source(), ast::UnaryOp::kNot, + std::move(header.value->condition)); // { break; } auto break_stmt = std::make_unique(not_condition->source()); @@ -1831,22 +1827,22 @@ std::unique_ptr ParserImpl::for_stmt() { auto break_if_not_condition = std::make_unique( not_condition->source(), std::move(not_condition), std::move(break_body)); - body->insert(0, std::move(break_if_not_condition)); + body.value->insert(0, std::move(break_if_not_condition)); } std::unique_ptr continuing_body = nullptr; - if (header->continuing != nullptr) { - continuing_body = - std::make_unique(header->continuing->source()); - continuing_body->append(std::move(header->continuing)); + if (header.value->continuing != nullptr) { + continuing_body = std::make_unique( + header.value->continuing->source()); + continuing_body->append(std::move(header.value->continuing)); } - auto loop = std::make_unique(source, std::move(body), - std::move(continuing_body)); + auto loop = std::make_unique( + source, std::move(body.value), std::move(continuing_body)); - if (header->initializer != nullptr) { + if (header.value->initializer != nullptr) { auto result = std::make_unique(source); - result->append(std::move(header->initializer)); + result->append(std::move(header.value->initializer)); result->append(std::move(loop)); return result; } @@ -1869,12 +1865,14 @@ std::unique_ptr ParserImpl::func_call_stmt() { auto name = t.to_str(); - t = peek(); ast::ExpressionList params; + + t = peek(); if (!t.IsParenRight() && !t.IsEof()) { - params = expect_argument_expression_list(); - if (has_error()) + auto list = expect_argument_expression_list(); + if (list.errored) return nullptr; + params = std::move(list.value); } if (!expect("call statement", Token::Type::kParenRight)) @@ -1912,7 +1910,7 @@ std::unique_ptr ParserImpl::continuing_stmt() { if (!match(Token::Type::kContinuing)) return std::make_unique(); - return expect_body_stmt(); + return expect_body_stmt().value; } // primary_expression @@ -1936,10 +1934,10 @@ std::unique_ptr ParserImpl::primary_expression() { t = peek(); if (t.IsParenLeft()) { auto paren = expect_paren_rhs_stmt(); - if (has_error()) + if (paren.errored) return nullptr; - return paren; + return std::move(paren.value); } if (t.IsBitcast()) { @@ -1968,11 +1966,11 @@ std::unique_ptr ParserImpl::primary_expression() { } auto params = expect_paren_rhs_stmt(); - if (has_error()) + if (params.errored) return nullptr; return std::make_unique(source, type, - std::move(params)); + std::move(params.value)); } else if (t.IsIdentifier()) { next(); // Consume the peek @@ -1983,24 +1981,26 @@ std::unique_ptr ParserImpl::primary_expression() { if (has_error()) return nullptr; if (type != nullptr) { - ast::ExpressionList params; + auto expr = expect_paren_block( + "type constructor", + [&]() -> Expect> { + t = peek(); + if (t.IsParenRight() || t.IsEof()) + return std::make_unique( + source, type, ast::ExpressionList{}); - auto ok = expect_paren_block("type constructor", [&] { - t = peek(); - if (!t.IsParenRight() && !t.IsEof()) { - params = expect_argument_expression_list(); - if (has_error()) - return false; - } - return true; - }); + auto params = expect_argument_expression_list(); + if (params.errored) + return Failure::kErrored; - if (!ok) { + return std::make_unique( + source, type, std::move(params.value)); + }); + + if (expr.errored) return nullptr; - } - return std::make_unique(source, type, - std::move(params)); + return std::move(expr.value); } return nullptr; } @@ -2038,12 +2038,14 @@ std::unique_ptr ParserImpl::postfix_expr( } else if (t.IsParenLeft()) { next(); // Consume the peek - t = peek(); ast::ExpressionList params; + + t = peek(); if (!t.IsParenRight() && !t.IsEof()) { - params = expect_argument_expression_list(); - if (has_error()) + auto list = expect_argument_expression_list(); + if (list.errored) return nullptr; + params = std::move(list.value); } if (!expect("call expression", Token::Type::kParenRight)) @@ -2054,13 +2056,13 @@ std::unique_ptr ParserImpl::postfix_expr( } else if (t.IsPeriod()) { next(); // Consume the peek - std::string ident; - if (!expect_ident("member accessor", &ident, &source)) + auto ident = expect_ident("member accessor"); + if (ident.errored) return nullptr; expr = std::make_unique( - source, std::move(prefix), - std::make_unique(source, ident)); + ident.source, std::move(prefix), + std::make_unique(ident.source, ident.value)); } else { return prefix; } @@ -2081,14 +2083,12 @@ std::unique_ptr ParserImpl::postfix_expression() { // argument_expression_list // : (logical_or_expression COMMA)* logical_or_expression -ast::ExpressionList ParserImpl::expect_argument_expression_list() { +Expect ParserImpl::expect_argument_expression_list() { auto arg = logical_or_expression(); if (has_error()) - return {}; - if (arg == nullptr) { - add_error(peek(), "unable to parse argument expression"); - return {}; - } + return Failure::kErrored; + if (arg == nullptr) + return add_error(peek(), "unable to parse argument expression"); ast::ExpressionList ret; ret.push_back(std::move(arg)); @@ -2096,10 +2096,10 @@ ast::ExpressionList ParserImpl::expect_argument_expression_list() { while (match(Token::Type::kComma)) { arg = logical_or_expression(); if (has_error()) - return {}; + return Failure::kErrored; if (arg == nullptr) { - add_error(peek(), "unable to parse argument expression after comma"); - return {}; + return add_error(peek(), + "unable to parse argument expression after comma"); } ret.push_back(std::move(arg)); } @@ -2141,7 +2141,7 @@ std::unique_ptr ParserImpl::unary_expression() { // | STAR unary_expression multiplicative_expr // | FORWARD_SLASH unary_expression multiplicative_expr // | MODULO unary_expression multiplicative_expr -std::unique_ptr ParserImpl::expect_multiplicative_expr( +Expect> ParserImpl::expect_multiplicative_expr( std::unique_ptr lhs) { auto t = peek(); @@ -2161,10 +2161,10 @@ std::unique_ptr ParserImpl::expect_multiplicative_expr( auto rhs = unary_expression(); if (has_error()) - return nullptr; + return Failure::kErrored; if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of " + name + " expression"); - return nullptr; + 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))); @@ -2179,14 +2179,14 @@ std::unique_ptr ParserImpl::multiplicative_expression() { if (lhs == nullptr) return nullptr; - return expect_multiplicative_expr(std::move(lhs)); + return expect_multiplicative_expr(std::move(lhs)).value; } // additive_expr // : // | PLUS multiplicative_expression additive_expr // | MINUS multiplicative_expression additive_expr -std::unique_ptr ParserImpl::expect_additive_expr( +Expect> ParserImpl::expect_additive_expr( std::unique_ptr lhs) { auto t = peek(); @@ -2203,11 +2203,9 @@ std::unique_ptr ParserImpl::expect_additive_expr( auto rhs = multiplicative_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of + expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2221,14 +2219,14 @@ std::unique_ptr ParserImpl::additive_expression() { if (lhs == nullptr) return nullptr; - return expect_additive_expr(std::move(lhs)); + return expect_additive_expr(std::move(lhs)).value; } // shift_expr // : // | LESS_THAN LESS_THAN additive_expression shift_expr // | GREATER_THAN GREATER_THAN additive_expression shift_expr -std::unique_ptr ParserImpl::expect_shift_expr( +Expect> ParserImpl::expect_shift_expr( std::unique_ptr lhs) { auto t = peek(); auto source = t.source(); @@ -2252,11 +2250,10 @@ std::unique_ptr ParserImpl::expect_shift_expr( auto rhs = additive_expression(); if (has_error()) - return nullptr; + return Failure::kErrored; if (rhs == nullptr) { - add_error(peek(), std::string("unable to parse right side of ") + name + - " expression"); - return nullptr; + 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))); @@ -2271,7 +2268,7 @@ std::unique_ptr ParserImpl::shift_expression() { if (lhs == nullptr) return nullptr; - return expect_shift_expr(std::move(lhs)); + return expect_shift_expr(std::move(lhs)).value; } // relational_expr @@ -2280,7 +2277,7 @@ std::unique_ptr ParserImpl::shift_expression() { // | GREATER_THAN shift_expression relational_expr // | LESS_THAN_EQUAL shift_expression relational_expr // | GREATER_THAN_EQUAL shift_expression relational_expr -std::unique_ptr ParserImpl::expect_relational_expr( +Expect> ParserImpl::expect_relational_expr( std::unique_ptr lhs) { auto t = peek(); ast::BinaryOp op = ast::BinaryOp::kNone; @@ -2301,11 +2298,12 @@ std::unique_ptr ParserImpl::expect_relational_expr( auto rhs = shift_expression(); if (has_error()) - return nullptr; + return Failure::kErrored; if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of " + name + " expression"); - return nullptr; + 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))); } @@ -2319,14 +2317,14 @@ std::unique_ptr ParserImpl::relational_expression() { if (lhs == nullptr) return nullptr; - return expect_relational_expr(std::move(lhs)); + return expect_relational_expr(std::move(lhs)).value; } // equality_expr // : // | EQUAL_EQUAL relational_expression equality_expr // | NOT_EQUAL relational_expression equality_expr -std::unique_ptr ParserImpl::expect_equality_expr( +Expect> ParserImpl::expect_equality_expr( std::unique_ptr lhs) { auto t = peek(); ast::BinaryOp op = ast::BinaryOp::kNone; @@ -2343,11 +2341,12 @@ std::unique_ptr ParserImpl::expect_equality_expr( auto rhs = relational_expression(); if (has_error()) - return nullptr; + return Failure::kErrored; if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of " + name + " expression"); - return nullptr; + 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))); } @@ -2361,13 +2360,13 @@ std::unique_ptr ParserImpl::equality_expression() { if (lhs == nullptr) return nullptr; - return expect_equality_expr(std::move(lhs)); + return expect_equality_expr(std::move(lhs)).value; } // and_expr // : // | AND equality_expression and_expr -std::unique_ptr ParserImpl::expect_and_expr( +Expect> ParserImpl::expect_and_expr( std::unique_ptr lhs) { auto t = peek(); if (!t.IsAnd()) @@ -2378,11 +2377,10 @@ std::unique_ptr ParserImpl::expect_and_expr( auto rhs = equality_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of & expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2396,13 +2394,13 @@ std::unique_ptr ParserImpl::and_expression() { if (lhs == nullptr) return nullptr; - return expect_and_expr(std::move(lhs)); + return expect_and_expr(std::move(lhs)).value; } // exclusive_or_expr // : // | XOR and_expression exclusive_or_expr -std::unique_ptr ParserImpl::expect_exclusive_or_expr( +Expect> ParserImpl::expect_exclusive_or_expr( std::unique_ptr lhs) { auto t = peek(); if (!t.IsXor()) @@ -2413,11 +2411,10 @@ std::unique_ptr ParserImpl::expect_exclusive_or_expr( auto rhs = and_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of ^ expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2431,13 +2428,13 @@ std::unique_ptr ParserImpl::exclusive_or_expression() { if (lhs == nullptr) return nullptr; - return expect_exclusive_or_expr(std::move(lhs)); + return expect_exclusive_or_expr(std::move(lhs)).value; } // inclusive_or_expr // : // | OR exclusive_or_expression inclusive_or_expr -std::unique_ptr ParserImpl::expect_inclusive_or_expr( +Expect> ParserImpl::expect_inclusive_or_expr( std::unique_ptr lhs) { auto t = peek(); if (!t.IsOr()) @@ -2448,11 +2445,10 @@ std::unique_ptr ParserImpl::expect_inclusive_or_expr( auto rhs = exclusive_or_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of | expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2466,13 +2462,13 @@ std::unique_ptr ParserImpl::inclusive_or_expression() { if (lhs == nullptr) return nullptr; - return expect_inclusive_or_expr(std::move(lhs)); + return expect_inclusive_or_expr(std::move(lhs)).value; } // logical_and_expr // : // | AND_AND inclusive_or_expression logical_and_expr -std::unique_ptr ParserImpl::expect_logical_and_expr( +Expect> ParserImpl::expect_logical_and_expr( std::unique_ptr lhs) { auto t = peek(); if (!t.IsAndAnd()) @@ -2483,11 +2479,10 @@ std::unique_ptr ParserImpl::expect_logical_and_expr( auto rhs = inclusive_or_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of && expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2501,13 +2496,13 @@ std::unique_ptr ParserImpl::logical_and_expression() { if (lhs == nullptr) return nullptr; - return expect_logical_and_expr(std::move(lhs)); + return expect_logical_and_expr(std::move(lhs)).value; } // logical_or_expr // : // | OR_OR logical_and_expression logical_or_expr -std::unique_ptr ParserImpl::expect_logical_or_expr( +Expect> ParserImpl::expect_logical_or_expr( std::unique_ptr lhs) { auto t = peek(); if (!t.IsOrOr()) @@ -2518,11 +2513,10 @@ std::unique_ptr ParserImpl::expect_logical_or_expr( auto rhs = logical_and_expression(); if (has_error()) - return nullptr; - if (rhs == nullptr) { - add_error(peek(), "unable to parse right side of || expression"); - return nullptr; - } + return Failure::kErrored; + if (rhs == nullptr) + 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))); } @@ -2536,7 +2530,7 @@ std::unique_ptr ParserImpl::logical_or_expression() { if (lhs == nullptr) return nullptr; - return expect_logical_or_expr(std::move(lhs)); + return expect_logical_or_expr(std::move(lhs)).value; } // assignment_stmt @@ -2603,51 +2597,52 @@ std::unique_ptr ParserImpl::const_literal() { // const_expr // : type_decl PAREN_LEFT (const_expr COMMA)? const_expr PAREN_RIGHT // | const_literal -std::unique_ptr ParserImpl::expect_const_expr() { +Expect> +ParserImpl::expect_const_expr() { return expect_const_expr_internal(0); } -std::unique_ptr +Expect> ParserImpl::expect_const_expr_internal(uint32_t depth) { auto t = peek(); if (depth > kMaxConstExprDepth) { - add_error(t, "max const_expr depth reached"); - return nullptr; + return add_error(t, "max const_expr depth reached"); } auto source = t.source(); auto* type = type_decl(); if (type != nullptr) { - ast::ExpressionList params; - bool ok = expect_paren_block("type constructor", [&] { - auto param = expect_const_expr_internal(depth + 1); - if (has_error()) - return false; - params.push_back(std::move(param)); - while (match(Token::Type::kComma)) { - param = expect_const_expr_internal(depth + 1); - if (has_error()) - return false; - params.push_back(std::move(param)); - } - return true; - }); + auto params = expect_paren_block( + "type constructor", [&]() -> Expect { + ast::ExpressionList list; + auto param = expect_const_expr_internal(depth + 1); + if (param.errored) + return Failure::kErrored; + list.emplace_back(std::move(param.value)); + while (match(Token::Type::kComma)) { + param = expect_const_expr_internal(depth + 1); + if (param.errored) + return Failure::kErrored; + list.emplace_back(std::move(param.value)); + } + return list; + }); - if (!ok) - return nullptr; + if (params.errored) + return Failure::kErrored; - return std::make_unique(source, type, - std::move(params)); + return std::make_unique( + source, type, std::move(params.value)); } auto lit = const_literal(); if (has_error()) - return nullptr; + return Failure::kErrored; if (lit == nullptr) { add_error(peek(), "unable to parse const literal"); - return nullptr; + return Failure::kErrored; } return std::make_unique(source, std::move(lit)); @@ -2672,11 +2667,11 @@ bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { } while (true) { - if (auto deco = expect_decoration()) { - decos.emplace_back(std::move(deco)); - } else { + auto deco = expect_decoration(); + if (deco.errored) return false; - } + + decos.emplace_back(std::move(deco.value)); if (match(Token::Type::kComma)) { continue; @@ -2694,85 +2689,94 @@ bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) { } } -std::unique_ptr ParserImpl::expect_decoration() { +Expect> ParserImpl::expect_decoration() { auto t = peek(); - if (auto deco = decoration()) { - return deco; - } - if (!has_error()) { - add_error(t, "expected decoration"); - } - return nullptr; + auto deco = decoration(); + if (has_error()) + return Failure::kErrored; + if (deco == nullptr) + return add_error(t, "expected decoration"); + return std::move(deco); } std::unique_ptr ParserImpl::decoration() { + using Result = std::unique_ptr; auto t = next(); if (t.IsLocation()) { const char* use = "location decoration"; - return expect_paren_block(use, [&]() { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, t.source()) - : nullptr; + return expect_paren_block_old(use, [&]() -> Result { + auto val = expect_positive_sint(use); + if (val.errored) + return nullptr; + + return std::make_unique(val.value, val.source); }); } if (t.IsBinding()) { const char* use = "binding decoration"; - return expect_paren_block(use, [&]() { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, t.source()) - : nullptr; + return expect_paren_block_old(use, [&]() -> Result { + auto val = expect_positive_sint(use); + if (val.errored) + return nullptr; + + return std::make_unique(val.value, val.source); }); } if (t.IsSet()) { const char* use = "set decoration"; - return expect_paren_block(use, [&]() { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique(val, t.source()) - : nullptr; + return expect_paren_block_old(use, [&]() -> Result { + auto val = expect_positive_sint(use); + if (val.errored) + return nullptr; + + return std::make_unique(val.value, val.source); }); } if (t.IsBuiltin()) { - return expect_paren_block("builtin decoration", [&]() { - ast::Builtin builtin; - Source source; - std::tie(builtin, source) = expect_builtin(); - return (builtin != ast::Builtin::kNone) - ? std::make_unique(builtin, source) - : nullptr; + return expect_paren_block_old("builtin decoration", [&]() -> Result { + auto builtin = expect_builtin(); + if (builtin.errored) + return nullptr; + + return std::make_unique(builtin.value, + builtin.source); }); } if (t.IsWorkgroupSize()) { - return expect_paren_block("workgroup_size decoration", [&]() { + return expect_paren_block_old("workgroup_size decoration", [&]() -> Result { uint32_t x; - if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) { - return std::unique_ptr(nullptr); - } uint32_t y = 1; uint32_t z = 1; + + auto val = expect_nonzero_positive_sint("workgroup_size x parameter"); + if (val.errored) + return nullptr; + x = val.value; + if (match(Token::Type::kComma)) { - if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) { - return std::unique_ptr(nullptr); - } + val = expect_nonzero_positive_sint("workgroup_size y parameter"); + if (val.errored) + return nullptr; + y = val.value; + if (match(Token::Type::kComma)) { - if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) { - return std::unique_ptr(nullptr); - } + val = expect_nonzero_positive_sint("workgroup_size z parameter"); + if (val.errored) + return nullptr; + z = val.value; } } + return std::make_unique(x, y, z, t.source()); }); } if (t.IsStage()) { - return expect_paren_block("stage decoration", [&]() { - ast::PipelineStage stage; - Source source; - std::tie(stage, source) = expect_pipeline_stage(); - return (stage != ast::PipelineStage::kNone) - ? std::make_unique(stage, source) - : nullptr; + return expect_paren_block_old("stage decoration", [&]() -> Result { + auto stage = expect_pipeline_stage(); + if (stage.errored) + return nullptr; + + return std::make_unique(stage.value, stage.source); }); } if (t.IsBlock()) { @@ -2780,29 +2784,32 @@ std::unique_ptr ParserImpl::decoration() { } if (t.IsStride()) { const char* use = "stride decoration"; - return expect_paren_block(use, [&]() { - uint32_t val; - bool ok = expect_nonzero_positive_sint(use, &val); - return ok ? std::make_unique(val, t.source()) - : nullptr; + return expect_paren_block_old(use, [&]() -> Result { + auto val = expect_nonzero_positive_sint(use); + if (val.errored) + return nullptr; + + return std::make_unique(val.value, t.source()); }); } if (t.IsOffset()) { const char* use = "offset decoration"; - return expect_paren_block(use, [&]() { - uint32_t val; - bool ok = expect_positive_sint(use, &val); - return ok ? std::make_unique( - val, t.source()) - : nullptr; + return expect_paren_block_old(use, [&]() -> Result { + auto val = expect_positive_sint(use); + if (val.errored) + return nullptr; + + return std::make_unique(val.value, + t.source()); }); } return nullptr; } template -std::vector> ParserImpl::cast_decorations( +Expect>> ParserImpl::cast_decorations( ast::DecorationList& in) { + bool ok = true; std::vector> out; out.reserve(in.size()); for (auto& deco : in) { @@ -2811,6 +2818,7 @@ std::vector> ParserImpl::cast_decorations( msg << deco->GetKind() << " decoration type cannot be used for " << T::Kind; add_error(deco->GetSource(), msg.str()); + ok = false; continue; } out.emplace_back(ast::As(std::move(deco))); @@ -2818,6 +2826,10 @@ std::vector> ParserImpl::cast_decorations( // clear in so that we can verify decorations were consumed with // expect_decorations_consumed() in.clear(); + + if (!ok) + return Failure::kErrored; + return out; } @@ -2856,67 +2868,51 @@ bool ParserImpl::expect(const std::string& use, Token::Type tok) { return true; } -bool ParserImpl::expect_sint(const std::string& use, int32_t* out) { - auto t = next(); - if (!t.IsSintLiteral()) { - add_error(t.source(), "expected signed integer literal", use); - return false; - } - *out = t.to_i32(); - return true; -} - -bool ParserImpl::expect_positive_sint(const std::string& use, uint32_t* out) { - auto t = peek(); - int32_t val; - if (!expect_sint(use, &val)) - return false; - - if (val < 0) { - add_error(t, use + " must be positive"); - return false; - } - *out = static_cast(val); - return true; -} - -bool ParserImpl::expect_nonzero_positive_sint(const std::string& use, - uint32_t* out) { - auto t = peek(); - int32_t val; - if (!expect_sint(use, &val)) - return false; - - if (val <= 0) { - add_error(t, use + " must be greater than 0"); - return false; - } - *out = static_cast(val); - return true; -} - -bool ParserImpl::expect_ident(const std::string& use, - std::string* out, - Source* source /* = nullptr */) { +Expect ParserImpl::expect_sint(const std::string& use) { auto t = next(); - if (source != nullptr) - *source = t.source(); + if (!t.IsSintLiteral()) + return add_error(t.source(), "expected signed integer literal", use); - if (!t.IsIdentifier()) { - add_error(t.source(), "expected identifier", use); - return false; - } + return {t.to_i32(), t.source()}; +} - *out = t.to_str(); - return true; +Expect ParserImpl::expect_positive_sint(const std::string& use) { + auto sint = expect_sint(use); + if (sint.errored) + return Failure::kErrored; + + if (sint.value < 0) + return add_error(sint.source, use + " must be positive"); + + return {static_cast(sint.value), sint.source}; +} + +Expect ParserImpl::expect_nonzero_positive_sint( + const std::string& use) { + auto sint = expect_sint(use); + if (sint.errored) + return Failure::kErrored; + + if (sint.value <= 0) + return add_error(sint.source, use + " must be greater than 0"); + + return {static_cast(sint.value), sint.source}; +} + +Expect ParserImpl::expect_ident(const std::string& use) { + auto t = next(); + if (!t.IsIdentifier()) + return add_error(t.source(), "expected identifier", use); + + return {t.to_str(), t.source()}; } template -T ParserImpl::expect_block(Token::Type start, - Token::Type end, - const std::string& use, - F&& body) { +T ParserImpl::expect_block_old(Token::Type start, + Token::Type end, + const std::string& use, + F&& body) { if (!expect(use, start)) { return {}; } @@ -2930,6 +2926,36 @@ T ParserImpl::expect_block(Token::Type start, return res; } +template +T ParserImpl::expect_block(Token::Type start, + Token::Type end, + const std::string& use, + F&& body) { + if (!expect(use, start)) { + return Failure::kErrored; + } + auto res = body(); + if (res.errored) { + return Failure::kErrored; + } + if (!expect(use, end)) { + return Failure::kErrored; + } + 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 5e1b941f5c..5bddd68ae8 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -15,6 +15,7 @@ #ifndef SRC_READER_WGSL_PARSER_IMPL_H_ #define SRC_READER_WGSL_PARSER_IMPL_H_ +#include #include #include #include @@ -79,7 +80,61 @@ struct ForHeader { /// ParserImpl for WGSL source data class ParserImpl { + /// Failure holds enumerator values used for the constructing an Expect in the + /// errored state. + struct Failure { + enum Errored { kErrored }; + }; + public: + /// Expect is the return type of the parser methods that are expected to + /// return a parsed value of type T, unless there was an parse error. + /// In the case of a parse error the called method will have called + /// |add_error()| and the Expect will have |errored| set to true. + template + struct Expect { + /// An alias to the templated type T. + using type = T; + + /// Don't allow an Expect to take a nullptr. + inline Expect(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 Expect(U&& val, const Source& s = {}) // NOLINT + : value(std::forward(val)), source(s) {} + + /// Constructor for parse error. + inline Expect(Failure::Errored) : errored(true) {} // NOLINT + + /// Copy constructor + inline Expect(const Expect&) = default; + /// Move constructor + inline Expect(Expect&&) = default; + /// Assignment operator + /// @return this Expect + inline Expect& operator=(const Expect&) = default; + /// Assignment move operator + /// @return this Expect + inline Expect& operator=(Expect&&) = default; + + /// @return a pointer to |value|. |errored| must be false to call. + inline T* operator->() { + assert(!errored); + return &value; + } + + /// The expected 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; + }; + /// TypedIdentifier holds a parsed identifier and type. Returned by /// variable_ident_decl(). struct TypedIdentifier { @@ -130,19 +185,25 @@ class ParserImpl { /// Appends an error at |t| with the message |msg| /// @param t the token to associate the error with /// @param msg the error message - void add_error(const Token& t, const std::string& msg); + /// @return |errored| so that you can combine an add_error call and return on + /// the same line. + Failure::Errored add_error(const Token& t, const std::string& msg); /// Appends an error raised when parsing |use| at |t| with the message |msg| /// @param source the source to associate the error with /// @param msg the error message /// @param use a description of what was being parsed when the error was /// raised. - void add_error(const Source& source, - const std::string& msg, - const std::string& use); + /// @return |errored| so that you can combine an add_error call and return on + /// the same line. + Failure::Errored add_error(const Source& source, + const std::string& msg, + const std::string& use); /// Appends an error at |source| with the message |msg| /// @param source the source to associate the error with /// @param msg the error message - void add_error(const Source& source, const std::string& msg); + /// @return |errored| so that you can combine an add_error call and return on + /// the same line. + Failure::Errored add_error(const Source& source, const std::string& msg); /// Registers a constructed type into the parser /// @param name the constructed name @@ -156,7 +217,8 @@ class ParserImpl { /// Parses the `translation_unit` grammar element void translation_unit(); /// Parses the `global_decl` grammar element, erroring on parse failure. - void expect_global_decl(); + /// @return true on parse success, otherwise an error. + Expect expect_global_decl(); /// Parses a `global_variable_decl` grammar element with the initial /// `variable_decoration_list*` provided as |decos|. /// @returns the variable parsed or nullptr @@ -173,7 +235,7 @@ class ParserImpl { /// failure. /// @param use a description of what was being parsed if an error was raised. /// @returns the identifier and type parsed or empty otherwise - TypedIdentifier expect_variable_ident_decl(const std::string& use); + 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(); @@ -183,10 +245,10 @@ class ParserImpl { /// Parses a `type_decl` grammar element /// @returns the parsed Type or nullptr if none matched. ast::type::Type* type_decl(); - /// Parses a `storage_class` grammar element - /// @param use a description of what was being parsed if an error was raised + /// 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 - ast::StorageClass expect_storage_class(const std::string& use); + Expect expect_storage_class(const std::string& use); /// Parses a `struct_decl` grammar element with the initial /// `struct_decoration_decl*` provided as |decos|. /// @returns the struct type or nullptr on error @@ -195,13 +257,13 @@ class ParserImpl { ast::DecorationList& decos); /// Parses a `struct_body_decl` grammar element, erroring on parse failure. /// @returns the struct members - ast::StructMemberList expect_struct_body_decl(); + Expect expect_struct_body_decl(); /// Parses a `struct_member` grammar element with the initial /// `struct_member_decoration_decl+` provided as |decos|, erroring on parse /// failure. /// @param decos the list of decorations for the struct member. /// @returns the struct member or nullptr - std::unique_ptr expect_struct_member( + Expect> expect_struct_member( ast::DecorationList& decos); /// Parses a `function_decl` grammar element with the initial /// `function_decoration_decl*` provided as |decos|. @@ -230,8 +292,10 @@ class ParserImpl { /// @returns the parsed Type or nullptr if none matched. ast::type::Type* depth_texture_type(); /// Parses a `image_storage_type` grammar element + /// @param use a description of what was being parsed if an error was raised. /// @returns returns the image format or kNone if none matched. - ast::type::ImageFormat image_storage_type(); + 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(); @@ -240,26 +304,24 @@ class ParserImpl { std::unique_ptr function_header(); /// Parses a `param_list` grammar element, erroring on parse failure. /// @returns the parsed variables - ast::VariableList expect_param_list(); + Expect expect_param_list(); /// Parses a `pipeline_stage` grammar element, erroring if the next token does /// not match a stage name. - /// @returns the pipeline stage or PipelineStage::kNone if none matched, along - /// with the source location for the stage. - std::pair expect_pipeline_stage(); + /// @returns the pipeline stage. + Expect expect_pipeline_stage(); /// Parses a builtin identifier, erroring if the next token does not match a /// valid builtin name. - /// @returns the builtin or Builtin::kNone if none matched, along with the - /// source location for the stage. - std::pair expect_builtin(); + /// @returns the parsed builtin. + Expect expect_builtin(); /// Parses a `body_stmt` grammar element, erroring on parse failure. /// @returns the parsed statements - std::unique_ptr expect_body_stmt(); + Expect> expect_body_stmt(); /// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure. /// @returns the parsed element or nullptr - std::unique_ptr expect_paren_rhs_stmt(); + Expect> expect_paren_rhs_stmt(); /// Parses a `statements` grammar element /// @returns the statements parsed - std::unique_ptr statements(); + Expect> expect_statements(); /// Parses a `statement` grammar element /// @returns the parsed statement or nullptr std::unique_ptr statement(); @@ -292,7 +354,7 @@ class ParserImpl { std::unique_ptr switch_body(); /// Parses a `case_selectors` grammar element /// @returns the list of literals - ast::CaseSelectorList case_selectors(); + Expect expect_case_selectors(); /// Parses a `case_body` grammar element /// @returns the parsed statements std::unique_ptr case_body(); @@ -304,7 +366,7 @@ class ParserImpl { std::unique_ptr loop_stmt(); /// Parses a `for_header` grammar element, erroring on parse failure. /// @returns the parsed for header or nullptr - std::unique_ptr expect_for_header(); + Expect> expect_for_header(); /// Parses a `for_stmt` grammar element /// @returns the parsed for loop or nullptr std::unique_ptr for_stmt(); @@ -316,14 +378,14 @@ class ParserImpl { std::unique_ptr const_literal(); /// Parses a `const_expr` grammar element, erroring on parse failure. /// @returns the parsed constructor expression or nullptr on error - std::unique_ptr expect_const_expr(); + Expect> expect_const_expr(); /// Parses a `primary_expression` grammar element /// @returns the parsed expression or nullptr std::unique_ptr primary_expression(); /// Parses a `argument_expression_list` grammar element, erroring on parse /// failure. /// @returns the list of arguments - ast::ExpressionList expect_argument_expression_list(); + Expect expect_argument_expression_list(); /// Parses the recursive portion of the postfix_expression /// @param prefix the left side of the expression /// @returns the parsed expression or nullptr @@ -339,7 +401,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_multiplicative_expr( + Expect> expect_multiplicative_expr( std::unique_ptr lhs); /// Parses the `multiplicative_expression` grammar element /// @returns the parsed expression or nullptr @@ -348,7 +410,7 @@ class ParserImpl { /// failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_additive_expr( + Expect> expect_additive_expr( std::unique_ptr lhs); /// Parses the `additive_expression` grammar element /// @returns the parsed expression or nullptr @@ -357,7 +419,7 @@ class ParserImpl { /// failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_shift_expr( + Expect> expect_shift_expr( std::unique_ptr lhs); /// Parses the `shift_expression` grammar element /// @returns the parsed expression or nullptr @@ -366,7 +428,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_relational_expr( + Expect> expect_relational_expr( std::unique_ptr lhs); /// Parses the `relational_expression` grammar element /// @returns the parsed expression or nullptr @@ -375,7 +437,7 @@ class ParserImpl { /// failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_equality_expr( + Expect> expect_equality_expr( std::unique_ptr lhs); /// Parses the `equality_expression` grammar element /// @returns the parsed expression or nullptr @@ -384,7 +446,7 @@ class ParserImpl { /// failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_and_expr( + Expect> expect_and_expr( std::unique_ptr lhs); /// Parses the `and_expression` grammar element /// @returns the parsed expression or nullptr @@ -393,7 +455,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_exclusive_or_expr( + Expect> expect_exclusive_or_expr( std::unique_ptr lhs); /// Parses the `exclusive_or_expression` grammar elememnt /// @returns the parsed expression or nullptr @@ -402,7 +464,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_inclusive_or_expr( + Expect> expect_inclusive_or_expr( std::unique_ptr lhs); /// Parses the `inclusive_or_expression` grammar element /// @returns the parsed expression or nullptr @@ -411,7 +473,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_logical_and_expr( + Expect> expect_logical_and_expr( std::unique_ptr lhs); /// Parses a `logical_and_expression` grammar element /// @returns the parsed expression or nullptr @@ -420,7 +482,7 @@ class ParserImpl { /// parse failure. /// @param lhs the left side of the expression /// @returns the parsed expression or nullptr - std::unique_ptr expect_logical_or_expr( + Expect> expect_logical_or_expr( std::unique_ptr lhs); /// Parses a `logical_or_expression` grammar element /// @returns the parsed expression or nullptr @@ -449,12 +511,16 @@ class ParserImpl { /// represent a decoration. /// @see #decoration for the full list of decorations this method parses. /// @return the parsed decoration, or nullptr on error. - std::unique_ptr expect_decoration(); + Expect> expect_decoration(); private: - /// ResultType resolves to the return type for the function or lambda F. + /// ReturnType resolves to the return type for the function or lambda F. template - using ResultType = typename std::result_of::type; + using ReturnType = typename std::result_of::type; + + /// ResultType resolves to |T| for a |RESULT| of type Expect. + template + using ResultType = typename RESULT::type; /// @returns true and consumes the next token if it equals |tok|. /// @param source if not nullptr, the next token's source is written to this @@ -470,33 +536,25 @@ class ParserImpl { /// next token is not a signed integer. /// Always consumes the next token. /// @param use a description of what was being parsed if an error was raised - /// @param out the pointer to write the parsed integer to - /// @returns true if the signed integer was parsed without error - bool expect_sint(const std::string& use, int32_t* out); + /// @returns the parsed integer. + Expect expect_sint(const std::string& use); /// Parses a signed integer from the next token in the stream, erroring if /// the next token is not a signed integer or is negative. /// Always consumes the next token. /// @param use a description of what was being parsed if an error was raised - /// @param out the pointer to write the parsed integer to - /// @returns true if the signed integer was parsed without error - bool expect_positive_sint(const std::string& use, uint32_t* out); + /// @returns the parsed integer. + Expect expect_positive_sint(const std::string& use); /// Parses a non-zero signed integer from the next token in the stream, /// erroring if the next token is not a signed integer or is less than 1. /// Always consumes the next token. /// @param use a description of what was being parsed if an error was raised - /// @param out the pointer to write the parsed integer to - /// @returns true if the signed integer was parsed without error - bool expect_nonzero_positive_sint(const std::string& use, uint32_t* out); + /// @returns the parsed integer. + Expect expect_nonzero_positive_sint(const std::string& use); /// Errors if the next token is not an identifier. /// Always consumes the next token. /// @param use a description of what was being parsed if an error was raised - /// @param out the pointer to write the parsed identifier to - /// @param source if not nullptr, the next token's source is written to this - /// pointer, regardless of success or error - /// @returns true if the identifier was parsed without error - bool expect_ident(const std::string& use, - std::string* out, - Source* source = nullptr); + /// @returns the parsed identifier. + Expect expect_ident(const std::string& use); /// Parses a lexical block starting with the token |start| and ending with /// the token |end|. |body| is called to parse the lexical block body between /// the |start| and |end| tokens. @@ -508,10 +566,10 @@ class ParserImpl { /// @param end the token that ends the lexical block /// @param use a description of what was being parsed if an error was raised /// @param body a function or lambda that is called to parse the lexical block - /// body, with the signature T(). + /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise /// a zero-initialized |T|. - template > + template > T expect_block(Token::Type start, Token::Type end, const std::string& use, @@ -521,36 +579,53 @@ class ParserImpl { /// and |end| arguments, respectively. /// @param use a description of what was being parsed if an error was raised /// @param body a function or lambda that is called to parse the lexical block - /// body, with the signature T(). + /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise /// a zero-initialized |T|. - template > + template > T expect_paren_block(const std::string& use, F&& body); /// A convenience function that calls |expect_block| passing /// |Token::Type::kBraceLeft| and |Token::Type::kBraceRight| for the |start| /// and |end| arguments, respectively. /// @param use a description of what was being parsed if an error was raised /// @param body a function or lambda that is called to parse the lexical block - /// body, with the signature T(). + /// body, with the signature: `Expect()`. /// @return the value returned by |body| if no errors are raised, otherwise /// a zero-initialized |T|. - template > + 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 - std::vector> cast_decorations(ast::DecorationList& in); + Expect>> cast_decorations( + ast::DecorationList& in); /// Reports an error if the decoration list |list| is not empty. /// Used to ensure that all decorations are consumed. bool expect_decorations_consumed(const ast::DecorationList& list); - ast::type::Type* expect_type_decl_pointer(); - ast::type::Type* expect_type_decl_vector(Token t); - ast::type::Type* expect_type_decl_array(ast::ArrayDecorationList decos); - ast::type::Type* expect_type_decl_matrix(Token t); + Expect expect_type_decl_pointer(); + Expect expect_type_decl_vector(Token t); + Expect expect_type_decl_array( + ast::ArrayDecorationList decos); + Expect expect_type_decl_matrix(Token t); - std::unique_ptr expect_const_expr_internal( - uint32_t depth); + Expect> + expect_const_expr_internal(uint32_t depth); Context& ctx_; diag::List diags_; diff --git a/src/reader/wgsl/parser_impl_argument_expression_list_test.cc b/src/reader/wgsl/parser_impl_argument_expression_list_test.cc index 78007b10a5..6302c8e345 100644 --- a/src/reader/wgsl/parser_impl_argument_expression_list_test.cc +++ b/src/reader/wgsl/parser_impl_argument_expression_list_test.cc @@ -30,26 +30,29 @@ TEST_F(ParserImplTest, ArgumentExpressionList_Parses) { auto* p = parser("a"); auto e = p->expect_argument_expression_list(); ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(e.errored); - ASSERT_EQ(e.size(), 1u); - ASSERT_TRUE(e[0]->IsIdentifier()); + ASSERT_EQ(e.value.size(), 1u); + ASSERT_TRUE(e.value[0]->IsIdentifier()); } TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) { auto* p = parser("a, -33, 1+2"); auto e = p->expect_argument_expression_list(); ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_FALSE(e.errored); - ASSERT_EQ(e.size(), 3u); - ASSERT_TRUE(e[0]->IsIdentifier()); - ASSERT_TRUE(e[1]->IsConstructor()); - ASSERT_TRUE(e[2]->IsBinary()); + ASSERT_EQ(e.value.size(), 3u); + ASSERT_TRUE(e.value[0]->IsIdentifier()); + ASSERT_TRUE(e.value[1]->IsConstructor()); + ASSERT_TRUE(e.value[2]->IsBinary()); } TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) { auto* p = parser("a, "); auto e = p->expect_argument_expression_list(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:4: unable to parse argument expression after comma"); } @@ -57,6 +60,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) { auto* p = parser("if(a) {}"); auto e = p->expect_argument_expression_list(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:1: unable to parse argument expression"); } diff --git a/src/reader/wgsl/parser_impl_body_stmt_test.cc b/src/reader/wgsl/parser_impl_body_stmt_test.cc index 6451de591c..4a3b5a0814 100644 --- a/src/reader/wgsl/parser_impl_body_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_body_stmt_test.cc @@ -28,22 +28,25 @@ TEST_F(ParserImplTest, BodyStmt) { })"); auto e = p->expect_body_stmt(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 2u); - EXPECT_TRUE(e->get(0)->IsDiscard()); - EXPECT_TRUE(e->get(1)->IsReturn()); + ASSERT_FALSE(e.errored); + ASSERT_EQ(e.value->size(), 2u); + EXPECT_TRUE(e.value->get(0)->IsDiscard()); + EXPECT_TRUE(e.value->get(1)->IsReturn()); } TEST_F(ParserImplTest, BodyStmt_Empty) { auto* p = parser("{}"); auto e = p->expect_body_stmt(); ASSERT_FALSE(p->has_error()) << p->error(); - EXPECT_EQ(e->size(), 0u); + ASSERT_FALSE(e.errored); + EXPECT_EQ(e.value->size(), 0u); } TEST_F(ParserImplTest, BodyStmt_InvalidStmt) { auto* p = parser("{fn main() -> void {}}"); auto e = p->expect_body_stmt(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:2: expected '}'"); } @@ -51,6 +54,7 @@ TEST_F(ParserImplTest, BodyStmt_MissingRightParen) { auto* p = parser("{return;"); auto e = p->expect_body_stmt(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:9: expected '}'"); } diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc index 5d427dc8d7..14b716fe13 100644 --- a/src/reader/wgsl/parser_impl_const_expr_test.cc +++ b/src/reader/wgsl/parser_impl_const_expr_test.cc @@ -30,11 +30,11 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) { auto* p = parser("vec2(1., 2.)"); auto e = p->expect_const_expr(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); + ASSERT_FALSE(e.errored); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor()); - auto* t = e->AsConstructor()->AsTypeConstructor(); + auto* t = e.value->AsConstructor()->AsTypeConstructor(); ASSERT_TRUE(t->type()->IsVector()); EXPECT_EQ(t->type()->AsVector()->size(), 2u); @@ -58,7 +58,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) { auto* p = parser("vec2(1., 2."); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor"); } @@ -66,7 +67,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) { auto* p = parser("vec2 1., 2.)"); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor"); } @@ -74,7 +76,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_HangingComma) { auto* p = parser("vec2(1.,)"); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:14: unable to parse const literal"); } @@ -82,7 +85,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) { auto* p = parser("vec2(1. 2."); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor"); } @@ -90,7 +94,8 @@ TEST_F(ParserImplTest, ConstExpr_MissingExpr) { auto* p = parser("vec2()"); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:11: unable to parse const literal"); } @@ -98,7 +103,8 @@ TEST_F(ParserImplTest, ConstExpr_InvalidExpr) { auto* p = parser("vec2(1., if(a) {})"); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:15: unable to parse const literal"); } @@ -106,10 +112,11 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral) { auto* p = parser("true"); auto e = p->expect_const_expr(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsConstructor()); - ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor()); - auto* c = e->AsConstructor()->AsScalarConstructor(); + ASSERT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsConstructor()); + ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor()); + auto* c = e.value->AsConstructor()->AsScalarConstructor(); ASSERT_TRUE(c->literal()->IsBool()); EXPECT_TRUE(c->literal()->AsBool()->IsTrue()); } @@ -118,7 +125,8 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) { auto* p = parser("invalid"); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:1: unknown constructed type 'invalid'"); } @@ -134,7 +142,8 @@ TEST_F(ParserImplTest, ConstExpr_Recursion) { auto* p = parser(out.str()); auto e = p->expect_const_expr(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:517: max const_expr depth reached"); } diff --git a/src/reader/wgsl/parser_impl_for_stmt_test.cc b/src/reader/wgsl/parser_impl_for_stmt_test.cc index a8a81288ac..3520a58ad2 100644 --- a/src/reader/wgsl/parser_impl_for_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_for_stmt_test.cc @@ -27,16 +27,18 @@ class ForStmtTest : public ParserImplTest { public: void TestForLoop(std::string loop_str, std::string for_str) { auto* p_loop = parser(loop_str); - auto e_loop = p_loop->statements(); - ASSERT_FALSE(p_loop->has_error()) << p_loop->error(); - ASSERT_NE(e_loop, nullptr); + auto e_loop = p_loop->expect_statements(); + EXPECT_FALSE(e_loop.errored); + EXPECT_FALSE(p_loop->has_error()) << p_loop->error(); + ASSERT_NE(e_loop.value, nullptr); auto* p_for = parser(for_str); - auto e_for = p_for->statements(); - ASSERT_FALSE(p_for->has_error()) << p_for->error(); - ASSERT_NE(e_for, nullptr); + auto e_for = p_for->expect_statements(); + EXPECT_FALSE(e_for.errored); + EXPECT_FALSE(p_for->has_error()) << p_for->error(); + ASSERT_NE(e_for.value, nullptr); - EXPECT_EQ(e_loop->str(), e_for->str()); + EXPECT_EQ(e_loop.value->str(), e_for.value->str()); } }; diff --git a/src/reader/wgsl/parser_impl_image_storage_type_test.cc b/src/reader/wgsl/parser_impl_image_storage_type_test.cc index 0caed67ea4..f454a3bc17 100644 --- a/src/reader/wgsl/parser_impl_image_storage_type_test.cc +++ b/src/reader/wgsl/parser_impl_image_storage_type_test.cc @@ -24,253 +24,289 @@ namespace { TEST_F(ParserImplTest, ImageStorageType_Invalid) { auto* p = parser("1234"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kNone); - EXPECT_FALSE(p->has_error()); + auto t = p->expect_image_storage_type("test"); + EXPECT_TRUE(t.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:1: invalid format for test"); } TEST_F(ParserImplTest, ImageStorageType_R8Unorm) { auto* p = parser("r8unorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR8Unorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Unorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R8Snorm) { auto* p = parser("r8snorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR8Snorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Snorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R8Uint) { auto* p = parser("r8uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR8Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R8Sint) { auto* p = parser("r8sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR8Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R16Uint) { auto* p = parser("r16uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR16Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R16Sint) { auto* p = parser("r16sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR16Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R16Float) { auto* p = parser("r16float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR16Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg8Unorm) { auto* p = parser("rg8unorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg8Unorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Unorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg8Snorm) { auto* p = parser("rg8snorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg8Snorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Snorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg8Uint) { auto* p = parser("rg8uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg8Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg8Sint) { auto* p = parser("rg8sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg8Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R32Uint) { auto* p = parser("r32uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR32Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R32Sint) { auto* p = parser("r32sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR32Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_R32Float) { auto* p = parser("r32float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kR32Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg16Uint) { auto* p = parser("rg16uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg16Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg16Sint) { auto* p = parser("rg16sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg16Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg16Float) { auto* p = parser("rg16float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg16Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba8Unorm) { auto* p = parser("rgba8unorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Unorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Unorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba8UnormSrgb) { auto* p = parser("rgba8unorm_srgb"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba8UnormSrgb); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8UnormSrgb); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba8Snorm) { auto* p = parser("rgba8snorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Snorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Snorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba8Uint) { auto* p = parser("rgba8uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba8Sint) { auto* p = parser("rgba8sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Bgra8Unorm) { auto* p = parser("bgra8unorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kBgra8Unorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kBgra8Unorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Bgra8UnormSrgb) { auto* p = parser("bgra8unorm_srgb"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kBgra8UnormSrgb); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kBgra8UnormSrgb); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgb10A2Unorm) { auto* p = parser("rgb10a2unorm"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgb10A2Unorm); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgb10A2Unorm); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg11B10Float) { auto* p = parser("rg11b10float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg11B10Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg11B10Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg32Uint) { auto* p = parser("rg32uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg32Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg32Sint) { auto* p = parser("rg32sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg32Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rg32Float) { auto* p = parser("rg32float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRg32Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba16Uint) { auto* p = parser("rgba16uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba16Sint) { auto* p = parser("rgba16sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba16Float) { auto* p = parser("rgba16float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Float); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba32Uint) { auto* p = parser("rgba32uint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Uint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Uint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba32Sint) { auto* p = parser("rgba32sint"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Sint); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Sint); EXPECT_FALSE(p->has_error()); } TEST_F(ParserImplTest, ImageStorageType_Rgba32Float) { auto* p = parser("rgba32float"); - auto t = p->image_storage_type(); - EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Float); + auto t = p->expect_image_storage_type("test"); + EXPECT_FALSE(t.errored); + EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Float); EXPECT_FALSE(p->has_error()); } diff --git a/src/reader/wgsl/parser_impl_param_list_test.cc b/src/reader/wgsl/parser_impl_param_list_test.cc index 1711106057..03eea45060 100644 --- a/src/reader/wgsl/parser_impl_param_list_test.cc +++ b/src/reader/wgsl/parser_impl_param_list_test.cc @@ -34,16 +34,17 @@ TEST_F(ParserImplTest, ParamList_Single) { auto* p = parser("a : i32"); auto e = p->expect_param_list(); ASSERT_FALSE(p->has_error()) << p->error(); - EXPECT_EQ(e.size(), 1u); + ASSERT_FALSE(e.errored); + EXPECT_EQ(e.value.size(), 1u); - EXPECT_EQ(e[0]->name(), "a"); - EXPECT_EQ(e[0]->type(), i32); - EXPECT_TRUE(e[0]->is_const()); + EXPECT_EQ(e.value[0]->name(), "a"); + EXPECT_EQ(e.value[0]->type(), i32); + EXPECT_TRUE(e.value[0]->is_const()); - ASSERT_EQ(e[0]->source().range.begin.line, 1u); - ASSERT_EQ(e[0]->source().range.begin.column, 1u); - ASSERT_EQ(e[0]->source().range.end.line, 1u); - ASSERT_EQ(e[0]->source().range.end.column, 2u); + ASSERT_EQ(e.value[0]->source().range.begin.line, 1u); + ASSERT_EQ(e.value[0]->source().range.begin.column, 1u); + ASSERT_EQ(e.value[0]->source().range.end.line, 1u); + ASSERT_EQ(e.value[0]->source().range.end.column, 2u); } TEST_F(ParserImplTest, ParamList_Multiple) { @@ -54,47 +55,50 @@ TEST_F(ParserImplTest, ParamList_Multiple) { auto* p = parser("a : i32, b: f32, c: vec2"); auto e = p->expect_param_list(); ASSERT_FALSE(p->has_error()) << p->error(); - EXPECT_EQ(e.size(), 3u); + ASSERT_FALSE(e.errored); + EXPECT_EQ(e.value.size(), 3u); - EXPECT_EQ(e[0]->name(), "a"); - EXPECT_EQ(e[0]->type(), i32); - EXPECT_TRUE(e[0]->is_const()); + EXPECT_EQ(e.value[0]->name(), "a"); + EXPECT_EQ(e.value[0]->type(), i32); + EXPECT_TRUE(e.value[0]->is_const()); - ASSERT_EQ(e[0]->source().range.begin.line, 1u); - ASSERT_EQ(e[0]->source().range.begin.column, 1u); - ASSERT_EQ(e[0]->source().range.end.line, 1u); - ASSERT_EQ(e[0]->source().range.end.column, 2u); + ASSERT_EQ(e.value[0]->source().range.begin.line, 1u); + ASSERT_EQ(e.value[0]->source().range.begin.column, 1u); + ASSERT_EQ(e.value[0]->source().range.end.line, 1u); + ASSERT_EQ(e.value[0]->source().range.end.column, 2u); - EXPECT_EQ(e[1]->name(), "b"); - EXPECT_EQ(e[1]->type(), f32); - EXPECT_TRUE(e[1]->is_const()); + EXPECT_EQ(e.value[1]->name(), "b"); + EXPECT_EQ(e.value[1]->type(), f32); + EXPECT_TRUE(e.value[1]->is_const()); - ASSERT_EQ(e[1]->source().range.begin.line, 1u); - ASSERT_EQ(e[1]->source().range.begin.column, 10u); - ASSERT_EQ(e[1]->source().range.end.line, 1u); - ASSERT_EQ(e[1]->source().range.end.column, 11u); + ASSERT_EQ(e.value[1]->source().range.begin.line, 1u); + ASSERT_EQ(e.value[1]->source().range.begin.column, 10u); + ASSERT_EQ(e.value[1]->source().range.end.line, 1u); + ASSERT_EQ(e.value[1]->source().range.end.column, 11u); - EXPECT_EQ(e[2]->name(), "c"); - EXPECT_EQ(e[2]->type(), vec2); - EXPECT_TRUE(e[2]->is_const()); + EXPECT_EQ(e.value[2]->name(), "c"); + EXPECT_EQ(e.value[2]->type(), vec2); + EXPECT_TRUE(e.value[2]->is_const()); - ASSERT_EQ(e[2]->source().range.begin.line, 1u); - ASSERT_EQ(e[2]->source().range.begin.column, 18u); - ASSERT_EQ(e[2]->source().range.end.line, 1u); - ASSERT_EQ(e[2]->source().range.end.column, 19u); + ASSERT_EQ(e.value[2]->source().range.begin.line, 1u); + ASSERT_EQ(e.value[2]->source().range.begin.column, 18u); + ASSERT_EQ(e.value[2]->source().range.end.line, 1u); + ASSERT_EQ(e.value[2]->source().range.end.column, 19u); } TEST_F(ParserImplTest, ParamList_Empty) { auto* p = parser(""); auto e = p->expect_param_list(); ASSERT_FALSE(p->has_error()); - EXPECT_EQ(e.size(), 0u); + ASSERT_FALSE(e.errored); + EXPECT_EQ(e.value.size(), 0u); } TEST_F(ParserImplTest, ParamList_HangingComma) { auto* p = parser("a : i32,"); auto e = p->expect_param_list(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); EXPECT_EQ(p->error(), "1:9: expected identifier for parameter"); } diff --git a/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc b/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc index 9360f7e6da..e55bc8900b 100644 --- a/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc +++ b/src/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc @@ -25,15 +25,17 @@ TEST_F(ParserImplTest, ParenRhsStmt) { auto* p = parser("(a + b)"); auto e = p->expect_paren_rhs_stmt(); ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_NE(e, nullptr); - ASSERT_TRUE(e->IsBinary()); + ASSERT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + ASSERT_TRUE(e.value->IsBinary()); } TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) { auto* p = parser("true)"); auto e = p->expect_paren_rhs_stmt(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:1: expected '('"); } @@ -41,7 +43,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) { auto* p = parser("(true"); auto e = p->expect_paren_rhs_stmt(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:6: expected ')'"); } @@ -49,7 +52,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) { auto* p = parser("(if (a() {})"); auto e = p->expect_paren_rhs_stmt(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:2: unable to parse expression"); } @@ -57,7 +61,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) { auto* p = parser("()"); auto e = p->expect_paren_rhs_stmt(); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(e, nullptr); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); EXPECT_EQ(p->error(), "1:2: unable to parse expression"); } diff --git a/src/reader/wgsl/parser_impl_pipeline_stage_test.cc b/src/reader/wgsl/parser_impl_pipeline_stage_test.cc index 0fcffc44be..4cae54e206 100644 --- a/src/reader/wgsl/parser_impl_pipeline_stage_test.cc +++ b/src/reader/wgsl/parser_impl_pipeline_stage_test.cc @@ -36,15 +36,14 @@ TEST_P(PipelineStageTest, Parses) { auto params = GetParam(); auto* p = parser(params.input); - ast::PipelineStage stage; - Source source; - std::tie(stage, source) = p->expect_pipeline_stage(); + auto stage = p->expect_pipeline_stage(); ASSERT_FALSE(p->has_error()) << p->error(); - EXPECT_EQ(stage, params.result); - EXPECT_EQ(source.range.begin.line, 1u); - EXPECT_EQ(source.range.begin.column, 1u); - EXPECT_EQ(source.range.end.line, 1u); - EXPECT_EQ(source.range.end.column, 1u + params.input.size()); + ASSERT_FALSE(stage.errored); + EXPECT_EQ(stage.value, params.result); + EXPECT_EQ(stage.source.range.begin.line, 1u); + EXPECT_EQ(stage.source.range.begin.column, 1u); + EXPECT_EQ(stage.source.range.end.line, 1u); + EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size()); auto t = p->next(); EXPECT_TRUE(t.IsEof()); @@ -59,16 +58,10 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(ParserImplTest, PipelineStage_NoMatch) { auto* p = parser("not-a-stage"); - ast::PipelineStage stage; - Source source; - std::tie(stage, source) = p->expect_pipeline_stage(); + auto stage = p->expect_pipeline_stage(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(stage.errored); ASSERT_EQ(p->error(), "1:1: invalid value for stage decoration"); - ASSERT_EQ(stage, ast::PipelineStage::kNone); - EXPECT_EQ(source.range.begin.line, 1u); - EXPECT_EQ(source.range.begin.column, 1u); - EXPECT_EQ(source.range.end.line, 1u); - EXPECT_EQ(source.range.end.column, 4u); } } // namespace diff --git a/src/reader/wgsl/parser_impl_statements_test.cc b/src/reader/wgsl/parser_impl_statements_test.cc index a22e6566ef..c7417e9395 100644 --- a/src/reader/wgsl/parser_impl_statements_test.cc +++ b/src/reader/wgsl/parser_impl_statements_test.cc @@ -24,18 +24,20 @@ namespace { TEST_F(ParserImplTest, Statements) { auto* p = parser("discard; return;"); - auto e = p->statements(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 2u); - EXPECT_TRUE(e->get(0)->IsDiscard()); - EXPECT_TRUE(e->get(1)->IsReturn()); + auto e = p->expect_statements(); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value->size(), 2u); + EXPECT_TRUE(e.value->get(0)->IsDiscard()); + EXPECT_TRUE(e.value->get(1)->IsReturn()); } TEST_F(ParserImplTest, Statements_Empty) { auto* p = parser(""); - auto e = p->statements(); - ASSERT_FALSE(p->has_error()) << p->error(); - ASSERT_EQ(e->size(), 0u); + auto e = p->expect_statements(); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value->size(), 0u); } } // namespace diff --git a/src/reader/wgsl/parser_impl_storage_class_test.cc b/src/reader/wgsl/parser_impl_storage_class_test.cc index bca0a666d7..2945512324 100644 --- a/src/reader/wgsl/parser_impl_storage_class_test.cc +++ b/src/reader/wgsl/parser_impl_storage_class_test.cc @@ -38,8 +38,9 @@ TEST_P(StorageClassTest, Parses) { auto* p = parser(params.input); auto sc = p->expect_storage_class("test"); - ASSERT_FALSE(p->has_error()); - EXPECT_EQ(sc, params.result); + EXPECT_FALSE(sc.errored); + EXPECT_FALSE(p->has_error()); + EXPECT_EQ(sc.value, params.result); auto t = p->next(); EXPECT_TRUE(t.IsEof()); @@ -62,8 +63,8 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(ParserImplTest, StorageClass_NoMatch) { auto* p = parser("not-a-storage-class"); auto sc = p->expect_storage_class("test"); - ASSERT_EQ(sc, ast::StorageClass::kNone); - ASSERT_TRUE(p->has_error()); + EXPECT_EQ(sc.errored, true); + EXPECT_TRUE(p->has_error()); EXPECT_EQ(p->error(), "1:1: invalid storage class for test"); auto t = p->next(); diff --git a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc index 7e8d7d24ea..f46cc30d94 100644 --- a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc +++ b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc @@ -29,9 +29,10 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) { auto* p = parser("{a : i32;}"); auto m = p->expect_struct_body_decl(); ASSERT_FALSE(p->has_error()); - ASSERT_EQ(m.size(), 1u); + ASSERT_FALSE(m.errored); + ASSERT_EQ(m.value.size(), 1u); - const auto& mem = m[0]; + const auto& mem = m.value[0]; EXPECT_EQ(mem->name(), "a"); EXPECT_EQ(mem->type(), i32); EXPECT_EQ(mem->decorations().size(), 0u); @@ -41,7 +42,8 @@ TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) { auto* p = parser("{}"); auto m = p->expect_struct_body_decl(); ASSERT_FALSE(p->has_error()); - ASSERT_EQ(m.size(), 0u); + ASSERT_FALSE(m.errored); + ASSERT_EQ(m.value.size(), 0u); } TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) { @@ -51,6 +53,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) { })"); auto m = p->expect_struct_body_decl(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(m.errored); EXPECT_EQ(p->error(), "3:12: expected signed integer literal for offset decoration"); } @@ -59,6 +62,7 @@ TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) { auto* p = parser("{a : i32;"); auto m = p->expect_struct_body_decl(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(m.errored); EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration"); } @@ -70,6 +74,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) { } )"); auto m = p->expect_struct_body_decl(); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(m.errored); EXPECT_EQ(p->error(), "4:3: expected identifier for struct member"); } diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc index 186e0f01f4..563ece6a87 100644 --- a/src/reader/wgsl/parser_impl_struct_member_test.cc +++ b/src/reader/wgsl/parser_impl_struct_member_test.cc @@ -32,16 +32,17 @@ TEST_F(ParserImplTest, StructMember_Parses) { EXPECT_EQ(decos.size(), 0u); auto m = p->expect_struct_member(decos); ASSERT_FALSE(p->has_error()); - ASSERT_NE(m, nullptr); + ASSERT_FALSE(m.errored); + ASSERT_NE(m.value, nullptr); - EXPECT_EQ(m->name(), "a"); - EXPECT_EQ(m->type(), i32); - EXPECT_EQ(m->decorations().size(), 0u); + EXPECT_EQ(m.value->name(), "a"); + EXPECT_EQ(m.value->type(), i32); + EXPECT_EQ(m.value->decorations().size(), 0u); - ASSERT_EQ(m->source().range.begin.line, 1u); - ASSERT_EQ(m->source().range.begin.column, 1u); - ASSERT_EQ(m->source().range.end.line, 1u); - ASSERT_EQ(m->source().range.end.column, 2u); + ASSERT_EQ(m.value->source().range.begin.line, 1u); + ASSERT_EQ(m.value->source().range.begin.column, 1u); + ASSERT_EQ(m.value->source().range.end.line, 1u); + ASSERT_EQ(m.value->source().range.end.column, 2u); } TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { @@ -52,18 +53,19 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { EXPECT_EQ(decos.size(), 1u); auto m = p->expect_struct_member(decos); ASSERT_FALSE(p->has_error()); - ASSERT_NE(m, nullptr); + ASSERT_FALSE(m.errored); + ASSERT_NE(m.value, nullptr); - EXPECT_EQ(m->name(), "a"); - EXPECT_EQ(m->type(), i32); - EXPECT_EQ(m->decorations().size(), 1u); - EXPECT_TRUE(m->decorations()[0]->IsOffset()); - EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); + EXPECT_EQ(m.value->name(), "a"); + EXPECT_EQ(m.value->type(), i32); + EXPECT_EQ(m.value->decorations().size(), 1u); + EXPECT_TRUE(m.value->decorations()[0]->IsOffset()); + EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u); - ASSERT_EQ(m->source().range.begin.line, 1u); - ASSERT_EQ(m->source().range.begin.column, 15u); - ASSERT_EQ(m->source().range.end.line, 1u); - ASSERT_EQ(m->source().range.end.column, 16u); + ASSERT_EQ(m.value->source().range.begin.line, 1u); + ASSERT_EQ(m.value->source().range.begin.column, 15u); + ASSERT_EQ(m.value->source().range.end.line, 1u); + ASSERT_EQ(m.value->source().range.end.column, 16u); } TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { @@ -75,20 +77,21 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { EXPECT_EQ(decos.size(), 2u); auto m = p->expect_struct_member(decos); ASSERT_FALSE(p->has_error()); - ASSERT_NE(m, nullptr); + ASSERT_FALSE(m.errored); + ASSERT_NE(m.value, nullptr); - EXPECT_EQ(m->name(), "a"); - EXPECT_EQ(m->type(), i32); - EXPECT_EQ(m->decorations().size(), 2u); - EXPECT_TRUE(m->decorations()[0]->IsOffset()); - EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); - EXPECT_TRUE(m->decorations()[1]->IsOffset()); - EXPECT_EQ(m->decorations()[1]->AsOffset()->offset(), 4u); + EXPECT_EQ(m.value->name(), "a"); + EXPECT_EQ(m.value->type(), i32); + EXPECT_EQ(m.value->decorations().size(), 2u); + EXPECT_TRUE(m.value->decorations()[0]->IsOffset()); + EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u); + EXPECT_TRUE(m.value->decorations()[1]->IsOffset()); + EXPECT_EQ(m.value->decorations()[1]->AsOffset()->offset(), 4u); - ASSERT_EQ(m->source().range.begin.line, 2u); - ASSERT_EQ(m->source().range.begin.column, 15u); - ASSERT_EQ(m->source().range.end.line, 2u); - ASSERT_EQ(m->source().range.end.column, 16u); + ASSERT_EQ(m.value->source().range.begin.line, 2u); + ASSERT_EQ(m.value->source().range.begin.column, 15u); + ASSERT_EQ(m.value->source().range.end.line, 2u); + ASSERT_EQ(m.value->source().range.end.column, 16u); } TEST_F(ParserImplTest, StructMember_InvalidDecoration) { @@ -96,7 +99,8 @@ TEST_F(ParserImplTest, StructMember_InvalidDecoration) { auto decos = p->decoration_list(); auto m = p->expect_struct_member(decos); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(m, nullptr); + ASSERT_TRUE(m.errored); + ASSERT_EQ(m.value, nullptr); EXPECT_EQ(p->error(), "1:10: expected signed integer literal for offset decoration"); } @@ -106,7 +110,8 @@ TEST_F(ParserImplTest, StructMember_InvalidVariable) { auto decos = p->decoration_list(); auto m = p->expect_struct_member(decos); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(m, nullptr); + ASSERT_TRUE(m.errored); + ASSERT_EQ(m.value, nullptr); EXPECT_EQ(p->error(), "1:19: unknown constructed type 'B'"); } @@ -115,7 +120,8 @@ TEST_F(ParserImplTest, StructMember_MissingSemicolon) { auto decos = p->decoration_list(); auto m = p->expect_struct_member(decos); ASSERT_TRUE(p->has_error()); - ASSERT_EQ(m, nullptr); + ASSERT_TRUE(m.errored); + ASSERT_EQ(m.value, nullptr); EXPECT_EQ(p->error(), "1:8: expected ';' for struct member"); } diff --git a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc index f9eb7a744c..08d0a39e0b 100644 --- a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc +++ b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc @@ -25,34 +25,38 @@ TEST_F(ParserImplTest, VariableIdentDecl_Parses) { auto* p = parser("my_var : f32"); auto decl = p->expect_variable_ident_decl("test"); ASSERT_FALSE(p->has_error()); - ASSERT_EQ(decl.name, "my_var"); - ASSERT_NE(decl.type, nullptr); - ASSERT_TRUE(decl.type->IsF32()); + ASSERT_FALSE(decl.errored); + ASSERT_EQ(decl->name, "my_var"); + ASSERT_NE(decl->type, nullptr); + ASSERT_TRUE(decl->type->IsF32()); - ASSERT_EQ(decl.source.range.begin.line, 1u); - ASSERT_EQ(decl.source.range.begin.column, 1u); - ASSERT_EQ(decl.source.range.end.line, 1u); - ASSERT_EQ(decl.source.range.end.column, 7u); + ASSERT_EQ(decl->source.range.begin.line, 1u); + ASSERT_EQ(decl->source.range.begin.column, 1u); + ASSERT_EQ(decl->source.range.end.line, 1u); + ASSERT_EQ(decl->source.range.end.column, 7u); } TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) { auto* p = parser(": f32"); auto decl = p->expect_variable_ident_decl("test"); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(decl.errored); ASSERT_EQ(p->error(), "1:1: expected identifier for test"); } TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) { auto* p = parser("my_var f32"); - auto r = p->expect_variable_ident_decl("test"); + auto decl = p->expect_variable_ident_decl("test"); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(decl.errored); ASSERT_EQ(p->error(), "1:8: expected ':' for test"); } TEST_F(ParserImplTest, VariableIdentDecl_MissingType) { auto* p = parser("my_var :"); - auto r = p->expect_variable_ident_decl("test"); + auto decl = p->expect_variable_ident_decl("test"); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(decl.errored); ASSERT_EQ(p->error(), "1:9: invalid type for test"); } @@ -60,13 +64,15 @@ TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) { auto* p = parser("123 : f32"); auto decl = p->expect_variable_ident_decl("test"); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(decl.errored); ASSERT_EQ(p->error(), "1:1: expected identifier for test"); } TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) { auto* p = parser("my_var : invalid"); - auto r = p->expect_variable_ident_decl("test"); + auto decl = p->expect_variable_ident_decl("test"); ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(decl.errored); ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'"); }