mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-12 14:46:08 +00:00
Add break-if support.
This CL adds support for `break-if` to Tint. Bug: tint:1633, tint:1451 Change-Id: I30dfd62a3e09255624ff76ebe0cdd3a3c7cf9c5f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106420 Auto-Submit: Dan Sinclair <dsinclair@chromium.org> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: dan sinclair <dsinclair@google.com>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
f8c07d4753
commit
b8b0c21918
@@ -19,6 +19,7 @@
|
||||
#include "src/tint/ast/array.h"
|
||||
#include "src/tint/ast/assignment_statement.h"
|
||||
#include "src/tint/ast/bitcast_expression.h"
|
||||
#include "src/tint/ast/break_if_statement.h"
|
||||
#include "src/tint/ast/break_statement.h"
|
||||
#include "src/tint/ast/call_statement.h"
|
||||
#include "src/tint/ast/continue_statement.h"
|
||||
@@ -2265,8 +2266,7 @@ ForHeader::ForHeader(const ast::Statement* init,
|
||||
|
||||
ForHeader::~ForHeader() = default;
|
||||
|
||||
// (variable_statement | variable_updating_statement |
|
||||
// func_call_statement)?
|
||||
// (variable_statement | variable_updating_statement | func_call_statement)?
|
||||
Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
|
||||
auto call = func_call_statement();
|
||||
if (call.errored) {
|
||||
@@ -2317,10 +2317,7 @@ Maybe<const ast::Statement*> ParserImpl::for_header_continuing() {
|
||||
}
|
||||
|
||||
// for_header
|
||||
// : (variable_statement | variable_updating_statement | func_call_statement)?
|
||||
// SEMICOLON
|
||||
// expression? SEMICOLON
|
||||
// (variable_updating_statement | func_call_statement)?
|
||||
// : for_header_initializer? SEMICOLON expression? SEMICOLON for_header_continuing?
|
||||
Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
|
||||
auto initializer = for_header_initializer();
|
||||
if (initializer.errored) {
|
||||
@@ -2444,28 +2441,58 @@ Maybe<const ast::ContinueStatement*> ParserImpl::continue_statement() {
|
||||
// break_if_statement:
|
||||
// 'break' 'if' expression semicolon
|
||||
Maybe<const ast::Statement*> ParserImpl::break_if_statement() {
|
||||
// TODO(crbug.com/tint/1451): Add support for break-if
|
||||
return Failure::kNoMatch;
|
||||
auto& t1 = peek();
|
||||
auto& t2 = peek(1);
|
||||
|
||||
// Match both the `break` and `if` at the same time.
|
||||
if (!t1.Is(Token::Type::kBreak) || !t2.Is(Token::Type::kIf)) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
next(); // Consume the peek
|
||||
next(); // Consume the peek
|
||||
|
||||
auto expr = expression();
|
||||
if (expr.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (!expr.matched) {
|
||||
return add_error(t1, "expected expression for `break if`");
|
||||
}
|
||||
if (!match(Token::Type::kSemicolon)) {
|
||||
return add_error(peek(), "expected ';' for `break if` statement");
|
||||
}
|
||||
|
||||
return create<ast::BreakIfStatement>(t1.source(), expr.value);
|
||||
}
|
||||
|
||||
// continuing_compound_statement:
|
||||
// brace_left statement* break_if_statement? brace_right
|
||||
Maybe<const ast::BlockStatement*> ParserImpl::continuing_compound_statement() {
|
||||
return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
|
||||
auto stmts = expect_statements();
|
||||
if (stmts.errored) {
|
||||
return Failure::kErrored;
|
||||
StatementList stmts;
|
||||
|
||||
while (continue_parsing()) {
|
||||
// Note, break-if has to parse before statements because statements includes `break`
|
||||
auto break_if = break_if_statement();
|
||||
if (break_if.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (break_if.matched) {
|
||||
stmts.Push(break_if.value);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto stmt = statement();
|
||||
if (stmt.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (!stmt.matched) {
|
||||
break;
|
||||
}
|
||||
stmts.Push(stmt.value);
|
||||
}
|
||||
|
||||
auto break_if = break_if_statement();
|
||||
if (break_if.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (break_if.matched) {
|
||||
stmts.value.Push(break_if.value);
|
||||
}
|
||||
|
||||
return create<ast::BlockStatement>(Source{}, stmts.value);
|
||||
return create<ast::BlockStatement>(Source{}, stmts);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -110,5 +110,57 @@ TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
|
||||
EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_Continuing_BreakIf) {
|
||||
auto p = parser("loop { continuing { break if 1 + 2 < 5; }}");
|
||||
auto e = p->loop_statement();
|
||||
EXPECT_TRUE(e.matched);
|
||||
EXPECT_FALSE(e.errored);
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_EQ(e->body->statements.Length(), 0u);
|
||||
ASSERT_EQ(e->continuing->statements.Length(), 1u);
|
||||
EXPECT_TRUE(e->continuing->statements[0]->Is<ast::BreakIfStatement>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_Continuing_BreakIf_MissingExpr) {
|
||||
auto p = parser("loop { continuing { break if; }}");
|
||||
auto e = p->loop_statement();
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:21: expected expression for `break if`");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_Continuing_BreakIf_InvalidExpr) {
|
||||
auto p = parser("loop { continuing { break if switch; }}");
|
||||
auto e = p->loop_statement();
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:21: expected expression for `break if`");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_NoContinuing_BreakIf) {
|
||||
auto p = parser("loop { break if true; }");
|
||||
auto e = p->loop_statement();
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:14: expected ';' for break statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_Continuing_BreakIf_MissingSemicolon) {
|
||||
auto p = parser("loop { continuing { break if 1 + 2 < 5 }}");
|
||||
auto e = p->loop_statement();
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:40: expected ';' for `break if` statement");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
||||
|
||||
Reference in New Issue
Block a user