[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

@@ -0,0 +1,39 @@
// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ast/case_selector.h"
#include <utility>
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::CaseSelector);
namespace tint::ast {
CaseSelector::CaseSelector(ProgramID pid, NodeID nid, const Source& src, const ast::Expression* e)
: Base(pid, nid, src), expr(e) {}
CaseSelector::CaseSelector(CaseSelector&&) = default;
CaseSelector::~CaseSelector() = default;
const CaseSelector* CaseSelector::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);
auto ex = ctx->Clone(expr);
return ctx->dst->create<CaseSelector>(src, ex);
}
} // namespace tint::ast

View File

@@ -0,0 +1,52 @@
// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_AST_CASE_SELECTOR_H_
#define SRC_TINT_AST_CASE_SELECTOR_H_
#include <vector>
#include "src/tint/ast/block_statement.h"
#include "src/tint/ast/expression.h"
namespace tint::ast {
/// A case selector
class CaseSelector final : public Castable<CaseSelector, Node> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param src the source of this node
/// @param expr the selector expression, |nullptr| for a `default` selector
CaseSelector(ProgramID pid, NodeID nid, const Source& src, const Expression* expr = nullptr);
/// Move constructor
CaseSelector(CaseSelector&&);
~CaseSelector() override;
/// @returns true if this is a default statement
bool IsDefault() const { return expr == nullptr; }
/// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned node
const CaseSelector* Clone(CloneContext* ctx) const override;
/// The selector, nullptr for a default selector
const Expression* const expr = nullptr;
};
} // namespace tint::ast
#endif // SRC_TINT_AST_CASE_SELECTOR_H_

View File

@@ -0,0 +1,40 @@
// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ast/case_selector.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ast/test_helper.h"
using namespace tint::number_suffixes; // NOLINT
namespace tint::ast {
namespace {
using CaseSelectorTest = TestHelper;
TEST_F(CaseSelectorTest, NonDefault) {
auto* e = Expr(2_i);
auto* c = CaseSelector(e);
EXPECT_FALSE(c->IsDefault());
EXPECT_EQ(e, c->expr);
}
TEST_F(CaseSelectorTest, Default) {
auto* c = DefaultCaseSelector();
EXPECT_TRUE(c->IsDefault());
}
} // namespace
} // namespace tint::ast

View File

@@ -25,10 +25,11 @@ namespace tint::ast {
CaseStatement::CaseStatement(ProgramID pid,
NodeID nid,
const Source& src,
utils::VectorRef<const Expression*> s,
utils::VectorRef<const CaseSelector*> s,
const BlockStatement* b)
: Base(pid, nid, src), selectors(std::move(s)), body(b) {
TINT_ASSERT(AST, body);
TINT_ASSERT(AST, !selectors.IsEmpty());
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
for (auto* selector : selectors) {
TINT_ASSERT(AST, selector);
@@ -40,6 +41,15 @@ CaseStatement::CaseStatement(CaseStatement&&) = default;
CaseStatement::~CaseStatement() = default;
bool CaseStatement::ContainsDefault() const {
for (const auto* sel : selectors) {
if (sel->IsDefault()) {
return true;
}
}
return false;
}
const CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);

View File

@@ -18,7 +18,7 @@
#include <vector>
#include "src/tint/ast/block_statement.h"
#include "src/tint/ast/expression.h"
#include "src/tint/ast/case_selector.h"
namespace tint::ast {
@@ -34,23 +34,23 @@ class CaseStatement final : public Castable<CaseStatement, Statement> {
CaseStatement(ProgramID pid,
NodeID nid,
const Source& src,
utils::VectorRef<const Expression*> selectors,
utils::VectorRef<const CaseSelector*> selectors,
const BlockStatement* body);
/// Move constructor
CaseStatement(CaseStatement&&);
~CaseStatement() override;
/// @returns true if this is a default statement
bool IsDefault() const { return selectors.IsEmpty(); }
/// Clones this node and all transitive child nodes using the `CloneContext`
/// `ctx`.
/// @param ctx the clone context
/// @return the newly cloned node
const CaseStatement* Clone(CloneContext* ctx) const override;
/// @returns true if this item contains a default selector
bool ContainsDefault() const;
/// The case selectors, empty if none set
const utils::Vector<const Expression*, 4> selectors;
const utils::Vector<const CaseSelector*, 4> selectors;
/// The case body
const BlockStatement* const body;

View File

@@ -27,7 +27,7 @@ namespace {
using CaseStatementTest = TestHelper;
TEST_F(CaseStatementTest, Creation_i32) {
auto* selector = Expr(2_i);
auto* selector = CaseSelector(2_i);
utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
@@ -41,7 +41,7 @@ TEST_F(CaseStatementTest, Creation_i32) {
}
TEST_F(CaseStatementTest, Creation_u32) {
auto* selector = Expr(2_u);
auto* selector = CaseSelector(2_u);
utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
@@ -54,8 +54,20 @@ TEST_F(CaseStatementTest, Creation_u32) {
EXPECT_EQ(c->body->statements[0], discard);
}
TEST_F(CaseStatementTest, ContainsDefault_WithDefault) {
utils::Vector b{CaseSelector(2_u), DefaultCaseSelector()};
auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
EXPECT_TRUE(c->ContainsDefault());
}
TEST_F(CaseStatementTest, ContainsDefault_WithOutDefault) {
utils::Vector b{CaseSelector(2_u), CaseSelector(3_u)};
auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
EXPECT_FALSE(c->ContainsDefault());
}
TEST_F(CaseStatementTest, Creation_WithSource) {
utils::Vector b{Expr(2_i)};
utils::Vector b{CaseSelector(2_i)};
auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(),
@@ -66,22 +78,9 @@ TEST_F(CaseStatementTest, Creation_WithSource) {
EXPECT_EQ(src.range.begin.column, 2u);
}
TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) {
auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(),
});
auto* c = create<CaseStatement>(utils::Empty, body);
EXPECT_TRUE(c->IsDefault());
}
TEST_F(CaseStatementTest, IsDefault_WithSelectors) {
utils::Vector b{Expr(2_i)};
auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
EXPECT_FALSE(c->IsDefault());
}
TEST_F(CaseStatementTest, IsCase) {
auto* c = create<CaseStatement>(utils::Empty, create<BlockStatement>(utils::Empty));
auto* c = create<CaseStatement>(utils::Vector{DefaultCaseSelector()},
create<BlockStatement>(utils::Empty));
EXPECT_TRUE(c->Is<CaseStatement>());
}
@@ -89,7 +88,7 @@ TEST_F(CaseStatementTest, Assert_Null_Body) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.create<CaseStatement>(utils::Empty, nullptr);
b.create<CaseStatement>(utils::Vector{b.DefaultCaseSelector()}, nullptr);
},
"internal compiler error");
}
@@ -98,7 +97,7 @@ TEST_F(CaseStatementTest, Assert_Null_Selector) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.create<CaseStatement>(utils::Vector<const ast::IntLiteralExpression*, 1>{nullptr},
b.create<CaseStatement>(utils::Vector<const ast::CaseSelector*, 1>{nullptr},
b.create<BlockStatement>(utils::Empty));
},
"internal compiler error");
@@ -109,7 +108,8 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Call) {
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.create<CaseStatement>(utils::Empty, b2.create<BlockStatement>(utils::Empty));
b1.create<CaseStatement>(utils::Vector{b1.DefaultCaseSelector()},
b2.create<BlockStatement>(utils::Empty));
},
"internal compiler error");
}
@@ -119,7 +119,7 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Selector) {
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.create<CaseStatement>(utils::Vector{b2.Expr(2_i)},
b1.create<CaseStatement>(utils::Vector{b2.CaseSelector(b2.Expr(2_i))},
b1.create<BlockStatement>(utils::Empty));
},
"internal compiler error");

View File

@@ -25,7 +25,7 @@ namespace {
using SwitchStatementTest = TestHelper;
TEST_F(SwitchStatementTest, Creation) {
auto* case_stmt = create<CaseStatement>(utils::Vector{Expr(1_u)}, Block());
auto* case_stmt = create<CaseStatement>(utils::Vector{CaseSelector(1_u)}, Block());
auto* ident = Expr("ident");
utils::Vector body{case_stmt};
@@ -44,7 +44,7 @@ TEST_F(SwitchStatementTest, Creation_WithSource) {
}
TEST_F(SwitchStatementTest, IsSwitch) {
utils::Vector lit{Expr(2_i)};
utils::Vector lit{CaseSelector(2_i)};
auto* ident = Expr("ident");
utils::Vector body{create<CaseStatement>(lit, Block())};
@@ -58,7 +58,8 @@ TEST_F(SwitchStatementTest, Assert_Null_Condition) {
{
ProgramBuilder b;
CaseStatementList cases;
cases.Push(b.create<CaseStatement>(utils::Vector{b.Expr(1_i)}, b.Block()));
cases.Push(
b.create<CaseStatement>(utils::Vector{b.CaseSelector(b.Expr(1_i))}, b.Block()));
b.create<SwitchStatement>(nullptr, cases);
},
"internal compiler error");
@@ -82,7 +83,7 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_Condition) {
b1.create<SwitchStatement>(b2.Expr(true), utils::Vector{
b1.create<CaseStatement>(
utils::Vector{
b1.Expr(1_i),
b1.CaseSelector(b1.Expr(1_i)),
},
b1.Block()),
});
@@ -98,7 +99,7 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_CaseStatement) {
b1.create<SwitchStatement>(b1.Expr(true), utils::Vector{
b2.create<CaseStatement>(
utils::Vector{
b2.Expr(1_i),
b2.CaseSelector(b2.Expr(1_i)),
},
b2.Block()),
});