diff --git a/BUILD.gn b/BUILD.gn index 035e61fb99..24a19b0706 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -229,6 +229,8 @@ source_set("libtint_core_src") { "src/ast/binary_expression.h", "src/ast/binding_decoration.cc", "src/ast/binding_decoration.h", + "src/ast/block_statement.cc", + "src/ast/block_statement.h", "src/ast/bool_literal.cc", "src/ast/bool_literal.h", "src/ast/break_statement.cc", @@ -667,6 +669,7 @@ source_set("tint_unittests_core_src") { "src/ast/assignment_statement_test.cc", "src/ast/binary_expression_test.cc", "src/ast/binding_decoration_test.cc", + "src/ast/block_statement_test.cc", "src/ast/bool_literal_test.cc", "src/ast/break_statement_test.cc", "src/ast/builtin_decoration_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49304eb94f..a5bd4b9e41 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,8 @@ set(TINT_LIB_SRCS ast/binary_expression.h ast/binding_decoration.cc ast/binding_decoration.h + ast/block_statement.cc + ast/block_statement.h ast/bool_literal.h ast/bool_literal.cc ast/break_statement.cc @@ -278,6 +280,7 @@ set(TINT_TEST_SRCS ast/as_expression_test.cc ast/assignment_statement_test.cc ast/binding_decoration_test.cc + ast/block_statement_test.cc ast/bool_literal_test.cc ast/break_statement_test.cc ast/builtin_decoration_test.cc diff --git a/src/ast/block_statement.cc b/src/ast/block_statement.cc new file mode 100644 index 0000000000..33ee8c3653 --- /dev/null +++ b/src/ast/block_statement.cc @@ -0,0 +1,54 @@ +// Copyright 2020 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/ast/block_statement.h" + +namespace tint { +namespace ast { + +BlockStatement::BlockStatement() : Statement() {} + +BlockStatement::BlockStatement(const Source& source) : Statement(source) {} + +BlockStatement::BlockStatement(BlockStatement&&) = default; + +BlockStatement::~BlockStatement() = default; + +bool BlockStatement::IsBlock() const { + return true; +} + +bool BlockStatement::IsValid() const { + for (const auto& stmt : *this) { + if (stmt == nullptr || !stmt->IsValid()) { + return false; + } + } + return true; +} + +void BlockStatement::to_str(std::ostream& out, size_t indent) const { + make_indent(out, indent); + out << "Block{" << std::endl; + + for (const auto& stmt : *this) { + stmt->to_str(out, indent + 2); + } + + make_indent(out, indent); + out << "}" << std::endl; +} + +} // namespace ast +} // namespace tint diff --git a/src/ast/block_statement.h b/src/ast/block_statement.h new file mode 100644 index 0000000000..c7c15877d1 --- /dev/null +++ b/src/ast/block_statement.h @@ -0,0 +1,88 @@ +// Copyright 2020 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_AST_BLOCK_STATEMENT_H_ +#define SRC_AST_BLOCK_STATEMENT_H_ + +#include +#include +#include + +#include "src/ast/statement.h" + +namespace tint { +namespace ast { + +/// A block statement +class BlockStatement : public Statement { + public: + /// Constructor + BlockStatement(); + /// Constructor + /// @param source the block statement source + explicit BlockStatement(const Source& source); + /// Move constructor + BlockStatement(BlockStatement&&); + ~BlockStatement() override; + + /// Appends a statement to the block + /// @param stmt the statement to append + void append(std::unique_ptr stmt) { + statements_.push_back(std::move(stmt)); + } + + /// @returns the number of statements directly in the block + size_t size() const { return statements_.size(); } + + /// Retrieves the statement at |idx| + /// @param idx the index. The index is not bounds checked. + /// @returns the statement at |idx| + ast::Statement* operator[](size_t idx) { return statements_[idx].get(); } + /// Retrieves the statement at |idx| + /// @param idx the index. The index is not bounds checked. + /// @returns the statement at |idx| + const ast::Statement* operator[](size_t idx) const { + return statements_[idx].get(); + } + + /// @returns the beginning iterator + std::vector>::const_iterator begin() const { + return statements_.begin(); + } + /// @returns the ending iterator + std::vector>::const_iterator end() const { + return statements_.end(); + } + + /// @returns true if this is a block statement + bool IsBlock() const override; + + /// @returns true if the node is valid + bool IsValid() const override; + + /// Writes a representation of the node to the output stream + /// @param out the stream to write to + /// @param indent number of spaces to indent the node when writing + void to_str(std::ostream& out, size_t indent) const override; + + private: + BlockStatement(const BlockStatement&) = delete; + + std::vector> statements_; +}; + +} // namespace ast +} // namespace tint + +#endif // SRC_AST_BLOCK_STATEMENT_H_ diff --git a/src/ast/block_statement_test.cc b/src/ast/block_statement_test.cc new file mode 100644 index 0000000000..f0a6cbd263 --- /dev/null +++ b/src/ast/block_statement_test.cc @@ -0,0 +1,91 @@ +// Copyright 2020 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/ast/block_statement.h" + +#include +#include + +#include "gtest/gtest.h" +#include "src/ast/discard_statement.h" +#include "src/ast/if_statement.h" + +namespace tint { +namespace ast { +namespace { + +using BlockStatementTest = testing::Test; + +TEST_F(BlockStatementTest, Creation) { + auto d = std::make_unique(); + auto* ptr = d.get(); + + BlockStatement b; + b.append(std::move(d)); + + ASSERT_EQ(b.size(), 1u); + EXPECT_EQ(b[0], ptr); +} + +TEST_F(BlockStatementTest, Creation_WithSource) { + BlockStatement b(Source{20, 2}); + auto src = b.source(); + EXPECT_EQ(src.line, 20u); + EXPECT_EQ(src.column, 2u); +} + +TEST_F(BlockStatementTest, IsBlock) { + BlockStatement b; + EXPECT_TRUE(b.IsBlock()); +} + +TEST_F(BlockStatementTest, IsValid) { + BlockStatement b; + b.append(std::make_unique()); + EXPECT_TRUE(b.IsValid()); +} + +TEST_F(BlockStatementTest, IsValid_Empty) { + BlockStatement b; + EXPECT_TRUE(b.IsValid()); +} + +TEST_F(BlockStatementTest, IsValid_NullBodyStatement) { + BlockStatement b; + b.append(std::make_unique()); + b.append(nullptr); + EXPECT_FALSE(b.IsValid()); +} + +TEST_F(BlockStatementTest, IsValid_InvalidBodyStatement) { + BlockStatement b; + b.append(std::make_unique()); + EXPECT_FALSE(b.IsValid()); +} + +TEST_F(BlockStatementTest, ToStr) { + BlockStatement b; + b.append(std::make_unique()); + + std::ostringstream out; + b.to_str(out, 2); + EXPECT_EQ(out.str(), R"( Block{ + Discard{} + } +)"); +} + +} // namespace +} // namespace ast +} // namespace tint diff --git a/src/ast/statement.cc b/src/ast/statement.cc index 43441dad63..f63487f593 100644 --- a/src/ast/statement.cc +++ b/src/ast/statement.cc @@ -17,6 +17,7 @@ #include #include "src/ast/assignment_statement.h" +#include "src/ast/block_statement.h" #include "src/ast/break_statement.h" #include "src/ast/call_statement.h" #include "src/ast/case_statement.h" @@ -45,6 +46,10 @@ bool Statement::IsAssign() const { return false; } +bool Statement::IsBlock() const { + return false; +} + bool Statement::IsBreak() const { return false; } @@ -98,6 +103,11 @@ const AssignmentStatement* Statement::AsAssign() const { return static_cast(this); } +const BlockStatement* Statement::AsBlock() const { + assert(IsBlock()); + return static_cast(this); +} + const BreakStatement* Statement::AsBreak() const { assert(IsBreak()); return static_cast(this); @@ -163,6 +173,11 @@ AssignmentStatement* Statement::AsAssign() { return static_cast(this); } +BlockStatement* Statement::AsBlock() { + assert(IsBlock()); + return static_cast(this); +} + BreakStatement* Statement::AsBreak() { assert(IsBreak()); return static_cast(this); diff --git a/src/ast/statement.h b/src/ast/statement.h index 4f259bb9f3..7df9aea6cc 100644 --- a/src/ast/statement.h +++ b/src/ast/statement.h @@ -24,6 +24,7 @@ namespace tint { namespace ast { class AssignmentStatement; +class BlockStatement; class BreakStatement; class CallStatement; class CaseStatement; @@ -44,6 +45,8 @@ class Statement : public Node { /// @returns true if this is an assign statement virtual bool IsAssign() const; + /// @returns true if this is a block statement + virtual bool IsBlock() const; /// @returns true if this is a break statement virtual bool IsBreak() const; /// @returns true if this is a call statement @@ -71,6 +74,8 @@ class Statement : public Node { /// @returns the statement as a const assign statement const AssignmentStatement* AsAssign() const; + /// @returns the statement as a const block statement + const BlockStatement* AsBlock() const; /// @returns the statement as a const break statement const BreakStatement* AsBreak() const; /// @returns the statement as a const call statement @@ -98,6 +103,8 @@ class Statement : public Node { /// @returns the statement as an assign statement AssignmentStatement* AsAssign(); + /// @returns the statement as a block statement + BlockStatement* AsBlock(); /// @returns the statement as a break statement BreakStatement* AsBreak(); /// @returns the statement as a call statement