wsgl parser: Add ParserImpl::Expect<T>
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 <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 52aba79..b04a509 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -74,6 +74,9 @@
namespace wgsl {
namespace {
+template <typename T>
+using Expect = ParserImpl::Expect<T>;
+
/// 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() = 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 @@
// 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 @@
// | 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<bool> 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 @@
return nullptr;
auto var_decos = cast_decorations<ast::VariableDecoration>(decos);
- if (var_decos.size() > 0) {
+ if (var_decos.errored)
+ return nullptr;
+
+ if (var_decos.value.size() > 0) {
auto dv = std::make_unique<ast::DecoratedVariable>(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 @@
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<ast::Variable>(
- 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 @@
return nullptr;
auto decl = expect_variable_ident_decl("variable declaration");
- if (has_error())
+ if (decl.errored)
return nullptr;
- return std::make_unique<ast::Variable>(decl.source, decl.name, sc, decl.type);
+ return std::make_unique<ast::Variable>(decl->source, decl->name, sc,
+ decl->type);
}
// texture_sampler_types
@@ -426,19 +428,15 @@
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<ast::type::StorageTextureType>(
- storage_dim, access, format));
+ storage_dim, access, format.value));
}
return nullptr;
@@ -622,7 +620,8 @@
// | RGBA32UINT
// | RGBA32SINT
// | RGBA32FLOAT
-ast::type::ImageFormat ParserImpl::image_storage_type() {
+Expect<ast::type::ImageFormat> ParserImpl::expect_image_storage_type(
+ const std::string& use) {
if (match(Token::Type::kFormatR8Unorm))
return ast::type::ImageFormat::kR8Unorm;
@@ -728,31 +727,31 @@
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::TypedIdentifier> 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 @@
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 @@
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 @@
return nullptr;
}
- auto* alias =
- ctx_.type_mgr().Get(std::make_unique<ast::type::AliasType>(name, type));
- register_constructed(name, alias);
+ auto* alias = ctx_.type_mgr().Get(
+ std::make_unique<ast::type::AliasType>(name.value, type));
+ register_constructed(name.value, alias);
return alias->AsAlias();
}
@@ -853,11 +852,12 @@
if (match(Token::Type::kU32))
return ctx_.type_mgr().Get(std::make_unique<ast::type::U32Type>());
- 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 @@
if (match(Token::Type::kArray)) {
auto array_decos = cast_decorations<ast::ArrayDecoration>(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 @@
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 @@
return nullptr;
}
-ast::type::Type* ParserImpl::expect_type_decl_pointer() {
+Expect<ast::type::Type*> 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<ast::type::PointerType>(subtype, sc));
+ std::make_unique<ast::type::PointerType>(subtype, sc.value));
}
-ast::type::Type* ParserImpl::expect_type_decl_vector(Token t) {
+Expect<ast::type::Type*> ParserImpl::expect_type_decl_vector(Token t) {
next(); // Consume the peek
uint32_t count = 2;
@@ -927,53 +927,52 @@
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<ast::type::VectorType>(subtype, count));
}
-ast::type::Type* ParserImpl::expect_type_decl_array(
+Expect<ast::type::Type*> 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<ast::type::ArrayType>(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<ast::type::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
next(); // Consume the peek
uint32_t rows = 2;
@@ -990,24 +989,18 @@
}
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<ast::type::MatrixType>(subtype, rows, columns));
@@ -1023,7 +1016,8 @@
// | IMAGE
// | PRIVATE
// | FUNCTION
-ast::StorageClass ParserImpl::expect_storage_class(const std::string& use) {
+Expect<ast::StorageClass> ParserImpl::expect_storage_class(
+ const std::string& use) {
if (match(Token::Type::kIn))
return ast::StorageClass::kInput;
@@ -1051,8 +1045,7 @@
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 @@
return nullptr;
auto struct_decos = cast_decorations<ast::StructDecoration>(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<ast::type::StructType>(
- name, std::make_unique<ast::Struct>(source, std::move(struct_decos),
- std::move(body)));
+ name.value,
+ std::make_unique<ast::Struct>(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<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
+ return expect_brace_block(
+ "struct declaration", [&]() -> Expect<ast::StructMemberList> {
+ 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<ast::StructMember> ParserImpl::expect_struct_member(
+Expect<std::unique_ptr<ast::StructMember>> 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 @@
// 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<ast::StructMemberDecoration>(decos);
if (!expect("struct member", Token::Type::kSemicolon))
- return nullptr;
+ return Failure::kErrored;
- return std::make_unique<ast::StructMember>(decl.source, decl.name, decl.type,
- std::move(member_decos));
+ return std::make_unique<ast::StructMember>(
+ decl->source, decl->name, decl->type, std::move(member_decos.value));
}
// function_decl
@@ -1142,13 +1139,15 @@
return nullptr;
auto func_decos = cast_decorations<ast::FunctionDecoration>(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 @@
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 @@
return nullptr;
}
- return std::make_unique<ast::Function>(source, name, std::move(params), type);
+ return std::make_unique<ast::Function>(source, name.value,
+ std::move(params.value), type);
}
// param_list
// :
// | (variable_ident_decl COMMA)* variable_ident_decl
-ast::VariableList ParserImpl::expect_param_list() {
+Expect<ast::VariableList> 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<ast::Variable>(
- 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 @@
break;
decl = expect_variable_ident_decl("parameter");
- if (has_error())
- return {};
+ if (decl.errored)
+ return Failure::kErrored;
}
return ret;
@@ -1236,7 +1236,7 @@
// : VERTEX
// | FRAGMENT
// | COMPUTE
-std::pair<ast::PipelineStage, Source> ParserImpl::expect_pipeline_stage() {
+Expect<ast::PipelineStage> ParserImpl::expect_pipeline_stage() {
Source source;
if (match(Token::Type::kVertex, &source))
return {ast::PipelineStage::kVertex, source};
@@ -1247,57 +1247,53 @@
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<ast::Builtin, Source> ParserImpl::expect_builtin() {
- Source source;
- std::string ident;
+Expect<ast::Builtin> 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<ast::BlockStatement> ParserImpl::expect_body_stmt() {
- return expect_brace_block("", [&] { return statements(); });
+Expect<std::unique_ptr<ast::BlockStatement>> ParserImpl::expect_body_stmt() {
+ return expect_brace_block("", [&] { return expect_statements(); });
}
// paren_rhs_stmt
// : PAREN_LEFT logical_or_expression PAREN_RIGHT
-std::unique_ptr<ast::Expression> ParserImpl::expect_paren_rhs_stmt() {
- return expect_paren_block("", [&]() -> std::unique_ptr<ast::Expression> {
- auto expr = logical_or_expression();
- if (has_error())
- return nullptr;
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_paren_rhs_stmt() {
+ return expect_paren_block(
+ "", [&]() -> Expect<std::unique_ptr<ast::Expression>> {
+ 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<ast::BlockStatement> ParserImpl::statements() {
+Expect<std::unique_ptr<ast::BlockStatement>> ParserImpl::expect_statements() {
auto ret = std::make_unique<ast::BlockStatement>();
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 @@
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 @@
}
auto var = std::make_unique<ast::Variable>(
- 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<ast::VariableDeclStatement>(decl.source,
+ return std::make_unique<ast::VariableDeclStatement>(decl->source,
std::move(var));
}
@@ -1510,11 +1505,11 @@
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 @@
if (has_error())
return nullptr;
- auto stmt = std::make_unique<ast::IfStatement>(source, std::move(condition),
- std::move(body));
+ auto stmt = std::make_unique<ast::IfStatement>(
+ source, std::move(condition.value), std::move(body.value));
if (el != nullptr) {
elseif.push_back(std::move(el));
}
@@ -1548,15 +1543,15 @@
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<ast::ElseStatement>(
- 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 @@
next(); // Consume the peek
auto body = expect_body_stmt();
- if (has_error())
+ if (body.errored)
return nullptr;
- return std::make_unique<ast::ElseStatement>(source, std::move(body));
+ return std::make_unique<ast::ElseStatement>(source, std::move(body.value));
}
// switch_stmt
@@ -1591,11 +1586,11 @@
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 @@
if (!ok)
return nullptr;
- return std::make_unique<ast::SwitchStatement>(source, std::move(condition),
- std::move(body));
+ return std::make_unique<ast::SwitchStatement>(
+ source, std::move(condition.value), std::move(body));
}
// switch_body
@@ -1629,14 +1624,14 @@
auto stmt = std::make_unique<ast::CaseStatement>();
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 @@
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 @@
// case_selectors
// : const_literal (COMMA const_literal)*
-ast::CaseSelectorList ParserImpl::case_selectors() {
+Expect<ast::CaseSelectorList> 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<ast::IntLiteral> 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 @@
if (!match(Token::Type::kLoop, &source))
return nullptr;
- return expect_brace_block(
+ return expect_brace_block_old(
"loop", [&]() -> std::unique_ptr<ast::LoopStatement> {
- 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<ast::LoopStatement>(source, std::move(body),
- std::move(continuing));
+ return std::make_unique<ast::LoopStatement>(
+ source, std::move(body.value), std::move(continuing));
});
}
@@ -1745,49 +1741,49 @@
// SEMICOLON
// logical_or_expression? SEMICOLON
// (assignment_stmt | func_call_stmt)?
-std::unique_ptr<ForHeader> ParserImpl::expect_for_header() {
+Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
std::unique_ptr<ast::Statement> 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<ast::Statement> 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 @@
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<ast::UnaryOpExpression>(
- 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<ast::BreakStatement>(not_condition->source());
@@ -1831,22 +1827,22 @@
auto break_if_not_condition = std::make_unique<ast::IfStatement>(
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<ast::BlockStatement> continuing_body = nullptr;
- if (header->continuing != nullptr) {
- continuing_body =
- std::make_unique<ast::BlockStatement>(header->continuing->source());
- continuing_body->append(std::move(header->continuing));
+ if (header.value->continuing != nullptr) {
+ continuing_body = std::make_unique<ast::BlockStatement>(
+ header.value->continuing->source());
+ continuing_body->append(std::move(header.value->continuing));
}
- auto loop = std::make_unique<ast::LoopStatement>(source, std::move(body),
- std::move(continuing_body));
+ auto loop = std::make_unique<ast::LoopStatement>(
+ source, std::move(body.value), std::move(continuing_body));
- if (header->initializer != nullptr) {
+ if (header.value->initializer != nullptr) {
auto result = std::make_unique<ast::BlockStatement>(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 @@
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 @@
if (!match(Token::Type::kContinuing))
return std::make_unique<ast::BlockStatement>();
- return expect_body_stmt();
+ return expect_body_stmt().value;
}
// primary_expression
@@ -1936,10 +1934,10 @@
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 @@
}
auto params = expect_paren_rhs_stmt();
- if (has_error())
+ if (params.errored)
return nullptr;
return std::make_unique<ast::BitcastExpression>(source, type,
- std::move(params));
+ std::move(params.value));
} else if (t.IsIdentifier()) {
next(); // Consume the peek
@@ -1983,24 +1981,26 @@
if (has_error())
return nullptr;
if (type != nullptr) {
- ast::ExpressionList params;
+ auto expr = expect_paren_block(
+ "type constructor",
+ [&]() -> Expect<std::unique_ptr<ast::TypeConstructorExpression>> {
+ t = peek();
+ if (t.IsParenRight() || t.IsEof())
+ return std::make_unique<ast::TypeConstructorExpression>(
+ 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<ast::TypeConstructorExpression>(
+ source, type, std::move(params.value));
+ });
+
+ if (expr.errored)
return nullptr;
- }
- return std::make_unique<ast::TypeConstructorExpression>(source, type,
- std::move(params));
+ return std::move(expr.value);
}
return nullptr;
}
@@ -2038,12 +2038,14 @@
} 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 @@
} 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<ast::MemberAccessorExpression>(
- source, std::move(prefix),
- std::make_unique<ast::IdentifierExpression>(source, ident));
+ ident.source, std::move(prefix),
+ std::make_unique<ast::IdentifierExpression>(ident.source, ident.value));
} else {
return prefix;
}
@@ -2081,14 +2083,12 @@
// argument_expression_list
// : (logical_or_expression COMMA)* logical_or_expression
-ast::ExpressionList ParserImpl::expect_argument_expression_list() {
+Expect<ast::ExpressionList> 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 @@
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 @@
// | STAR unary_expression multiplicative_expr
// | FORWARD_SLASH unary_expression multiplicative_expr
// | MODULO unary_expression multiplicative_expr
-std::unique_ptr<ast::Expression> ParserImpl::expect_multiplicative_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_multiplicative_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
@@ -2161,10 +2161,10 @@
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<ast::BinaryExpression>(
source, op, std::move(lhs), std::move(rhs)));
@@ -2179,14 +2179,14 @@
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<ast::Expression> ParserImpl::expect_additive_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_additive_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
@@ -2203,11 +2203,9 @@
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<ast::BinaryExpression>(
source, op, std::move(lhs), std::move(rhs)));
}
@@ -2221,14 +2219,14 @@
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<ast::Expression> ParserImpl::expect_shift_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_shift_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
auto source = t.source();
@@ -2252,11 +2250,10 @@
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<ast::BinaryExpression>(
source, op, std::move(lhs), std::move(rhs)));
@@ -2271,7 +2268,7 @@
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 @@
// | GREATER_THAN shift_expression relational_expr
// | LESS_THAN_EQUAL shift_expression relational_expr
// | GREATER_THAN_EQUAL shift_expression relational_expr
-std::unique_ptr<ast::Expression> ParserImpl::expect_relational_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_relational_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
ast::BinaryOp op = ast::BinaryOp::kNone;
@@ -2301,11 +2298,12 @@
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<ast::BinaryExpression>(
source, op, std::move(lhs), std::move(rhs)));
}
@@ -2319,14 +2317,14 @@
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<ast::Expression> ParserImpl::expect_equality_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_equality_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
ast::BinaryOp op = ast::BinaryOp::kNone;
@@ -2343,11 +2341,12 @@
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<ast::BinaryExpression>(
source, op, std::move(lhs), std::move(rhs)));
}
@@ -2361,13 +2360,13 @@
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<ast::Expression> ParserImpl::expect_and_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_and_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
if (!t.IsAnd())
@@ -2378,11 +2377,10 @@
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<ast::BinaryExpression>(
source, ast::BinaryOp::kAnd, std::move(lhs), std::move(rhs)));
}
@@ -2396,13 +2394,13 @@
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<ast::Expression> ParserImpl::expect_exclusive_or_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_exclusive_or_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
if (!t.IsXor())
@@ -2413,11 +2411,10 @@
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<ast::BinaryExpression>(
source, ast::BinaryOp::kXor, std::move(lhs), std::move(rhs)));
}
@@ -2431,13 +2428,13 @@
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<ast::Expression> ParserImpl::expect_inclusive_or_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_inclusive_or_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
if (!t.IsOr())
@@ -2448,11 +2445,10 @@
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<ast::BinaryExpression>(
source, ast::BinaryOp::kOr, std::move(lhs), std::move(rhs)));
}
@@ -2466,13 +2462,13 @@
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<ast::Expression> ParserImpl::expect_logical_and_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_logical_and_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
if (!t.IsAndAnd())
@@ -2483,11 +2479,10 @@
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<ast::BinaryExpression>(
source, ast::BinaryOp::kLogicalAnd, std::move(lhs), std::move(rhs)));
}
@@ -2501,13 +2496,13 @@
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<ast::Expression> ParserImpl::expect_logical_or_expr(
+Expect<std::unique_ptr<ast::Expression>> ParserImpl::expect_logical_or_expr(
std::unique_ptr<ast::Expression> lhs) {
auto t = peek();
if (!t.IsOrOr())
@@ -2518,11 +2513,10 @@
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<ast::BinaryExpression>(
source, ast::BinaryOp::kLogicalOr, std::move(lhs), std::move(rhs)));
}
@@ -2536,7 +2530,7 @@
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 @@
// const_expr
// : type_decl PAREN_LEFT (const_expr COMMA)? const_expr PAREN_RIGHT
// | const_literal
-std::unique_ptr<ast::ConstructorExpression> ParserImpl::expect_const_expr() {
+Expect<std::unique_ptr<ast::ConstructorExpression>>
+ParserImpl::expect_const_expr() {
return expect_const_expr_internal(0);
}
-std::unique_ptr<ast::ConstructorExpression>
+Expect<std::unique_ptr<ast::ConstructorExpression>>
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> {
+ 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<ast::TypeConstructorExpression>(source, type,
- std::move(params));
+ return std::make_unique<ast::TypeConstructorExpression>(
+ 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<ast::ScalarConstructorExpression>(source,
std::move(lit));
@@ -2672,11 +2667,11 @@
}
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 @@
}
}
-std::unique_ptr<ast::Decoration> ParserImpl::expect_decoration() {
+Expect<std::unique_ptr<ast::Decoration>> 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<ast::Decoration> ParserImpl::decoration() {
+ using Result = std::unique_ptr<ast::Decoration>;
auto t = next();
if (t.IsLocation()) {
const char* use = "location decoration";
- return expect_paren_block(use, [&]() {
- uint32_t val;
- bool ok = expect_positive_sint(use, &val);
- return ok ? std::make_unique<ast::LocationDecoration>(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<ast::LocationDecoration>(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<ast::BindingDecoration>(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<ast::BindingDecoration>(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<ast::SetDecoration>(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<ast::SetDecoration>(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<ast::BuiltinDecoration>(builtin, source)
- : nullptr;
+ return expect_paren_block_old("builtin decoration", [&]() -> Result {
+ auto builtin = expect_builtin();
+ if (builtin.errored)
+ return nullptr;
+
+ return std::make_unique<ast::BuiltinDecoration>(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<ast::WorkgroupDecoration>(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<ast::WorkgroupDecoration>(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<ast::WorkgroupDecoration>(nullptr);
- }
+ val = expect_nonzero_positive_sint("workgroup_size z parameter");
+ if (val.errored)
+ return nullptr;
+ z = val.value;
}
}
+
return std::make_unique<ast::WorkgroupDecoration>(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<ast::StageDecoration>(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<ast::StageDecoration>(stage.value, stage.source);
});
}
if (t.IsBlock()) {
@@ -2780,29 +2784,32 @@
}
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<ast::StrideDecoration>(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<ast::StrideDecoration>(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<ast::StructMemberOffsetDecoration>(
- 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<ast::StructMemberOffsetDecoration>(val.value,
+ t.source());
});
}
return nullptr;
}
template <typename T>
-std::vector<std::unique_ptr<T>> ParserImpl::cast_decorations(
+Expect<std::vector<std::unique_ptr<T>>> ParserImpl::cast_decorations(
ast::DecorationList& in) {
+ bool ok = true;
std::vector<std::unique_ptr<T>> out;
out.reserve(in.size());
for (auto& deco : in) {
@@ -2811,6 +2818,7 @@
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<T>(std::move(deco)));
@@ -2818,6 +2826,10 @@
// 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 @@
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<uint32_t>(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<uint32_t>(val);
- return true;
-}
-
-bool ParserImpl::expect_ident(const std::string& use,
- std::string* out,
- Source* source /* = nullptr */) {
+Expect<int32_t> 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<uint32_t> 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<uint32_t>(sint.value), sint.source};
+}
+
+Expect<uint32_t> 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<uint32_t>(sint.value), sint.source};
+}
+
+Expect<std::string> 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 <typename F, typename T>
-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 {};
}
@@ -2931,6 +2927,36 @@
}
template <typename F, typename T>
+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 <typename F, typename T>
+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<F>(body));
+}
+
+template <typename F, typename T>
+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<F>(body));
+}
+
+template <typename F, typename T>
T ParserImpl::expect_paren_block(const std::string& use, F&& body) {
return expect_block(Token::Type::kParenLeft, Token::Type::kParenRight, use,
std::forward<F>(body));
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 5e1b941..5bddd68 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 <cassert>
#include <deque>
#include <memory>
#include <string>
@@ -79,7 +80,61 @@
/// 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 <typename T>
+ 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 <typename U>
+ inline Expect(U&& val, const Source& s = {}) // NOLINT
+ : value(std::forward<U>(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 @@
/// 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 @@
/// 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<bool> 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 @@
/// 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<TypedIdentifier> 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 @@
/// 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<ast::StorageClass> 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 @@
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<ast::StructMemberList> 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<ast::StructMember> expect_struct_member(
+ Expect<std::unique_ptr<ast::StructMember>> 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 @@
/// @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<ast::type::ImageFormat> 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 @@
std::unique_ptr<ast::Function> function_header();
/// Parses a `param_list` grammar element, erroring on parse failure.
/// @returns the parsed variables
- ast::VariableList expect_param_list();
+ Expect<ast::VariableList> 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<ast::PipelineStage, Source> expect_pipeline_stage();
+ /// @returns the pipeline stage.
+ Expect<ast::PipelineStage> 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<ast::Builtin, Source> expect_builtin();
+ /// @returns the parsed builtin.
+ Expect<ast::Builtin> expect_builtin();
/// Parses a `body_stmt` grammar element, erroring on parse failure.
/// @returns the parsed statements
- std::unique_ptr<ast::BlockStatement> expect_body_stmt();
+ Expect<std::unique_ptr<ast::BlockStatement>> expect_body_stmt();
/// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure.
/// @returns the parsed element or nullptr
- std::unique_ptr<ast::Expression> expect_paren_rhs_stmt();
+ Expect<std::unique_ptr<ast::Expression>> expect_paren_rhs_stmt();
/// Parses a `statements` grammar element
/// @returns the statements parsed
- std::unique_ptr<ast::BlockStatement> statements();
+ Expect<std::unique_ptr<ast::BlockStatement>> expect_statements();
/// Parses a `statement` grammar element
/// @returns the parsed statement or nullptr
std::unique_ptr<ast::Statement> statement();
@@ -292,7 +354,7 @@
std::unique_ptr<ast::CaseStatement> switch_body();
/// Parses a `case_selectors` grammar element
/// @returns the list of literals
- ast::CaseSelectorList case_selectors();
+ Expect<ast::CaseSelectorList> expect_case_selectors();
/// Parses a `case_body` grammar element
/// @returns the parsed statements
std::unique_ptr<ast::BlockStatement> case_body();
@@ -304,7 +366,7 @@
std::unique_ptr<ast::LoopStatement> loop_stmt();
/// Parses a `for_header` grammar element, erroring on parse failure.
/// @returns the parsed for header or nullptr
- std::unique_ptr<ForHeader> expect_for_header();
+ Expect<std::unique_ptr<ForHeader>> expect_for_header();
/// Parses a `for_stmt` grammar element
/// @returns the parsed for loop or nullptr
std::unique_ptr<ast::Statement> for_stmt();
@@ -316,14 +378,14 @@
std::unique_ptr<ast::Literal> const_literal();
/// Parses a `const_expr` grammar element, erroring on parse failure.
/// @returns the parsed constructor expression or nullptr on error
- std::unique_ptr<ast::ConstructorExpression> expect_const_expr();
+ Expect<std::unique_ptr<ast::ConstructorExpression>> expect_const_expr();
/// Parses a `primary_expression` grammar element
/// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> 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<ast::ExpressionList> 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 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_multiplicative_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_multiplicative_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `multiplicative_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -348,7 +410,7 @@
/// failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_additive_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_additive_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `additive_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -357,7 +419,7 @@
/// failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_shift_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_shift_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `shift_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -366,7 +428,7 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_relational_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_relational_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `relational_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -375,7 +437,7 @@
/// failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_equality_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_equality_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `equality_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -384,7 +446,7 @@
/// failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_and_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_and_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `and_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -393,7 +455,7 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_exclusive_or_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_exclusive_or_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `exclusive_or_expression` grammar elememnt
/// @returns the parsed expression or nullptr
@@ -402,7 +464,7 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_inclusive_or_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_inclusive_or_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses the `inclusive_or_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -411,7 +473,7 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_logical_and_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_logical_and_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses a `logical_and_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -420,7 +482,7 @@
/// parse failure.
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr
- std::unique_ptr<ast::Expression> expect_logical_or_expr(
+ Expect<std::unique_ptr<ast::Expression>> expect_logical_or_expr(
std::unique_ptr<ast::Expression> lhs);
/// Parses a `logical_or_expression` grammar element
/// @returns the parsed expression or nullptr
@@ -449,12 +511,16 @@
/// 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<ast::Decoration> expect_decoration();
+ Expect<std::unique_ptr<ast::Decoration>> 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 <typename F>
- using ResultType = typename std::result_of<F()>::type;
+ using ReturnType = typename std::result_of<F()>::type;
+
+ /// ResultType resolves to |T| for a |RESULT| of type Expect<T>.
+ template <typename RESULT>
+ 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 @@
/// 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<int32_t> 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<uint32_t> 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<uint32_t> 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<std::string> 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 @@
/// @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<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
- template <typename F, typename T = ResultType<F>>
+ template <typename F, typename T = ReturnType<F>>
T expect_block(Token::Type start,
Token::Type end,
const std::string& use,
@@ -521,36 +579,53 @@
/// 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<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
- template <typename F, typename T = ResultType<F>>
+ template <typename F, typename T = ReturnType<F>>
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<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
- template <typename F, typename T = ResultType<F>>
+ template <typename F, typename T = ReturnType<F>>
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 <typename F, typename T = ReturnType<F>>
+ T expect_block_old(Token::Type start,
+ Token::Type end,
+ const std::string& use,
+ F&& body);
+ template <typename F, typename T = ReturnType<F>>
+ T expect_paren_block_old(const std::string& use, F&& body);
+ template <typename F, typename T = ReturnType<F>>
+ 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 <typename T>
- std::vector<std::unique_ptr<T>> cast_decorations(ast::DecorationList& in);
+ Expect<std::vector<std::unique_ptr<T>>> 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<ast::type::Type*> expect_type_decl_pointer();
+ Expect<ast::type::Type*> expect_type_decl_vector(Token t);
+ Expect<ast::type::Type*> expect_type_decl_array(
+ ast::ArrayDecorationList decos);
+ Expect<ast::type::Type*> expect_type_decl_matrix(Token t);
- std::unique_ptr<ast::ConstructorExpression> expect_const_expr_internal(
- uint32_t depth);
+ Expect<std::unique_ptr<ast::ConstructorExpression>>
+ 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 78007b1..6302c8e 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 @@
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 @@
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 6451de5..4a3b5a0 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 @@
})");
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 @@
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 5d427dc..14b716f 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 @@
auto* p = parser("vec2<f32>(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 @@
auto* p = parser("vec2<f32>(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 @@
auto* p = parser("vec2<f32> 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 @@
auto* p = parser("vec2<f32>(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 @@
auto* p = parser("vec2<f32>(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 @@
auto* p = parser("vec2<f32>()");
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 @@
auto* p = parser("vec2<f32>(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 @@
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 @@
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 @@
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 a8a8128..3520a58 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 @@
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 0caed67..f454a3b 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 @@
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 1711106..03eea45 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 @@
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 @@
auto* p = parser("a : i32, b: f32, c: vec2<f32>");
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 9360f7e..e55bc89 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 @@
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 @@
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 @@
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 @@
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 0fcffc4..4cae54e 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 @@
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 @@
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 a22e656..c7417e9 100644
--- a/src/reader/wgsl/parser_impl_statements_test.cc
+++ b/src/reader/wgsl/parser_impl_statements_test.cc
@@ -24,18 +24,20 @@
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 bca0a66..2945512 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 @@
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 @@
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 7e8d7d2..f46cc30 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 @@
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 @@
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 @@
})");
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 @@
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 @@
} )");
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 186e0f0..563ece6 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 f9eb7a7..08d0a39 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 @@
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 @@
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'");
}