[WGSL] Allow default as a case selector

This CL updates the WGSL parser to parse `default` as a case selector
value.

Bug: tint:1633
Change-Id: I57661d25924e36bec5c03f96399c557fb7bbf760
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106382
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair
2022-10-19 15:55:02 +00:00
committed by Dawn LUCI CQ
parent d27151d333
commit f148f0891b
62 changed files with 1212 additions and 367 deletions

View File

@@ -3024,7 +3024,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
for (size_t i = last_clause_index;; --i) {
// Create a list of integer literals for the selector values leading to
// this case clause.
utils::Vector<const ast::Expression*, 4> selectors;
utils::Vector<const ast::CaseSelector*, 4> selectors;
const bool has_selectors = clause_heads[i]->case_values.has_value();
if (has_selectors) {
auto values = clause_heads[i]->case_values.value();
@@ -3034,15 +3034,26 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
// The Tint AST handles 32-bit values.
const uint32_t value32 = uint32_t(value & 0xFFFFFFFF);
if (selector.type->IsUnsignedScalarOrVector()) {
selectors.Push(create<ast::IntLiteralExpression>(
Source{}, value32, ast::IntLiteralExpression::Suffix::kU));
selectors.Push(create<ast::CaseSelector>(
Source{}, create<ast::IntLiteralExpression>(
Source{}, value32, ast::IntLiteralExpression::Suffix::kU)));
} else {
selectors.Push(
selectors.Push(create<ast::CaseSelector>(
Source{},
create<ast::IntLiteralExpression>(Source{}, static_cast<int32_t>(value32),
ast::IntLiteralExpression::Suffix::kI));
ast::IntLiteralExpression::Suffix::kI)));
}
}
if ((default_info == clause_heads[i]) && construct->ContainsPos(default_info->pos)) {
// Generate a default selector
selectors.Push(create<ast::CaseSelector>(Source{}));
}
} else {
// Generate a default selector
selectors.Push(create<ast::CaseSelector>(Source{}));
}
TINT_ASSERT(Reader, !selectors.IsEmpty());
// Where does this clause end?
const auto end_id =
@@ -3057,17 +3068,6 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
swch->cases[case_idx] = create<ast::CaseStatement>(Source{}, selectors, body);
});
if ((default_info == clause_heads[i]) && has_selectors &&
construct->ContainsPos(default_info->pos)) {
// Generate a default clause with a just fallthrough.
auto* stmts = create<ast::BlockStatement>(
Source{}, StatementList{
create<ast::FallthroughStatement>(Source{}),
});
auto* case_stmt = create<ast::CaseStatement>(Source{}, utils::Empty, stmts);
swch->cases.Push(case_stmt);
}
if (i == 0) {
break;
}

View File

@@ -9349,10 +9349,7 @@ switch(42u) {
case 20u: {
var_1 = 20u;
}
default: {
fallthrough;
}
case 30u: {
case 30u, default: {
var_1 = 30u;
}
}

View File

@@ -1393,10 +1393,7 @@ TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_InMerge_PredecessorsDominatdB
auto got = test::ToString(p->program(), ast_body);
auto* expect = R"(var x_41 : u32;
switch(1u) {
default: {
fallthrough;
}
case 0u: {
case 0u, default: {
fallthrough;
}
case 1u: {

View File

@@ -2129,6 +2129,9 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
}
selector_list = std::move(selectors.value);
} else {
// Push the default case selector
selector_list.Push(create<ast::CaseSelector>(t.source()));
}
// Consume the optional colon if present.
@@ -2148,12 +2151,12 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
}
// case_selectors
// : expression (COMMA expression)* COMMA?
// : case_selector (COMMA case_selector)* COMMA?
Expect<ParserImpl::CaseSelectorList> ParserImpl::expect_case_selectors() {
CaseSelectorList selectors;
while (continue_parsing()) {
auto expr = expression();
auto expr = case_selector();
if (expr.errored) {
return Failure::kErrored;
}
@@ -2168,12 +2171,32 @@ Expect<ParserImpl::CaseSelectorList> ParserImpl::expect_case_selectors() {
}
if (selectors.IsEmpty()) {
return add_error(peek(), "unable to parse case selectors");
return add_error(peek(), "expected case selector expression or `default`");
}
return selectors;
}
// case_selector
// : DEFAULT
// | expression
Maybe<const ast::CaseSelector*> ParserImpl::case_selector() {
auto& p = peek();
if (match(Token::Type::kDefault)) {
return create<ast::CaseSelector>(p.source());
}
auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return Failure::kNoMatch;
}
return create<ast::CaseSelector>(p.source(), expr.value);
}
// case_body
// :
// | statement case_body

View File

@@ -74,7 +74,7 @@ class ParserImpl {
/// Pre-determined small vector sizes for AST pointers
//! @cond Doxygen_Suppress
using AttributeList = utils::Vector<const ast::Attribute*, 4>;
using CaseSelectorList = utils::Vector<const ast::Expression*, 4>;
using CaseSelectorList = utils::Vector<const ast::CaseSelector*, 4>;
using CaseStatementList = utils::Vector<const ast::CaseStatement*, 4>;
using ExpressionList = utils::Vector<const ast::Expression*, 8>;
using ParameterList = utils::Vector<const ast::Parameter*, 8>;
@@ -573,6 +573,9 @@ class ParserImpl {
/// Parses a `case_selectors` grammar element
/// @returns the list of literals
Expect<CaseSelectorList> expect_case_selectors();
/// Parses a `case_selector` grammar element
/// @returns the selector
Maybe<const ast::CaseSelector*> case_selector();
/// Parses a `case_body` grammar element
/// @returns the parsed statements
Maybe<const ast::BlockStatement*> case_body();

View File

@@ -1333,7 +1333,7 @@ fn f() { switch(1) {
TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase) {
EXPECT("fn f() { switch(1) { case ^: } }",
R"(test.wgsl:1:27 error: unable to parse case selectors
R"(test.wgsl:1:27 error: expected case selector expression or `default`
fn f() { switch(1) { case ^: } }
^
)");

View File

@@ -143,7 +143,7 @@ TEST_F(ParserImplTest, Statement_Switch_Invalid) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:18: unable to parse case selectors");
EXPECT_EQ(p->error(), "1:18: expected case selector expression or `default`");
}
TEST_F(ParserImplTest, Statement_Loop) {

View File

@@ -25,13 +25,16 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
auto* sel = stmt->selectors[0];
EXPECT_FALSE(sel->IsDefault());
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->body->statements.Length(), 1u);
@@ -46,12 +49,16 @@ TEST_F(ParserImplTest, SwitchBody_Case_Expression) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::BinaryExpression>());
auto* expr = stmt->selectors[0]->As<ast::BinaryExpression>();
auto* sel = stmt->selectors[0];
EXPECT_FALSE(sel->IsDefault());
ASSERT_TRUE(sel->expr->Is<ast::BinaryExpression>());
auto* expr = sel->expr->As<ast::BinaryExpression>();
EXPECT_EQ(ast::BinaryOp::kAdd, expr->op);
auto* v = expr->lhs->As<ast::IntLiteralExpression>();
@@ -74,13 +81,16 @@ TEST_F(ParserImplTest, SwitchBody_Case_WithColon) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 1u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* sel = stmt->selectors[0];
EXPECT_FALSE(sel->IsDefault());
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_EQ(e->body->statements.Length(), 1u);
@@ -95,17 +105,20 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 2u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* sel = stmt->selectors[0];
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[1]->Is<ast::IntLiteralExpression>());
expr = stmt->selectors[1]->As<ast::IntLiteralExpression>();
sel = stmt->selectors[1];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
expr = sel->expr->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
@@ -118,18 +131,20 @@ TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma_WithColon) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
auto* stmt = e->As<ast::CaseStatement>();
ASSERT_EQ(stmt->selectors.Length(), 2u);
ASSERT_TRUE(stmt->selectors[0]->Is<ast::IntLiteralExpression>());
auto* sel = stmt->selectors[0];
auto* expr = stmt->selectors[0]->As<ast::IntLiteralExpression>();
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(stmt->selectors[1]->Is<ast::IntLiteralExpression>());
expr = stmt->selectors[1]->As<ast::IntLiteralExpression>();
sel = stmt->selectors[1];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
expr = sel->expr->As<ast::IntLiteralExpression>();
EXPECT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
@@ -141,7 +156,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_Invalid) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
EXPECT_EQ(p->error(), "1:6: expected case selector expression or `default`");
}
TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
@@ -151,7 +166,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:5: unable to parse case selectors");
EXPECT_EQ(p->error(), "1:5: expected case selector expression or `default`");
}
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
@@ -202,17 +217,46 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_TRUE(e->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = e->selectors[0]->As<ast::IntLiteralExpression>();
auto* sel = e->selectors[0];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[1]->Is<ast::IntLiteralExpression>());
expr = e->selectors[1]->As<ast::IntLiteralExpression>();
sel = e->selectors[1];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_with_default) {
auto p = parser("case 1, default, 2 { }");
auto e = p->switch_body();
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_TRUE(e->ContainsDefault());
ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->selectors.Length(), 3u);
auto* sel = e->selectors[0];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
EXPECT_TRUE(e->selectors[1]->IsDefault());
sel = e->selectors[2];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
@@ -225,17 +269,19 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_WithColon) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_FALSE(e->IsDefault());
EXPECT_FALSE(e->ContainsDefault());
ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->selectors.Length(), 2u);
ASSERT_TRUE(e->selectors[0]->Is<ast::IntLiteralExpression>());
auto* expr = e->selectors[0]->As<ast::IntLiteralExpression>();
auto* sel = e->selectors[0];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
auto* expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 1);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
ASSERT_TRUE(e->selectors[1]->Is<ast::IntLiteralExpression>());
expr = e->selectors[1]->As<ast::IntLiteralExpression>();
sel = e->selectors[1];
ASSERT_TRUE(sel->expr->Is<ast::IntLiteralExpression>());
expr = sel->expr->As<ast::IntLiteralExpression>();
ASSERT_EQ(expr->value, 2);
EXPECT_EQ(expr->suffix, ast::IntLiteralExpression::Suffix::kNone);
}
@@ -257,7 +303,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsStartsWithComma) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
EXPECT_EQ(p->error(), "1:6: expected case selector expression or `default`");
}
TEST_F(ParserImplTest, SwitchBody_Default) {
@@ -268,7 +314,7 @@ TEST_F(ParserImplTest, SwitchBody_Default) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_TRUE(e->IsDefault());
EXPECT_TRUE(e->ContainsDefault());
ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}
@@ -281,7 +327,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_WithColon) {
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::CaseStatement>());
EXPECT_TRUE(e->IsDefault());
EXPECT_TRUE(e->ContainsDefault());
ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
}

View File

@@ -29,8 +29,8 @@ TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
ASSERT_EQ(e->body.Length(), 2u);
EXPECT_FALSE(e->body[0]->IsDefault());
EXPECT_FALSE(e->body[1]->IsDefault());
EXPECT_FALSE(e->body[0]->ContainsDefault());
EXPECT_FALSE(e->body[1]->ContainsDefault());
}
TEST_F(ParserImplTest, SwitchStmt_Empty) {
@@ -58,9 +58,24 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
ASSERT_EQ(e->body.Length(), 3u);
ASSERT_FALSE(e->body[0]->IsDefault());
ASSERT_TRUE(e->body[1]->IsDefault());
ASSERT_FALSE(e->body[2]->IsDefault());
ASSERT_FALSE(e->body[0]->ContainsDefault());
ASSERT_TRUE(e->body[1]->ContainsDefault());
ASSERT_FALSE(e->body[2]->ContainsDefault());
}
TEST_F(ParserImplTest, SwitchStmt_Default_Mixed) {
auto p = parser(R"(switch a {
case 1, default, 2: {}
})");
auto e = p->switch_statement();
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->Is<ast::SwitchStatement>());
ASSERT_EQ(e->body.Length(), 1u);
ASSERT_TRUE(e->body[0]->ContainsDefault());
}
TEST_F(ParserImplTest, SwitchStmt_WithParens) {
@@ -123,7 +138,7 @@ TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "2:7: unable to parse case selectors");
EXPECT_EQ(p->error(), "2:7: expected case selector expression or `default`");
}
} // namespace