wsgl parser: Add expect_block(), use it

`expect_block()` takes a start and end token, along with a function to parse a lexical block body.

This reduces code, keeps error messages consistent, and also gives us a future place to try resynchronising the parser so we can have more than one error emitted.

`expect_paren_block()` and `expect_brace_block()` are convenience helpers for providing the start and end tokens for common block types.

Bug: tint:282
Change-Id: I432a0301727b131a6fce875687b952dfc6889a4b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31736
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2020-11-04 20:08:51 +00:00 committed by Commit Bot service account
parent b8791a5129
commit 786bc92002
15 changed files with 274 additions and 344 deletions

View File

@ -435,62 +435,38 @@ std::unique_ptr<ast::VariableDecoration> ParserImpl::variable_decoration() {
Source source;
if (match(Token::Type::kLocation, &source)) {
const char* use = "location decoration";
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
uint32_t val;
if (!expect_positive_sint(use, &val))
return nullptr;
if (!expect(use, Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::LocationDecoration>(val, source);
return expect_paren_block(use, [&] {
uint32_t val;
bool ok = expect_positive_sint(use, &val);
return ok ? std::make_unique<ast::LocationDecoration>(val, source)
: nullptr;
});
}
if (match(Token::Type::kBuiltin, &source)) {
if (!expect("builtin decoration", Token::Type::kParenLeft))
return nullptr;
ast::Builtin builtin;
std::tie(builtin, source) = expect_builtin();
if (builtin == ast::Builtin::kNone)
return nullptr;
if (!expect("builtin decoration", Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::BuiltinDecoration>(builtin, source);
return expect_paren_block("builtin decoration", [&] {
ast::Builtin builtin;
std::tie(builtin, source) = expect_builtin();
return (builtin != ast::Builtin::kNone)
? std::make_unique<ast::BuiltinDecoration>(builtin, source)
: nullptr;
});
}
if (match(Token::Type::kBinding, &source)) {
const char* use = "binding decoration";
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
uint32_t val;
if (!expect_positive_sint(use, &val))
return nullptr;
if (!expect(use, Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::BindingDecoration>(val, source);
return expect_paren_block(use, [&] {
uint32_t val;
bool ok = expect_positive_sint(use, &val);
return ok ? std::make_unique<ast::BindingDecoration>(val, source)
: nullptr;
});
}
if (match(Token::Type::kSet, &source)) {
const char* use = "set decoration";
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
uint32_t val;
if (!expect_positive_sint(use, &val))
return nullptr;
if (!expect(use, Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::SetDecoration>(val, source);
return expect_paren_block(use, [&] {
uint32_t val;
bool ok = expect_positive_sint(use, &val);
return ok ? std::make_unique<ast::SetDecoration>(val, source) : nullptr;
});
}
return nullptr;
@ -1200,25 +1176,24 @@ bool ParserImpl::array_decoration_list(ast::ArrayDecorationList& decos) {
for (;;) {
Source source;
if (!match(Token::Type::kStride, &source)) {
if (match(Token::Type::kStride, &source)) {
const char* use = "stride decoration";
auto deco = expect_paren_block(use, [&] {
uint32_t val;
bool ok = expect_nonzero_positive_sint(use, &val);
return ok ? std::make_unique<ast::StrideDecoration>(val, source)
: nullptr;
});
if (!deco)
return false;
decos.emplace_back(std::move(deco));
} else {
add_error(source, "unknown array decoration");
return false;
}
const char* use = "stride decoration";
if (!expect(use, Token::Type::kParenLeft))
return false;
uint32_t stride;
if (!expect_nonzero_positive_sint(use, &stride))
return false;
decos.push_back(std::make_unique<ast::StrideDecoration>(stride, source));
if (!expect(use, Token::Type::kParenRight))
return false;
if (!match(Token::Type::kComma))
break;
}
@ -1402,43 +1377,23 @@ std::unique_ptr<ast::StructDecoration> ParserImpl::struct_decoration(Token t) {
// struct_body_decl
// : BRACKET_LEFT struct_member* BRACKET_RIGHT
ast::StructMemberList ParserImpl::struct_body_decl() {
auto t = peek();
if (!t.IsBraceLeft()) {
add_error(t, "missing { for struct declaration");
return {};
}
next(); // Consume the peek
return expect_brace_block("struct declaration", [&] {
ast::StructMemberList members;
t = peek();
if (t.IsBraceRight()) {
next(); // Consume the peek
return {};
}
while (!peek().IsBraceRight() && !peek().IsEof()) {
auto mem = struct_member();
if (has_error())
return ast::StructMemberList{};
if (mem == nullptr) {
add_error(peek(), "invalid struct member");
return ast::StructMemberList{};
}
ast::StructMemberList members;
for (;;) {
auto mem = struct_member();
if (has_error())
return {};
if (mem == nullptr) {
add_error(peek(), "invalid struct member");
return {};
members.push_back(std::move(mem));
}
members.push_back(std::move(mem));
t = peek();
if (t.IsBraceRight() || t.IsEof())
break;
}
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing } for struct declaration");
return {};
}
return members;
return members;
});
}
// struct_member
@ -1519,18 +1474,12 @@ ParserImpl::struct_member_decoration() {
return nullptr;
const char* use = "offset decoration";
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
uint32_t val;
if (!expect_positive_sint(use, &val))
return nullptr;
if (!expect(use, Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::StructMemberOffsetDecoration>(val, source);
return expect_paren_block(use, [&] {
uint32_t val;
bool ok = expect_positive_sint(use, &val);
return ok ? std::make_unique<ast::StructMemberOffsetDecoration>(val, source)
: nullptr;
});
}
// function_decl
@ -1624,55 +1573,36 @@ bool ParserImpl::function_decoration_decl(ast::FunctionDecorationList& decos) {
// | WORKGROUP_SIZE PAREN_LEFT INT_LITERAL
// (COMMA INT_LITERAL (COMMA INT_LITERAL)?)? PAREN_RIGHT
std::unique_ptr<ast::FunctionDecoration> ParserImpl::function_decoration() {
auto t = peek();
auto source = t.source();
if (t.IsWorkgroupSize()) {
next(); // Consume the peek
const char* use = "workgroup_size decoration";
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
uint32_t x;
if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) {
return nullptr;
}
uint32_t y = 1;
uint32_t z = 1;
if (match(Token::Type::kComma)) {
if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) {
return nullptr;
Source source;
if (match(Token::Type::kWorkgroupSize, &source)) {
return expect_paren_block("workgroup_size decoration", [&]() {
uint32_t x;
if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) {
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
}
uint32_t y = 1;
uint32_t z = 1;
if (match(Token::Type::kComma)) {
if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) {
return nullptr;
if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) {
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
}
if (match(Token::Type::kComma)) {
if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) {
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
}
}
}
}
if (!expect(use, Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::WorkgroupDecoration>(uint32_t(x), uint32_t(y),
uint32_t(z), source);
return std::make_unique<ast::WorkgroupDecoration>(x, y, z, source);
});
}
if (t.IsStage()) {
next(); // Consume the peek
if (!expect("stage decoration", Token::Type::kParenLeft))
return nullptr;
ast::PipelineStage stage;
std::tie(stage, source) = expect_pipeline_stage();
if (stage == ast::PipelineStage::kNone)
return nullptr;
if (!expect("stage decoration", Token::Type::kParenRight))
return nullptr;
return std::make_unique<ast::StageDecoration>(stage, source);
if (match(Token::Type::kStage, &source)) {
return expect_paren_block("stage decoration", [&]() {
ast::PipelineStage stage;
std::tie(stage, source) = expect_pipeline_stage();
return (stage != ast::PipelineStage::kNone)
? std::make_unique<ast::StageDecoration>(stage, source)
: nullptr;
});
}
return nullptr;
}
@ -1702,16 +1632,11 @@ std::unique_ptr<ast::Function> ParserImpl::function_header() {
if (!expect_ident(use, &name))
return nullptr;
if (!expect(use, Token::Type::kParenLeft))
return nullptr;
auto params = expect_paren_block(use, [&] { return param_list(); });
auto params = param_list();
if (has_error())
return nullptr;
if (!expect(use, Token::Type::kParenRight))
return nullptr;
auto t = next();
if (!t.IsArrow()) {
add_error(t, "missing -> for function declaration");
@ -1808,45 +1733,23 @@ std::pair<ast::Builtin, Source> ParserImpl::expect_builtin() {
// body_stmt
// : BRACKET_LEFT statements BRACKET_RIGHT
std::unique_ptr<ast::BlockStatement> ParserImpl::body_stmt() {
auto t = peek();
if (!t.IsBraceLeft()) {
add_error(t, "missing {");
return nullptr;
}
next(); // Consume the peek
auto stmts = statements();
if (has_error())
return nullptr;
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing }");
return nullptr;
}
return stmts;
return expect_brace_block("", [&] { return statements(); });
}
// paren_rhs_stmt
// : PAREN_LEFT logical_or_expression PAREN_RIGHT
std::unique_ptr<ast::Expression> ParserImpl::paren_rhs_stmt() {
if (!expect("", Token::Type::kParenLeft))
return nullptr;
return expect_paren_block("", [&]() -> std::unique_ptr<ast::Expression> {
auto expr = logical_or_expression();
if (has_error())
return nullptr;
auto expr = logical_or_expression();
if (has_error())
return nullptr;
if (expr == nullptr) {
add_error(peek(), "unable to parse expression");
return nullptr;
}
if (!expect("", Token::Type::kParenRight))
return nullptr;
return expr;
if (expr == nullptr) {
add_error(peek(), "unable to parse expression");
return nullptr;
}
return expr;
});
}
// statements
@ -2174,28 +2077,23 @@ std::unique_ptr<ast::SwitchStatement> ParserImpl::switch_stmt() {
return nullptr;
}
auto t = next();
if (!t.IsBraceLeft()) {
add_error(t, "missing { for switch statement");
return nullptr;
}
ast::CaseStatementList body;
for (;;) {
auto stmt = switch_body();
if (has_error())
return nullptr;
if (stmt == nullptr)
break;
bool ok = expect_brace_block("switch statement", [&] {
for (;;) {
auto stmt = switch_body();
if (has_error())
return false;
if (stmt == nullptr)
break;
body.push_back(std::move(stmt));
}
body.push_back(std::move(stmt));
}
return true;
});
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing } for switch statement");
if (!ok)
return nullptr;
}
return std::make_unique<ast::SwitchStatement>(source, std::move(condition),
std::move(body));
}
@ -2224,30 +2122,18 @@ std::unique_ptr<ast::CaseStatement> ParserImpl::switch_body() {
stmt->set_selectors(std::move(selectors));
}
t = next();
if (!t.IsColon()) {
add_error(t, "missing : for case statement");
return nullptr;
}
const char* use = "case statement";
t = next();
if (!t.IsBraceLeft()) {
add_error(t, "missing { for case statement");
if (!expect(use, Token::Type::kColon))
return nullptr;
}
auto body = case_body();
if (has_error())
auto body = expect_brace_block(use, [&] { return case_body(); });
if (body == nullptr)
return nullptr;
stmt->set_body(std::move(body));
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing } for case statement");
return nullptr;
}
return stmt;
}
@ -2313,28 +2199,19 @@ std::unique_ptr<ast::LoopStatement> ParserImpl::loop_stmt() {
if (!match(Token::Type::kLoop, &source))
return nullptr;
auto t = next();
if (!t.IsBraceLeft()) {
add_error(t, "missing { for loop");
return nullptr;
}
return expect_brace_block(
"loop", [&]() -> std::unique_ptr<ast::LoopStatement> {
auto body = statements();
if (has_error())
return nullptr;
auto body = statements();
if (has_error())
return nullptr;
auto continuing = continuing_stmt();
if (has_error())
return nullptr;
auto continuing = continuing_stmt();
if (has_error())
return nullptr;
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing } for loop");
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),
std::move(continuing));
});
}
ForHeader::ForHeader(std::unique_ptr<ast::Statement> init,
@ -2408,32 +2285,15 @@ std::unique_ptr<ast::Statement> ParserImpl::for_stmt() {
if (!match(Token::Type::kFor, &source))
return nullptr;
if (!expect("for loop", Token::Type::kParenLeft))
auto header = expect_paren_block("for loop", [&] { return for_header(); });
if (header == nullptr)
return nullptr;
auto header = for_header();
if (has_error())
return nullptr;
auto body = expect_brace_block("for loop", [&] { return statements(); });
if (!expect("for loop", Token::Type::kParenRight))
if (body == nullptr)
return nullptr;
auto t = next();
if (!t.IsBraceLeft()) {
add_error(t, "missing for loop {");
return nullptr;
}
auto body = statements();
if (has_error())
return nullptr;
t = next();
if (!t.IsBraceRight()) {
add_error(t, "missing for loop }");
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.
@ -2609,19 +2469,21 @@ std::unique_ptr<ast::Expression> ParserImpl::primary_expression() {
if (has_error())
return nullptr;
if (type != nullptr) {
if (!expect("type constructor", Token::Type::kParenLeft))
return nullptr;
t = peek();
ast::ExpressionList params;
if (!t.IsParenRight() && !t.IsEof()) {
params = argument_expression_list();
if (has_error())
return nullptr;
}
if (!expect("type constructor", Token::Type::kParenRight))
auto ok = expect_paren_block("type constructor", [&] {
t = peek();
if (!t.IsParenRight() && !t.IsEof()) {
params = argument_expression_list();
if (has_error())
return false;
}
return true;
});
if (!ok) {
return nullptr;
}
return std::make_unique<ast::TypeConstructorExpression>(source, type,
std::move(params));
@ -3271,36 +3133,30 @@ std::unique_ptr<ast::ConstructorExpression> ParserImpl::const_expr_internal(
auto* type = type_decl();
if (type != nullptr) {
if (!expect("type constructor", Token::Type::kParenLeft))
return nullptr;
ast::ExpressionList params;
auto param = const_expr_internal(depth + 1);
if (has_error())
return nullptr;
if (param == nullptr) {
add_error(peek(), "unable to parse constant expression");
return nullptr;
}
params.push_back(std::move(param));
for (;;) {
t = peek();
if (!t.IsComma())
break;
next(); // Consume the peek
param = const_expr_internal(depth + 1);
bool ok = expect_paren_block("type constructor", [&] {
auto param = const_expr_internal(depth + 1);
if (has_error())
return nullptr;
return false;
if (param == nullptr) {
add_error(peek(), "unable to parse constant expression");
return nullptr;
return false;
}
params.push_back(std::move(param));
}
while (match(Token::Type::kComma)) {
param = const_expr_internal(depth + 1);
if (has_error())
return false;
if (param == nullptr) {
add_error(peek(), "unable to parse constant expression");
return false;
}
params.push_back(std::move(param));
}
return true;
});
if (!expect("type constructor", Token::Type::kParenRight))
if (!ok)
return nullptr;
return std::make_unique<ast::TypeConstructorExpression>(source, type,
@ -3401,6 +3257,36 @@ bool ParserImpl::expect_ident(const std::string& use,
return true;
}
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 {};
}
auto res = body();
if (has_error()) {
return {};
}
if (!expect(use, end)) {
return {};
}
return res;
}
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));
}
template <typename F, typename T>
T ParserImpl::expect_brace_block(const std::string& use, F&& body) {
return expect_block(Token::Type::kBraceLeft, Token::Type::kBraceRight, use,
std::forward<F>(body));
}
} // namespace wgsl
} // namespace reader
} // namespace tint

View File

@ -18,6 +18,7 @@
#include <deque>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
@ -435,6 +436,10 @@ class ParserImpl {
std::unique_ptr<ast::AssignmentStatement> assignment_stmt();
private:
/// ResultType resolves to the return type for the function or lambda F.
template <typename F>
using ResultType = typename std::result_of<F()>::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
/// pointer, regardless of success or error
@ -476,6 +481,45 @@ class ParserImpl {
bool expect_ident(const std::string& use,
std::string* out,
Source* source = nullptr);
/// 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.
/// If the |start| or |end| tokens are not matched then an error is generated
/// and a zero-initialized |T| is returned.
/// If |body| raises an error while parsing then a zero-initialized |T| is
/// returned.
/// @param start the token that begins the lexical block
/// @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().
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
template <typename F, typename T = ResultType<F>>
T expect_block(Token::Type start,
Token::Type end,
const std::string& use,
F&& body);
/// A convenience function that calls |expect_block| passing
/// |Token::Type::kParenLeft| and |Token::Type::kParenRight| 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().
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
template <typename F, typename T = ResultType<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().
/// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|.
template <typename F, typename T = ResultType<F>>
T expect_brace_block(const std::string& use, F&& body);
ast::type::Type* type_decl_pointer(Token t);
ast::type::Type* type_decl_vector(Token t);

View File

@ -44,14 +44,14 @@ TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
auto* p = parser("{fn main() -> void {}}");
auto e = p->body_stmt();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:2: missing }");
EXPECT_EQ(p->error(), "1:2: expected '}'");
}
TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
auto* p = parser("{return;");
auto e = p->body_stmt();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: missing }");
EXPECT_EQ(p->error(), "1:9: expected '}'");
}
} // namespace

View File

@ -37,7 +37,7 @@ TEST_F(ParserImplTest, ElseStmt_InvalidBody) {
auto e = p->else_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing }");
EXPECT_EQ(p->error(), "1:8: expected '}'");
}
TEST_F(ParserImplTest, ElseStmt_MissingBody) {
@ -45,7 +45,7 @@ TEST_F(ParserImplTest, ElseStmt_MissingBody) {
auto e = p->else_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing {");
EXPECT_EQ(p->error(), "1:5: expected '{'");
}
} // namespace

View File

@ -55,14 +55,14 @@ TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) {
auto* p = parser("elseif (true) { fn main() -> void {}}");
auto e = p->elseif_stmt();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:17: missing }");
EXPECT_EQ(p->error(), "1:17: expected '}'");
}
TEST_F(ParserImplTest, ElseIfStmt_MissingBody) {
auto* p = parser("elseif (true)");
auto e = p->elseif_stmt();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:14: missing {");
EXPECT_EQ(p->error(), "1:14: expected '{'");
}
} // namespace

View File

@ -239,14 +239,14 @@ TEST_F(ParserImplErrorTest, ForLoopMissingRParen) {
TEST_F(ParserImplErrorTest, ForLoopMissingLBrace) {
EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }",
"test.wgsl:1:54 error: missing for loop {\n"
"test.wgsl:1:54 error: expected '{' for for loop\n"
"fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, ForLoopMissingRBrace) {
EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {",
"test.wgsl:1:55 error: missing for loop }\n"
"test.wgsl:1:55 error: expected '}' for for loop\n"
"fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {\n"
" ^\n");
}
@ -438,14 +438,14 @@ TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
EXPECT("fn f() -> void }",
"test.wgsl:1:16 error: missing {\n"
"test.wgsl:1:16 error: expected '{'\n"
"fn f() -> void }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
EXPECT("fn f() -> void {",
"test.wgsl:1:17 error: missing }\n"
"test.wgsl:1:17 error: expected '}'\n"
"fn f() -> void {\n"
" ^\n");
}
@ -647,14 +647,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingSemicolon) {
TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingLBrace) {
EXPECT("struct S };",
"test.wgsl:1:10 error: missing { for struct declaration\n"
"test.wgsl:1:10 error: expected '{' for struct declaration\n"
"struct S };\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingRBrace) {
EXPECT("struct S { i : i32;",
"test.wgsl:1:20 error: missing } for struct declaration\n"
"test.wgsl:1:20 error: expected '}' for struct declaration\n"
"struct S { i : i32;\n"
" ^\n");
}
@ -1101,14 +1101,14 @@ TEST_F(ParserImplErrorTest, LogicalOrInvalidExpr) {
TEST_F(ParserImplErrorTest, LoopMissingLBrace) {
EXPECT("fn f() -> void { loop } }",
"test.wgsl:1:23 error: missing { for loop\n"
"test.wgsl:1:23 error: expected '{' for loop\n"
"fn f() -> void { loop } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, LoopMissingRBrace) {
EXPECT("fn f() -> void { loop {",
"test.wgsl:1:24 error: missing } for loop\n"
"test.wgsl:1:24 error: expected '}' for loop\n"
"fn f() -> void { loop {\n"
" ^\n");
}
@ -1157,14 +1157,14 @@ TEST_F(ParserImplErrorTest, ShiftInvalidExpr) {
TEST_F(ParserImplErrorTest, SwitchStmtMissingLBrace) {
EXPECT("fn f() -> void { switch(1) }",
"test.wgsl:1:28 error: missing { for switch statement\n"
"test.wgsl:1:28 error: expected '{' for switch statement\n"
"fn f() -> void { switch(1) }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, SwitchStmtMissingRBrace) {
EXPECT("fn f() -> void { switch(1) {",
"test.wgsl:1:29 error: missing } for switch statement\n"
"test.wgsl:1:29 error: expected '}' for switch statement\n"
"fn f() -> void { switch(1) {\n"
" ^\n");
}
@ -1186,21 +1186,21 @@ TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase2) {
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingColon) {
EXPECT("fn f() -> void { switch(1) { case 1 {} } }",
"test.wgsl:1:37 error: missing : for case statement\n"
"test.wgsl:1:37 error: expected ':' for case statement\n"
"fn f() -> void { switch(1) { case 1 {} } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingLBrace) {
EXPECT("fn f() -> void { switch(1) { case 1: } } }",
"test.wgsl:1:38 error: missing { for case statement\n"
"test.wgsl:1:38 error: expected '{' for case statement\n"
"fn f() -> void { switch(1) { case 1: } } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingRBrace) {
EXPECT("fn f() -> void { switch(1) { case 1: {",
"test.wgsl:1:39 error: missing } for case statement\n"
"test.wgsl:1:39 error: expected '}' for case statement\n"
"fn f() -> void { switch(1) { case 1: {\n"
" ^\n");
}

View File

@ -200,7 +200,7 @@ TEST_F(ForStmtErrorTest, MissingRightParen) {
// Test a for loop with missing left brace is invalid.
TEST_F(ForStmtErrorTest, MissingLeftBrace) {
std::string for_str = "for (;;)";
std::string error_str = "1:9: missing for loop {";
std::string error_str = "1:9: expected '{' for for loop";
TestForWithError(for_str, error_str);
}
@ -208,7 +208,7 @@ TEST_F(ForStmtErrorTest, MissingLeftBrace) {
// Test a for loop with missing right brace is invalid.
TEST_F(ForStmtErrorTest, MissingRightBrace) {
std::string for_str = "for (;;) {";
std::string error_str = "1:11: missing for loop }";
std::string error_str = "1:11: expected '}' for for loop";
TestForWithError(for_str, error_str);
}
@ -275,7 +275,7 @@ TEST_F(ForStmtErrorTest, InvalidBody) {
// Test a for loop with a body not matching statements
TEST_F(ForStmtErrorTest, InvalidBodyMatch) {
std::string for_str = "for (;;) { fn main() -> void {} }";
std::string error_str = "1:12: missing for loop }";
std::string error_str = "1:12: expected '}' for for loop";
TestForWithError(for_str, error_str);
}

View File

@ -174,7 +174,7 @@ TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) {
auto f = p->function_decl();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr);
EXPECT_EQ(p->error(), "1:19: missing {");
EXPECT_EQ(p->error(), "1:19: expected '{'");
}
} // namespace

View File

@ -78,7 +78,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidBody) {
auto e = p->if_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:10: missing }");
EXPECT_EQ(p->error(), "1:10: expected '}'");
}
TEST_F(ParserImplTest, IfStmt_MissingBody) {
@ -86,7 +86,7 @@ TEST_F(ParserImplTest, IfStmt_MissingBody) {
auto e = p->if_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:7: missing {");
EXPECT_EQ(p->error(), "1:7: expected '{'");
}
TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
@ -94,7 +94,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
auto e = p->if_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:24: missing }");
EXPECT_EQ(p->error(), "1:24: expected '}'");
}
TEST_F(ParserImplTest, IfStmt_InvalidElse) {
@ -102,7 +102,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElse) {
auto e = p->if_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:18: missing }");
EXPECT_EQ(p->error(), "1:18: expected '}'");
}
} // namespace

View File

@ -70,7 +70,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing { for loop");
EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
}
TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:17: missing } for loop");
EXPECT_EQ(p->error(), "1:17: expected '}' for loop");
}
TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {

View File

@ -90,7 +90,7 @@ TEST_F(ParserImplTest, Statement_If_Invalid) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:10: missing }");
EXPECT_EQ(p->error(), "1:10: expected '}'");
}
TEST_F(ParserImplTest, Statement_Variable) {
@ -146,7 +146,7 @@ TEST_F(ParserImplTest, Statement_Loop_Invalid) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing { for loop");
EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
}
TEST_F(ParserImplTest, Statement_Assignment) {
@ -235,7 +235,7 @@ TEST_F(ParserImplTest, Statement_Body_Invalid) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:3: missing }");
EXPECT_EQ(p->error(), "1:3: expected '}'");
}
} // namespace

View File

@ -59,7 +59,7 @@ TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
auto* p = parser("{a : i32;");
auto m = p->struct_body_decl();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: missing } for struct declaration");
EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration");
}
TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {

View File

@ -94,7 +94,7 @@ TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
auto s = p->struct_decl();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr);
EXPECT_EQ(p->error(), "1:10: missing { for struct declaration");
EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
}
TEST_F(ParserImplTest, StructDecl_InvalidStructBody) {

View File

@ -62,7 +62,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing : for case statement");
EXPECT_EQ(p->error(), "1:8: expected ':' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
@ -70,7 +70,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing { for case statement");
EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:18: missing } for case statement");
EXPECT_EQ(p->error(), "1:18: expected '}' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
@ -86,7 +86,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing } for case statement");
EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Default) {
@ -105,7 +105,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing : for case statement");
EXPECT_EQ(p->error(), "1:9: expected ':' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
@ -113,7 +113,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:10: missing { for case statement");
EXPECT_EQ(p->error(), "1:10: expected '{' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
@ -121,7 +121,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:19: missing } for case statement");
EXPECT_EQ(p->error(), "1:19: expected '}' for case statement");
}
TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
@ -129,7 +129,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing } for case statement");
EXPECT_EQ(p->error(), "1:12: expected '}' for case statement");
}
} // namespace

View File

@ -84,7 +84,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing { for switch statement");
EXPECT_EQ(p->error(), "1:11: expected '{' for switch statement");
}
TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
@ -92,7 +92,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing } for switch statement");
EXPECT_EQ(p->error(), "1:12: expected '}' for switch statement");
}
TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {