diff --git a/BUILD.gn b/BUILD.gn index 1c0b35a865..e6c7e62876 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -239,6 +239,8 @@ source_set("libtint_core_src") { "src/ast/builtin_decoration.h", "src/ast/call_expression.cc", "src/ast/call_expression.h", + "src/ast/call_statement.cc", + "src/ast/call_statement.h", "src/ast/case_statement.cc", "src/ast/case_statement.h", "src/ast/cast_expression.cc", @@ -655,6 +657,7 @@ source_set("tint_unittests_core_src") { "src/ast/break_statement_test.cc", "src/ast/builtin_decoration_test.cc", "src/ast/call_expression_test.cc", + "src/ast/call_statement_test.cc", "src/ast/case_statement_test.cc", "src/ast/cast_expression_test.cc", "src/ast/continue_statement_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed8c279075..4c0c107f63 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,8 @@ set(TINT_LIB_SRCS ast/builtin_decoration.h ast/call_expression.cc ast/call_expression.h + ast/call_statement.cc + ast/call_statement.h ast/case_statement.cc ast/case_statement.h ast/cast_expression.cc @@ -278,6 +280,7 @@ set(TINT_TEST_SRCS ast/break_statement_test.cc ast/builtin_decoration_test.cc ast/call_expression_test.cc + ast/call_statement_test.cc ast/case_statement_test.cc ast/cast_expression_test.cc ast/continue_statement_test.cc diff --git a/src/ast/call_statement.cc b/src/ast/call_statement.cc new file mode 100644 index 0000000000..9bc4925ff1 --- /dev/null +++ b/src/ast/call_statement.cc @@ -0,0 +1,44 @@ +// 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/call_statement.h" + +#include "src/ast/call_expression.h" + +namespace tint { +namespace ast { + +CallStatement::CallStatement() : Statement() {} + +CallStatement::CallStatement(std::unique_ptr call) + : Statement(), call_(std::move(call)) {} + +CallStatement::CallStatement(CallStatement&&) = default; + +CallStatement::~CallStatement() = default; + +bool CallStatement::IsCall() const { + return true; +} + +bool CallStatement::IsValid() const { + return call_ != nullptr && call_->IsValid(); +} + +void CallStatement::to_str(std::ostream& out, size_t indent) const { + call_->to_str(out, indent); +} + +} // namespace ast +} // namespace tint diff --git a/src/ast/call_statement.h b/src/ast/call_statement.h new file mode 100644 index 0000000000..374136b726 --- /dev/null +++ b/src/ast/call_statement.h @@ -0,0 +1,67 @@ +// 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_CALL_STATEMENT_H_ +#define SRC_AST_CALL_STATEMENT_H_ + +#include +#include + +#include "src/ast/call_expression.h" +#include "src/ast/statement.h" + +namespace tint { +namespace ast { + +/// A call expression +class CallStatement : public Statement { + public: + /// Constructor + CallStatement(); + /// Constructor + /// @param call the function + explicit CallStatement(std::unique_ptr call); + /// Move constructor + CallStatement(CallStatement&&); + ~CallStatement() override; + + /// Sets the call expression + /// @param call the call + void set_expr(std::unique_ptr call) { + call_ = std::move(call); + } + /// @returns the call expression + CallExpression* expr() const { return call_.get(); } + + /// @returns true if this is a call statement + bool IsCall() 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: + CallStatement(const CallStatement&) = delete; + + std::unique_ptr call_; +}; + +} // namespace ast +} // namespace tint + +#endif // SRC_AST_CALL_STATEMENT_H_ diff --git a/src/ast/call_statement_test.cc b/src/ast/call_statement_test.cc new file mode 100644 index 0000000000..62b2134ede --- /dev/null +++ b/src/ast/call_statement_test.cc @@ -0,0 +1,73 @@ +// 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/call_statement.h" + +#include "gtest/gtest.h" +#include "src/ast/call_expression.h" +#include "src/ast/identifier_expression.h" + +namespace tint { +namespace ast { +namespace { + +using CallStatementTest = testing::Test; + +TEST_F(CallStatementTest, Creation) { + auto expr = std::make_unique( + std::make_unique("func"), ExpressionList{}); + auto* expr_ptr = expr.get(); + + CallStatement c(std::move(expr)); + EXPECT_EQ(c.expr(), expr_ptr); +} + +TEST_F(CallStatementTest, IsCall) { + CallStatement c; + EXPECT_TRUE(c.IsCall()); +} + +TEST_F(CallStatementTest, IsValid) { + CallStatement c(std::make_unique( + std::make_unique("func"), ExpressionList{})); + EXPECT_TRUE(c.IsValid()); +} + +TEST_F(CallStatementTest, IsValid_MissingExpr) { + CallStatement c; + EXPECT_FALSE(c.IsValid()); +} + +TEST_F(CallStatementTest, IsValid_InvalidExpr) { + CallStatement c(std::make_unique()); + EXPECT_FALSE(c.IsValid()); +} + +TEST_F(CallStatementTest, ToStr) { + CallStatement c(std::make_unique( + std::make_unique("func"), ExpressionList{})); + + std::ostringstream out; + c.to_str(out, 2); + EXPECT_EQ(out.str(), R"( Call{ + Identifier{func} + ( + ) + } +)"); +} + +} // namespace +} // namespace ast +} // namespace tint diff --git a/src/ast/statement.cc b/src/ast/statement.cc index 3ff8941d18..884c95475d 100644 --- a/src/ast/statement.cc +++ b/src/ast/statement.cc @@ -18,6 +18,7 @@ #include "src/ast/assignment_statement.h" #include "src/ast/break_statement.h" +#include "src/ast/call_statement.h" #include "src/ast/case_statement.h" #include "src/ast/continue_statement.h" #include "src/ast/else_statement.h" @@ -52,6 +53,10 @@ bool Statement::IsCase() const { return false; } +bool Statement::IsCall() const { + return false; +} + bool Statement::IsContinue() const { return false; } @@ -98,6 +103,11 @@ const BreakStatement* Statement::AsBreak() const { return static_cast(this); } +const CallStatement* Statement::AsCall() const { + assert(IsCall()); + return static_cast(this); +} + const CaseStatement* Statement::AsCase() const { assert(IsCase()); return static_cast(this); @@ -158,6 +168,11 @@ BreakStatement* Statement::AsBreak() { return static_cast(this); } +CallStatement* Statement::AsCall() { + assert(IsCall()); + return static_cast(this); +} + CaseStatement* Statement::AsCase() { assert(IsCase()); return static_cast(this); diff --git a/src/ast/statement.h b/src/ast/statement.h index 1dd56b39f8..f887ffbb61 100644 --- a/src/ast/statement.h +++ b/src/ast/statement.h @@ -25,6 +25,7 @@ namespace ast { class AssignmentStatement; class BreakStatement; +class CallStatement; class CaseStatement; class ContinueStatement; class ElseStatement; @@ -45,6 +46,8 @@ class Statement : public Node { virtual bool IsAssign() const; /// @returns true if this is a break statement virtual bool IsBreak() const; + /// @returns true if this is a call statement + virtual bool IsCall() const; /// @returns true if this is a case statement virtual bool IsCase() const; /// @returns true if this is a continue statement @@ -70,6 +73,8 @@ class Statement : public Node { const AssignmentStatement* AsAssign() const; /// @returns the statement as a const break statement const BreakStatement* AsBreak() const; + /// @returns the statement as a const call statement + const CallStatement* AsCall() const; /// @returns the statement as a const case statement const CaseStatement* AsCase() const; /// @returns the statement as a const continue statement @@ -95,6 +100,8 @@ class Statement : public Node { AssignmentStatement* AsAssign(); /// @returns the statement as a break statement BreakStatement* AsBreak(); + /// @returns the statement as a call statement + CallStatement* AsCall(); /// @returns the statement as a case statement CaseStatement* AsCase(); /// @returns the statement as a continue statement