wsgl parser: Use expect() for semicolon checks

Keeps error message consistent. Reduces code.

Bug: tint:282
Change-Id: Ifddb63b65d44427e0680bb25837fcb24ca854eb0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31725
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2020-11-04 14:17:51 +00:00 committed by Commit Bot service account
parent d70f251188
commit f7fc63b8e3
11 changed files with 68 additions and 103 deletions

View File

@ -224,11 +224,9 @@ void ParserImpl::global_decl() {
return;
}
if (gv != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' for variable declaration");
if (!expect("variable declaration", Token::Type::kSemicolon))
return;
}
module_.AddGlobalVariable(std::move(gv));
return;
}
@ -238,11 +236,9 @@ void ParserImpl::global_decl() {
return;
}
if (gc != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' for constant declaration");
if (!expect("constant declaration", Token::Type::kSemicolon))
return;
}
module_.AddGlobalVariable(std::move(gc));
return;
}
@ -252,11 +248,9 @@ void ParserImpl::global_decl() {
return;
}
if (ta != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' for type alias");
if (!expect("type alias", Token::Type::kSemicolon))
return;
}
module_.AddConstructedType(ta);
return;
}
@ -266,11 +260,9 @@ void ParserImpl::global_decl() {
return;
}
if (str != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' for struct declaration");
if (!expect("struct declaration", Token::Type::kSemicolon))
return;
}
auto* type = ctx_.type_mgr().Get(std::move(str));
register_constructed(type->AsStruct()->name(), type);
module_.AddConstructedType(type);
@ -1634,11 +1626,8 @@ std::unique_ptr<ast::StructMember> ParserImpl::struct_member() {
return nullptr;
}
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ; for struct member");
if (!expect("struct member", Token::Type::kSemicolon))
return nullptr;
}
return std::make_unique<ast::StructMember>(decl.source, decl.name, decl.type,
std::move(decos));
@ -2115,21 +2104,18 @@ std::unique_ptr<ast::BlockStatement> ParserImpl::statements() {
// | assignment_stmt SEMICOLON
// | body_stmt?
std::unique_ptr<ast::Statement> ParserImpl::statement() {
auto t = peek();
if (t.IsSemicolon()) {
next(); // Consume the peek
return statement();
while (match(Token::Type::kSemicolon)) {
// Skip empty statements
}
auto t = peek();
auto ret_stmt = return_stmt();
if (has_error())
return nullptr;
if (ret_stmt != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("return statement", Token::Type::kSemicolon))
return nullptr;
}
return ret_stmt;
}
@ -2161,11 +2147,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
if (has_error())
return nullptr;
if (func != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("function call", Token::Type::kSemicolon))
return nullptr;
}
return func;
}
@ -2173,11 +2157,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
if (has_error())
return nullptr;
if (var != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("variable declaration", Token::Type::kSemicolon))
return nullptr;
}
return var;
}
@ -2185,11 +2167,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
if (has_error())
return nullptr;
if (b != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("break statement", Token::Type::kSemicolon))
return nullptr;
}
return b;
}
@ -2197,11 +2177,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
if (has_error())
return nullptr;
if (cont != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("continue statement", Token::Type::kSemicolon))
return nullptr;
}
return cont;
}
@ -2209,11 +2187,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
auto source = t.source();
next(); // Consume the peek
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("discard statement", Token::Type::kSemicolon))
return nullptr;
}
return std::make_unique<ast::DiscardStatement>(source);
}
@ -2221,11 +2197,9 @@ std::unique_ptr<ast::Statement> ParserImpl::statement() {
if (has_error())
return nullptr;
if (assign != nullptr) {
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
if (!expect("assignment statement", Token::Type::kSemicolon))
return nullptr;
}
return assign;
}
@ -2547,11 +2521,8 @@ std::unique_ptr<ast::BlockStatement> ParserImpl::case_body() {
auto source = t.source();
next(); // Consume the peek
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ;");
return {};
}
if (!expect("fallthrough statement", Token::Type::kSemicolon))
return nullptr;
ret->append(std::make_unique<ast::FallthroughStatement>(source));
break;
@ -2638,22 +2609,16 @@ std::unique_ptr<ForHeader> ParserImpl::for_header() {
}
}
auto t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' after initializer in for loop");
if (!expect("initializer in for loop", Token::Type::kSemicolon))
return nullptr;
}
auto condition = logical_or_expression();
if (has_error()) {
return nullptr;
}
t = next();
if (!t.IsSemicolon()) {
add_error(t, "missing ';' after condition in for loop");
if (!expect("condition in for loop", Token::Type::kSemicolon))
return nullptr;
}
std::unique_ptr<ast::Statement> continuing = nullptr;
if (continuing == nullptr) {
@ -3634,7 +3599,7 @@ bool ParserImpl::expect(const std::string& use, Token::Type tok) {
auto t = next();
if (!t.Is(tok)) {
std::stringstream err;
err << "expected " << Token::TypeToName(tok);
err << "expected '" << Token::TypeToName(tok) << "'";
if (!use.empty()) {
err << " for " << use;
}

View File

@ -70,7 +70,7 @@ TEST_F(ParserImplTest, Statement_Call_Missing_Semi) {
auto* p = parser("a()");
auto e = p->statement();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:4: missing ;");
EXPECT_EQ(p->error(), "1:4: expected ';' for function call");
}
TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) {

View File

@ -60,7 +60,7 @@ TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) {
auto e = p->case_body();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing ;");
EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement");
}
} // namespace

View File

@ -34,7 +34,7 @@ TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
auto e = p->continuing_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:22: missing ;");
EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement");
}
} // namespace

View File

@ -77,7 +77,7 @@ TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) {
TEST_F(ParserImplErrorTest, AssignmentStmtMissingSemicolon) {
EXPECT("fn f() -> void { a = 1 }",
"test.wgsl:1:24 error: missing ;\n"
"test.wgsl:1:24 error: expected ';' for assignment statement\n"
"fn f() -> void { a = 1 }\n"
" ^\n");
}
@ -112,7 +112,7 @@ TEST_F(ParserImplErrorTest, BitcastExprMissingType) {
TEST_F(ParserImplErrorTest, BreakStmtMissingSemicolon) {
EXPECT("fn f() -> void { loop { break } }",
"test.wgsl:1:31 error: missing ;\n"
"test.wgsl:1:31 error: expected ';' for break statement\n"
"fn f() -> void { loop { break } }\n"
" ^\n");
}
@ -148,7 +148,7 @@ TEST_F(ParserImplErrorTest, CallStmtInvalidArgument1) {
TEST_F(ParserImplErrorTest, CallStmtMissingSemicolon) {
EXPECT("fn f() -> void { f() }",
"test.wgsl:1:22 error: missing ;\n"
"test.wgsl:1:22 error: expected ';' for function call\n"
"fn f() -> void { f() }\n"
" ^\n");
}
@ -190,14 +190,14 @@ TEST_F(ParserImplErrorTest, ConstVarStmtMissingConstructor) {
TEST_F(ParserImplErrorTest, ContinueStmtMissingSemicolon) {
EXPECT("fn f() -> void { loop { continue } }",
"test.wgsl:1:34 error: missing ;\n"
"test.wgsl:1:34 error: expected ';' for continue statement\n"
"fn f() -> void { loop { continue } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, DiscardStmtMissingSemicolon) {
EXPECT("fn f() -> void { discard }",
"test.wgsl:1:26 error: missing ;\n"
"test.wgsl:1:26 error: expected ';' for discard statement\n"
"fn f() -> void { discard }\n"
" ^\n");
}
@ -211,14 +211,14 @@ TEST_F(ParserImplErrorTest, EqualityInvalidExpr) {
TEST_F(ParserImplErrorTest, ForLoopInitializerMissingSemicolon) {
EXPECT("fn f() -> void { for (var i : i32 = 0 i < 8; i=i+1) {} }",
"test.wgsl:1:39 error: missing ';' after initializer in for loop\n"
"test.wgsl:1:39 error: expected ';' for initializer in for loop\n"
"fn f() -> void { for (var i : i32 = 0 i < 8; i=i+1) {} }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, ForLoopConditionMissingSemicolon) {
EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8 i=i+1) {} }",
"test.wgsl:1:46 error: missing ';' after condition in for loop\n"
"test.wgsl:1:46 error: expected ';' for condition in for loop\n"
"fn f() -> void { for (var i : i32 = 0; i < 8 i=i+1) {} }\n"
" ^\n");
}
@ -429,7 +429,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
EXPECT("const i : i32 = 1",
"test.wgsl:1:18 error: missing ';' for constant declaration\n"
"test.wgsl:1:18 error: expected ';' for constant declaration\n"
"const i : i32 = 1\n"
" ^\n");
}
@ -589,7 +589,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingIdentifier) {
TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingSemicolon) {
EXPECT("struct S {}",
"test.wgsl:1:12 error: missing ';' for struct declaration\n"
"test.wgsl:1:12 error: expected ';' for struct declaration\n"
"struct S {}\n"
" ^\n");
}
@ -631,7 +631,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructMemberInvalidIdentifier) {
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberMissingSemicolon) {
EXPECT("struct S { i : i32 };",
"test.wgsl:1:20 error: missing ; for struct member\n"
"test.wgsl:1:20 error: expected ';' for struct member\n"
"struct S { i : i32 };\n"
" ^\n");
}
@ -687,7 +687,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingAssignment) {
TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingSemicolon) {
EXPECT("type meow = f32",
"test.wgsl:1:16 error: missing ';' for type alias\n"
"test.wgsl:1:16 error: expected ';' for type alias\n"
"type meow = f32\n"
" ^\n");
}
@ -932,7 +932,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingType) {
TEST_F(ParserImplErrorTest, GlobalDeclVarMissingSemicolon) {
EXPECT("var i : i32",
"test.wgsl:1:12 error: missing ';' for variable declaration\n"
"test.wgsl:1:12 error: expected ';' for variable declaration\n"
"var i : i32\n"
" ^\n");
}
@ -1086,7 +1086,7 @@ TEST_F(ParserImplErrorTest, RelationalInvalidExpr) {
TEST_F(ParserImplErrorTest, ReturnStmtMissingSemicolon) {
EXPECT("fn f() -> void { return }",
"test.wgsl:1:25 error: missing ;\n"
"test.wgsl:1:25 error: expected ';' for return statement\n"
"fn f() -> void { return }\n"
" ^\n");
}
@ -1150,14 +1150,14 @@ TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingRBrace) {
TEST_F(ParserImplErrorTest, SwitchStmtCaseFallthroughMissingSemicolon) {
EXPECT("fn f() -> void { switch(1) { case 1: { fallthrough } case 2: {} } }",
"test.wgsl:1:52 error: missing ;\n"
"test.wgsl:1:52 error: expected ';' for fallthrough statement\n"
"fn f() -> void { switch(1) { case 1: { fallthrough } case 2: {} } }\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, VarStmtMissingSemicolon) {
EXPECT("fn f() -> void { var a : u32 }",
"test.wgsl:1:30 error: missing ;\n"
"test.wgsl:1:30 error: expected ';' for variable declaration\n"
"fn f() -> void { var a : u32 }\n"
" ^\n");
}

View File

@ -176,7 +176,7 @@ TEST_F(ForStmtErrorTest, MissingLeftParen) {
// Test a for loop with missing first semicolon is invalid.
TEST_F(ForStmtErrorTest, MissingFirstSemicolon) {
std::string for_str = "for () {}";
std::string error_str = "1:6: missing ';' after initializer in for loop";
std::string error_str = "1:6: expected ';' for initializer in for loop";
TestForWithError(for_str, error_str);
}
@ -184,7 +184,7 @@ TEST_F(ForStmtErrorTest, MissingFirstSemicolon) {
// Test a for loop with missing second semicolon is invalid.
TEST_F(ForStmtErrorTest, MissingSecondSemicolon) {
std::string for_str = "for (;) {}";
std::string error_str = "1:7: missing ';' after condition in for loop";
std::string error_str = "1:7: expected ';' for condition in for loop";
TestForWithError(for_str, error_str);
}
@ -225,7 +225,7 @@ TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
// variable_stmt | assignment_stmt | func_call_stmt.
TEST_F(ForStmtErrorTest, InvalidInitializerMatch) {
std::string for_str = "for (if (true) {} ;;) { }";
std::string error_str = "1:6: missing ';' after initializer in for loop";
std::string error_str = "1:6: expected ';' for initializer in for loop";
TestForWithError(for_str, error_str);
}
@ -242,7 +242,7 @@ TEST_F(ForStmtErrorTest, InvalidBreakConditionAsExpression) {
// logical_or_expression.
TEST_F(ForStmtErrorTest, InvalidBreakConditionMatch) {
std::string for_str = "for (; var i: i32 = 0;) { }";
std::string error_str = "1:8: missing ';' after condition in for loop";
std::string error_str = "1:8: expected ';' for condition in for loop";
TestForWithError(for_str, error_str);
}

View File

@ -166,7 +166,7 @@ TEST_F(ParserImplTest, FunctionDecl_InvalidBody) {
auto f = p->function_decl();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr);
EXPECT_EQ(p->error(), "1:28: missing ;");
EXPECT_EQ(p->error(), "1:28: expected ';' for return statement");
}
TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) {

View File

@ -52,7 +52,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
auto* p = parser("var<out> a : vec2<i32>");
p->global_decl();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:23: missing ';' for variable declaration");
EXPECT_EQ(p->error(), "1:23: expected ';' for variable declaration");
}
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
auto* p = parser("const a : vec2<i32> = vec2<i32>(1, 2)");
p->global_decl();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:38: missing ';' for constant declaration");
EXPECT_EQ(p->error(), "1:38: expected ';' for constant declaration");
}
TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
@ -124,7 +124,7 @@ TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
auto* p = parser("type A = i32");
p->global_decl();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:13: missing ';' for type alias");
EXPECT_EQ(p->error(), "1:13: expected ';' for type alias");
}
TEST_F(ParserImplTest, GlobalDecl_Function) {
@ -225,7 +225,7 @@ TEST_F(ParserImplTest, GlobalDecl_StructMissing_Semi) {
auto* p = parser("[[block]] struct A {}");
p->global_decl();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:22: missing ';' for struct declaration");
EXPECT_EQ(p->error(), "1:22: expected ';' for struct declaration");
}
} // namespace

View File

@ -86,7 +86,7 @@ TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:16: missing ;");
EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement");
}
TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
@ -94,7 +94,7 @@ TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:29: missing ;");
EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement");
}
} // namespace

View File

@ -66,7 +66,7 @@ TEST_F(ParserImplTest, Statement_Return_MissingSemi) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:7: missing ;");
EXPECT_EQ(p->error(), "1:7: expected ';' for return statement");
}
TEST_F(ParserImplTest, Statement_Return_Invalid) {
@ -74,7 +74,7 @@ TEST_F(ParserImplTest, Statement_Return_Invalid) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ;");
EXPECT_EQ(p->error(), "1:8: expected ';' for return statement");
}
TEST_F(ParserImplTest, Statement_If) {
@ -114,7 +114,7 @@ TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing ;");
EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration");
}
TEST_F(ParserImplTest, Statement_Switch) {
@ -170,7 +170,7 @@ TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ;");
EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement");
}
TEST_F(ParserImplTest, Statement_Break) {
@ -186,7 +186,7 @@ TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ;");
EXPECT_EQ(p->error(), "1:6: expected ';' for break statement");
}
TEST_F(ParserImplTest, Statement_Continue) {
@ -202,7 +202,7 @@ TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing ;");
EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement");
}
TEST_F(ParserImplTest, Statement_Discard) {
@ -218,7 +218,7 @@ TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) {
auto e = p->statement();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ;");
EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement");
}
TEST_F(ParserImplTest, Statement_Body) {

View File

@ -106,7 +106,7 @@ TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
auto m = p->struct_member();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ; for struct member");
EXPECT_EQ(p->error(), "1:8: expected ';' for struct member");
}
} // namespace