ast: Replace IsValid() with TINT_ASSERT()
The readers must not produce invalid ASTs. If readers cannot produce a valid AST, then they should error instead. If a reader does produce an invalid AST, this change catches this bad behavior early, significantly helping identify the root of the broken logic. IsValid() made a bit more sense in the days where the AST was mutable, and was constructed by calling setters on the nodes to build up the tree. In order to detect bad ASTs, IsValid() would have to perform an entire AST traversal and give a yes / no answer for the entire tree. Not only was this slow, an answer of 'no' didn't tell you *where* the AST was invalid, resulting in a lot of manual debugging. Now that the AST is fully immutable, all child nodes need to be built before their parents. The AST node constructors now become a perfect place to perform pointer sanity checking. The argument for attempting to catch and handle invalid ASTs is not a compelling one. Invalid ASTs are invalid compiler behavior, not something that should ever happen with a correctly functioning compiler. If this were to happen in production, the user would be utterly clueless to _why_ the program is invalid, or _how_ to fix it. Attempting to handle invalid ASTs is just masking a much larger problem. Let's just let the fuzzers do their job to catch any of these cases early. Fixed: chromium:1185569 Change-Id: I6496426a3a9da9d42627d2c1ca23917bfd04cc5c Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44048 Commit-Queue: Ben Clayton <bclayton@chromium.org> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
6ce58becd2
commit
8454d824d4
|
@ -24,7 +24,10 @@ namespace ast {
|
||||||
ArrayAccessorExpression::ArrayAccessorExpression(const Source& source,
|
ArrayAccessorExpression::ArrayAccessorExpression(const Source& source,
|
||||||
Expression* array,
|
Expression* array,
|
||||||
Expression* idx_expr)
|
Expression* idx_expr)
|
||||||
: Base(source), array_(array), idx_expr_(idx_expr) {}
|
: Base(source), array_(array), idx_expr_(idx_expr) {
|
||||||
|
TINT_ASSERT(array_);
|
||||||
|
TINT_ASSERT(idx_expr_);
|
||||||
|
}
|
||||||
|
|
||||||
ArrayAccessorExpression::ArrayAccessorExpression(ArrayAccessorExpression&&) =
|
ArrayAccessorExpression::ArrayAccessorExpression(ArrayAccessorExpression&&) =
|
||||||
default;
|
default;
|
||||||
|
@ -40,15 +43,6 @@ ArrayAccessorExpression* ArrayAccessorExpression::Clone(
|
||||||
return ctx->dst->create<ArrayAccessorExpression>(src, arr, idx);
|
return ctx->dst->create<ArrayAccessorExpression>(src, arr, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArrayAccessorExpression::IsValid() const {
|
|
||||||
if (array_ == nullptr || !array_->IsValid())
|
|
||||||
return false;
|
|
||||||
if (idx_expr_ == nullptr || !idx_expr_->IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArrayAccessorExpression::to_str(const semantic::Info& sem,
|
void ArrayAccessorExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -47,9 +47,6 @@ class ArrayAccessorExpression
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
ArrayAccessorExpression* Clone(CloneContext* ctx) const override;
|
ArrayAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -48,40 +49,22 @@ TEST_F(ArrayAccessorExpressionTest, IsArrayAccessor) {
|
||||||
EXPECT_TRUE(exp->Is<ArrayAccessorExpression>());
|
EXPECT_TRUE(exp->Is<ArrayAccessorExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ArrayAccessorExpressionTest, IsValid) {
|
TEST_F(ArrayAccessorExpressionTest, Assert_NullArray) {
|
||||||
auto* ary = Expr("ary");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* idx = Expr("idx");
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
b.create<ArrayAccessorExpression>(nullptr, b.Expr("idx"));
|
||||||
EXPECT_TRUE(exp->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ArrayAccessorExpressionTest, IsValid_MissingArray) {
|
TEST_F(ArrayAccessorExpressionTest, Assert_NullIndex) {
|
||||||
auto* idx = Expr("idx");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* exp = create<ArrayAccessorExpression>(nullptr, idx);
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(exp->IsValid());
|
b.create<ArrayAccessorExpression>(b.Expr("arr"), nullptr);
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(ArrayAccessorExpressionTest, IsValid_MissingIndex) {
|
|
||||||
auto* ary = Expr("ary");
|
|
||||||
|
|
||||||
auto* exp = create<ArrayAccessorExpression>(ary, nullptr);
|
|
||||||
EXPECT_FALSE(exp->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ArrayAccessorExpressionTest, IsValid_InvalidArray) {
|
|
||||||
auto* ary = Expr("");
|
|
||||||
auto* idx = Expr("idx");
|
|
||||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
|
||||||
EXPECT_FALSE(exp->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ArrayAccessorExpressionTest, IsValid_InvalidIndex) {
|
|
||||||
auto* ary = Expr("ary");
|
|
||||||
auto* idx = Expr("");
|
|
||||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
|
||||||
EXPECT_FALSE(exp->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ArrayAccessorExpressionTest, ToStr) {
|
TEST_F(ArrayAccessorExpressionTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
||||||
AssignmentStatement::AssignmentStatement(const Source& source,
|
AssignmentStatement::AssignmentStatement(const Source& source,
|
||||||
Expression* lhs,
|
Expression* lhs,
|
||||||
Expression* rhs)
|
Expression* rhs)
|
||||||
: Base(source), lhs_(lhs), rhs_(rhs) {}
|
: Base(source), lhs_(lhs), rhs_(rhs) {
|
||||||
|
TINT_ASSERT(lhs_);
|
||||||
|
TINT_ASSERT(rhs_);
|
||||||
|
}
|
||||||
|
|
||||||
AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
|
AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
|
||||||
|
|
||||||
|
@ -38,15 +41,6 @@ AssignmentStatement* AssignmentStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<AssignmentStatement>(src, l, r);
|
return ctx->dst->create<AssignmentStatement>(src, l, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssignmentStatement::IsValid() const {
|
|
||||||
if (lhs_ == nullptr || !lhs_->IsValid())
|
|
||||||
return false;
|
|
||||||
if (rhs_ == nullptr || !rhs_->IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssignmentStatement::to_str(const semantic::Info& sem,
|
void AssignmentStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -44,9 +44,6 @@ class AssignmentStatement : public Castable<AssignmentStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
AssignmentStatement* Clone(CloneContext* ctx) const override;
|
AssignmentStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -50,40 +51,22 @@ TEST_F(AssignmentStatementTest, IsAssign) {
|
||||||
EXPECT_TRUE(stmt->Is<AssignmentStatement>());
|
EXPECT_TRUE(stmt->Is<AssignmentStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssignmentStatementTest, IsValid) {
|
TEST_F(AssignmentStatementTest, Assert_NullLHS) {
|
||||||
auto* lhs = Expr("lhs");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* rhs = Expr("rhs");
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
b.create<AssignmentStatement>(nullptr, b.Expr(1));
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssignmentStatementTest, IsValid_MissingLHS) {
|
TEST_F(AssignmentStatementTest, Assert_NullRHS) {
|
||||||
auto* rhs = Expr("rhs");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* stmt = create<AssignmentStatement>(nullptr, rhs);
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
b.create<AssignmentStatement>(b.Expr(1), nullptr);
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(AssignmentStatementTest, IsValid_MissingRHS) {
|
|
||||||
auto* lhs = Expr("lhs");
|
|
||||||
|
|
||||||
auto* stmt = create<AssignmentStatement>(lhs, nullptr);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AssignmentStatementTest, IsValid_InvalidLHS) {
|
|
||||||
auto* lhs = Expr("");
|
|
||||||
auto* rhs = Expr("rhs");
|
|
||||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AssignmentStatementTest, IsValid_InvalidRHS) {
|
|
||||||
auto* lhs = Expr("lhs");
|
|
||||||
auto* rhs = Expr("");
|
|
||||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AssignmentStatementTest, ToStr) {
|
TEST_F(AssignmentStatementTest, ToStr) {
|
||||||
|
|
|
@ -25,7 +25,11 @@ BinaryExpression::BinaryExpression(const Source& source,
|
||||||
BinaryOp op,
|
BinaryOp op,
|
||||||
Expression* lhs,
|
Expression* lhs,
|
||||||
Expression* rhs)
|
Expression* rhs)
|
||||||
: Base(source), op_(op), lhs_(lhs), rhs_(rhs) {}
|
: Base(source), op_(op), lhs_(lhs), rhs_(rhs) {
|
||||||
|
TINT_ASSERT(lhs_);
|
||||||
|
TINT_ASSERT(rhs_);
|
||||||
|
TINT_ASSERT(op_ != BinaryOp::kNone);
|
||||||
|
}
|
||||||
|
|
||||||
BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
|
BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
|
||||||
|
|
||||||
|
@ -39,16 +43,6 @@ BinaryExpression* BinaryExpression::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<BinaryExpression>(src, op_, l, r);
|
return ctx->dst->create<BinaryExpression>(src, op_, l, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BinaryExpression::IsValid() const {
|
|
||||||
if (lhs_ == nullptr || !lhs_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (rhs_ == nullptr || !rhs_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return op_ != BinaryOp::kNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinaryExpression::to_str(const semantic::Info& sem,
|
void BinaryExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -110,9 +110,6 @@ class BinaryExpression : public Castable<BinaryExpression, Expression> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
BinaryExpression* Clone(CloneContext* ctx) const override;
|
BinaryExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -49,50 +50,22 @@ TEST_F(BinaryExpressionTest, IsBinary) {
|
||||||
EXPECT_TRUE(r->Is<BinaryExpression>());
|
EXPECT_TRUE(r->Is<BinaryExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BinaryExpressionTest, IsValid) {
|
|
||||||
auto* lhs = Expr("lhs");
|
|
||||||
auto* rhs = Expr("rhs");
|
|
||||||
|
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
|
||||||
EXPECT_TRUE(r->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BinaryExpressionTest, IsValid_Null_LHS) {
|
TEST_F(BinaryExpressionTest, IsValid_Null_LHS) {
|
||||||
auto* rhs = Expr("rhs");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, nullptr, rhs);
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(r->IsValid());
|
b.create<BinaryExpression>(BinaryOp::kEqual, nullptr, b.Expr("rhs"));
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(BinaryExpressionTest, IsValid_Invalid_LHS) {
|
|
||||||
auto* lhs = Expr("");
|
|
||||||
auto* rhs = Expr("rhs");
|
|
||||||
|
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
|
||||||
EXPECT_FALSE(r->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BinaryExpressionTest, IsValid_Null_RHS) {
|
TEST_F(BinaryExpressionTest, IsValid_Null_RHS) {
|
||||||
auto* lhs = Expr("lhs");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, nullptr);
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(r->IsValid());
|
b.create<BinaryExpression>(BinaryOp::kEqual, b.Expr("lhs"), nullptr);
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(BinaryExpressionTest, IsValid_Invalid_RHS) {
|
|
||||||
auto* lhs = Expr("lhs");
|
|
||||||
auto* rhs = Expr("");
|
|
||||||
|
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
|
||||||
EXPECT_FALSE(r->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BinaryExpressionTest, IsValid_Binary_None) {
|
|
||||||
auto* lhs = Expr("lhs");
|
|
||||||
auto* rhs = Expr("rhs");
|
|
||||||
|
|
||||||
auto* r = create<BinaryExpression>(BinaryOp::kNone, lhs, rhs);
|
|
||||||
EXPECT_FALSE(r->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BinaryExpressionTest, ToStr) {
|
TEST_F(BinaryExpressionTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
||||||
BitcastExpression::BitcastExpression(const Source& source,
|
BitcastExpression::BitcastExpression(const Source& source,
|
||||||
type::Type* type,
|
type::Type* type,
|
||||||
Expression* expr)
|
Expression* expr)
|
||||||
: Base(source), type_(type), expr_(expr) {}
|
: Base(source), type_(type), expr_(expr) {
|
||||||
|
TINT_ASSERT(type_);
|
||||||
|
TINT_ASSERT(expr_);
|
||||||
|
}
|
||||||
|
|
||||||
BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
|
BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
|
||||||
BitcastExpression::~BitcastExpression() = default;
|
BitcastExpression::~BitcastExpression() = default;
|
||||||
|
@ -37,12 +40,6 @@ BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<BitcastExpression>(src, ty, e);
|
return ctx->dst->create<BitcastExpression>(src, ty, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BitcastExpression::IsValid() const {
|
|
||||||
if (expr_ == nullptr || !expr_->IsValid())
|
|
||||||
return false;
|
|
||||||
return type_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BitcastExpression::to_str(const semantic::Info& sem,
|
void BitcastExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -43,9 +43,6 @@ class BitcastExpression : public Castable<BitcastExpression, Expression> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
BitcastExpression* Clone(CloneContext* ctx) const override;
|
BitcastExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/bitcast_expression.h"
|
#include "src/ast/bitcast_expression.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -47,29 +48,22 @@ TEST_F(BitcastExpressionTest, IsBitcast) {
|
||||||
EXPECT_TRUE(exp->Is<BitcastExpression>());
|
EXPECT_TRUE(exp->Is<BitcastExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BitcastExpressionTest, IsValid) {
|
TEST_F(BitcastExpressionTest, Assert_NullType) {
|
||||||
auto* expr = Expr("expr");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* exp = create<BitcastExpression>(ty.f32(), expr);
|
ProgramBuilder b;
|
||||||
EXPECT_TRUE(exp->IsValid());
|
b.create<BitcastExpression>(nullptr, b.Expr("idx"));
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BitcastExpressionTest, IsValid_MissingType) {
|
TEST_F(BitcastExpressionTest, Assert_NullExpr) {
|
||||||
auto* expr = Expr("expr");
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* exp = create<BitcastExpression>(nullptr, expr);
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(exp->IsValid());
|
b.create<BitcastExpression>(b.ty.f32(), nullptr);
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(BitcastExpressionTest, IsValid_MissingExpr) {
|
|
||||||
auto* exp = create<BitcastExpression>(ty.f32(), nullptr);
|
|
||||||
EXPECT_FALSE(exp->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BitcastExpressionTest, IsValid_InvalidExpr) {
|
|
||||||
auto* expr = Expr("");
|
|
||||||
auto* e = create<BitcastExpression>(ty.f32(), expr);
|
|
||||||
EXPECT_FALSE(e->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BitcastExpressionTest, ToStr) {
|
TEST_F(BitcastExpressionTest, ToStr) {
|
||||||
|
|
|
@ -23,7 +23,11 @@ namespace ast {
|
||||||
|
|
||||||
BlockStatement::BlockStatement(const Source& source,
|
BlockStatement::BlockStatement(const Source& source,
|
||||||
const StatementList& statements)
|
const StatementList& statements)
|
||||||
: Base(source), statements_(std::move(statements)) {}
|
: Base(source), statements_(std::move(statements)) {
|
||||||
|
for (auto* stmt : *this) {
|
||||||
|
TINT_ASSERT(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BlockStatement::BlockStatement(BlockStatement&&) = default;
|
BlockStatement::BlockStatement(BlockStatement&&) = default;
|
||||||
|
|
||||||
|
@ -36,15 +40,6 @@ BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<BlockStatement>(src, stmts);
|
return ctx->dst->create<BlockStatement>(src, stmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockStatement::IsValid() const {
|
|
||||||
for (auto* stmt : *this) {
|
|
||||||
if (stmt == nullptr || !stmt->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlockStatement::to_str(const semantic::Info& sem,
|
void BlockStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -71,9 +71,6 @@ class BlockStatement : public Castable<BlockStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
BlockStatement* Clone(CloneContext* ctx) const override;
|
BlockStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
@ -45,35 +46,13 @@ TEST_F(BlockStatementTest, IsBlock) {
|
||||||
EXPECT_TRUE(b->Is<BlockStatement>());
|
EXPECT_TRUE(b->Is<BlockStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStatementTest, IsValid) {
|
TEST_F(BlockStatementTest, Assert_NullStatement) {
|
||||||
auto* b = create<BlockStatement>(ast::StatementList{
|
EXPECT_FATAL_FAILURE(
|
||||||
create<DiscardStatement>(),
|
{
|
||||||
});
|
ProgramBuilder b;
|
||||||
EXPECT_TRUE(b->IsValid());
|
b.create<BlockStatement>(ast::StatementList{nullptr});
|
||||||
}
|
},
|
||||||
|
"internal compiler error");
|
||||||
TEST_F(BlockStatementTest, IsValid_Empty) {
|
|
||||||
auto* b = create<BlockStatement>(ast::StatementList{});
|
|
||||||
EXPECT_TRUE(b->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BlockStatementTest, IsValid_NullBodyStatement) {
|
|
||||||
auto* b = create<BlockStatement>(ast::StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_FALSE(b->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BlockStatementTest, IsValid_InvalidBodyStatement) {
|
|
||||||
auto* b = create<BlockStatement>(
|
|
||||||
|
|
||||||
ast::StatementList{
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ElseStatementList{}),
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(b->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockStatementTest, ToStr) {
|
TEST_F(BlockStatementTest, ToStr) {
|
||||||
|
|
|
@ -33,10 +33,6 @@ BreakStatement* BreakStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<BreakStatement>(src);
|
return ctx->dst->create<BreakStatement>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BreakStatement::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BreakStatement::to_str(const semantic::Info&,
|
void BreakStatement::to_str(const semantic::Info&,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -36,9 +36,6 @@ class BreakStatement : public Castable<BreakStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
BreakStatement* Clone(CloneContext* ctx) const override;
|
BreakStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -34,11 +34,6 @@ TEST_F(BreakStatementTest, IsBreak) {
|
||||||
EXPECT_TRUE(stmt->Is<BreakStatement>());
|
EXPECT_TRUE(stmt->Is<BreakStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BreakStatementTest, IsValid) {
|
|
||||||
auto* stmt = create<BreakStatement>();
|
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BreakStatementTest, ToStr) {
|
TEST_F(BreakStatementTest, ToStr) {
|
||||||
auto* stmt = create<BreakStatement>();
|
auto* stmt = create<BreakStatement>();
|
||||||
EXPECT_EQ(str(stmt), R"(Break{}
|
EXPECT_EQ(str(stmt), R"(Break{}
|
||||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
||||||
CallExpression::CallExpression(const Source& source,
|
CallExpression::CallExpression(const Source& source,
|
||||||
Expression* func,
|
Expression* func,
|
||||||
ExpressionList params)
|
ExpressionList params)
|
||||||
: Base(source), func_(func), params_(params) {}
|
: Base(source), func_(func), params_(params) {
|
||||||
|
TINT_ASSERT(func_);
|
||||||
|
for (auto* param : params_) {
|
||||||
|
TINT_ASSERT(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CallExpression::CallExpression(CallExpression&&) = default;
|
CallExpression::CallExpression(CallExpression&&) = default;
|
||||||
|
|
||||||
|
@ -38,18 +43,6 @@ CallExpression* CallExpression::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<CallExpression>(src, fn, p);
|
return ctx->dst->create<CallExpression>(src, fn, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CallExpression::IsValid() const {
|
|
||||||
if (func_ == nullptr || !func_->IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// All params must be valid
|
|
||||||
for (auto* param : params_) {
|
|
||||||
if (param == nullptr || !param->IsValid())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallExpression::to_str(const semantic::Info& sem,
|
void CallExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -43,9 +43,6 @@ class CallExpression : public Castable<CallExpression, Expression> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
CallExpression* Clone(CloneContext* ctx) const override;
|
CallExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -50,44 +51,26 @@ TEST_F(CallExpressionTest, IsCall) {
|
||||||
EXPECT_TRUE(stmt->Is<CallExpression>());
|
EXPECT_TRUE(stmt->Is<CallExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, IsValid) {
|
TEST_F(CallExpressionTest, Assert_NullFunction) {
|
||||||
auto* func = Expr("func");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* stmt = create<CallExpression>(func, ExpressionList{});
|
{
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
ProgramBuilder b;
|
||||||
|
b.create<CallExpression>(nullptr, ExpressionList{});
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, IsValid_MissingFunction) {
|
TEST_F(CallExpressionTest, Assert_NullParam) {
|
||||||
auto* stmt = create<CallExpression>(nullptr, ExpressionList{});
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, IsValid_NullParam) {
|
|
||||||
auto* func = Expr("func");
|
|
||||||
ExpressionList params;
|
ExpressionList params;
|
||||||
params.push_back(Expr("param1"));
|
params.push_back(b.Expr("param1"));
|
||||||
params.push_back(nullptr);
|
params.push_back(nullptr);
|
||||||
params.push_back(Expr("param2"));
|
params.push_back(b.Expr("param2"));
|
||||||
|
b.create<CallExpression>(b.Expr("func"), params);
|
||||||
auto* stmt = create<CallExpression>(func, params);
|
},
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
"internal compiler error");
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, IsValid_InvalidFunction) {
|
|
||||||
auto* func = Expr("");
|
|
||||||
ExpressionList params;
|
|
||||||
params.push_back(Expr("param1"));
|
|
||||||
|
|
||||||
auto* stmt = create<CallExpression>(func, params);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, IsValid_InvalidParam) {
|
|
||||||
auto* func = Expr("func");
|
|
||||||
ExpressionList params;
|
|
||||||
params.push_back(Expr(""));
|
|
||||||
|
|
||||||
auto* stmt = create<CallExpression>(func, params);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallExpressionTest, ToStr_NoParams) {
|
TEST_F(CallExpressionTest, ToStr_NoParams) {
|
||||||
|
|
|
@ -22,7 +22,9 @@ namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
CallStatement::CallStatement(const Source& source, CallExpression* call)
|
CallStatement::CallStatement(const Source& source, CallExpression* call)
|
||||||
: Base(source), call_(call) {}
|
: Base(source), call_(call) {
|
||||||
|
TINT_ASSERT(call_);
|
||||||
|
}
|
||||||
|
|
||||||
CallStatement::CallStatement(CallStatement&&) = default;
|
CallStatement::CallStatement(CallStatement&&) = default;
|
||||||
|
|
||||||
|
@ -35,10 +37,6 @@ CallStatement* CallStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<CallStatement>(src, call);
|
return ctx->dst->create<CallStatement>(src, call);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CallStatement::IsValid() const {
|
|
||||||
return call_ != nullptr && call_->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallStatement::to_str(const semantic::Info& sem,
|
void CallStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -41,9 +41,6 @@ class CallStatement : public Castable<CallStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
CallStatement* Clone(CloneContext* ctx) const override;
|
CallStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/call_statement.h"
|
#include "src/ast/call_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -30,25 +31,17 @@ TEST_F(CallStatementTest, Creation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallStatementTest, IsCall) {
|
TEST_F(CallStatementTest, IsCall) {
|
||||||
auto* c = create<CallStatement>(nullptr);
|
auto* c = create<CallStatement>(Call("f"));
|
||||||
EXPECT_TRUE(c->Is<CallStatement>());
|
EXPECT_TRUE(c->Is<CallStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallStatementTest, IsValid) {
|
TEST_F(CallStatementTest, Assert_NullCall) {
|
||||||
auto* c = create<CallStatement>(
|
EXPECT_FATAL_FAILURE(
|
||||||
create<CallExpression>(Expr("func"), ExpressionList{}));
|
{
|
||||||
EXPECT_TRUE(c->IsValid());
|
ProgramBuilder b;
|
||||||
}
|
b.create<CallStatement>(nullptr);
|
||||||
|
},
|
||||||
TEST_F(CallStatementTest, IsValid_MissingExpr) {
|
"internal compiler error");
|
||||||
auto* c = create<CallStatement>(nullptr);
|
|
||||||
EXPECT_FALSE(c->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(CallStatementTest, IsValid_InvalidExpr) {
|
|
||||||
auto* c = create<CallStatement>(
|
|
||||||
create<CallExpression>(nullptr, ast::ExpressionList{}));
|
|
||||||
EXPECT_FALSE(c->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CallStatementTest, ToStr) {
|
TEST_F(CallStatementTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
||||||
CaseStatement::CaseStatement(const Source& source,
|
CaseStatement::CaseStatement(const Source& source,
|
||||||
CaseSelectorList selectors,
|
CaseSelectorList selectors,
|
||||||
BlockStatement* body)
|
BlockStatement* body)
|
||||||
: Base(source), selectors_(selectors), body_(body) {}
|
: Base(source), selectors_(selectors), body_(body) {
|
||||||
|
TINT_ASSERT(body_);
|
||||||
|
}
|
||||||
|
|
||||||
CaseStatement::CaseStatement(CaseStatement&&) = default;
|
CaseStatement::CaseStatement(CaseStatement&&) = default;
|
||||||
|
|
||||||
|
@ -38,10 +40,6 @@ CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<CaseStatement>(src, sel, b);
|
return ctx->dst->create<CaseStatement>(src, sel, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CaseStatement::IsValid() const {
|
|
||||||
return body_ != nullptr && body_->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CaseStatement::to_str(const semantic::Info& sem,
|
void CaseStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -56,9 +56,6 @@ class CaseStatement : public Castable<CaseStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
CaseStatement* Clone(CloneContext* ctx) const override;
|
CaseStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/case_statement.h"
|
#include "src/ast/case_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
@ -89,36 +90,13 @@ TEST_F(CaseStatementTest, IsCase) {
|
||||||
EXPECT_TRUE(c->Is<CaseStatement>());
|
EXPECT_TRUE(c->Is<CaseStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CaseStatementTest, IsValid) {
|
TEST_F(CaseStatementTest, Assert_NullBody) {
|
||||||
auto* c = create<CaseStatement>(CaseSelectorList{},
|
EXPECT_FATAL_FAILURE(
|
||||||
create<BlockStatement>(StatementList{}));
|
{
|
||||||
EXPECT_TRUE(c->IsValid());
|
ProgramBuilder b;
|
||||||
}
|
b.create<CaseStatement>(CaseSelectorList{}, nullptr);
|
||||||
|
},
|
||||||
TEST_F(CaseStatementTest, IsValid_NullBodyStatement) {
|
"internal compiler error");
|
||||||
CaseSelectorList b;
|
|
||||||
b.push_back(create<SintLiteral>(ty.i32(), 2));
|
|
||||||
|
|
||||||
auto* body = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
auto* c = create<CaseStatement>(b, body);
|
|
||||||
EXPECT_FALSE(c->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(CaseStatementTest, IsValid_InvalidBodyStatement) {
|
|
||||||
CaseSelectorList b;
|
|
||||||
b.push_back(create<SintLiteral>(ty.i32(), 2));
|
|
||||||
|
|
||||||
auto* body = create<BlockStatement>(
|
|
||||||
|
|
||||||
StatementList{
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ElseStatementList{}),
|
|
||||||
});
|
|
||||||
auto* c = create<CaseStatement>(CaseSelectorList{b}, body);
|
|
||||||
EXPECT_FALSE(c->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CaseStatementTest, ToStr_WithSelectors_i32) {
|
TEST_F(CaseStatementTest, ToStr_WithSelectors_i32) {
|
||||||
|
|
|
@ -33,10 +33,6 @@ ContinueStatement* ContinueStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<ContinueStatement>(src);
|
return ctx->dst->create<ContinueStatement>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContinueStatement::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContinueStatement::to_str(const semantic::Info&,
|
void ContinueStatement::to_str(const semantic::Info&,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -36,9 +36,6 @@ class ContinueStatement : public Castable<ContinueStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
ContinueStatement* Clone(CloneContext* ctx) const override;
|
ContinueStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -34,11 +34,6 @@ TEST_F(ContinueStatementTest, IsContinue) {
|
||||||
EXPECT_TRUE(stmt->Is<ContinueStatement>());
|
EXPECT_TRUE(stmt->Is<ContinueStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ContinueStatementTest, IsValid) {
|
|
||||||
auto* stmt = create<ContinueStatement>();
|
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ContinueStatementTest, ToStr) {
|
TEST_F(ContinueStatementTest, ToStr) {
|
||||||
auto* stmt = create<ContinueStatement>();
|
auto* stmt = create<ContinueStatement>();
|
||||||
EXPECT_EQ(str(stmt), R"(Continue{}
|
EXPECT_EQ(str(stmt), R"(Continue{}
|
||||||
|
|
|
@ -39,9 +39,5 @@ std::ostream& operator<<(std::ostream& out, DecorationKind data) {
|
||||||
return out << "<unknown>";
|
return out << "<unknown>";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Decoration::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -42,9 +42,6 @@ class Decoration : public Castable<Decoration, Node> {
|
||||||
/// @return the decoration kind
|
/// @return the decoration kind
|
||||||
virtual DecorationKind GetKind() const = 0;
|
virtual DecorationKind GetKind() const = 0;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param source the source of this decoration
|
/// @param source the source of this decoration
|
||||||
|
|
|
@ -33,10 +33,6 @@ DiscardStatement* DiscardStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<DiscardStatement>(src);
|
return ctx->dst->create<DiscardStatement>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscardStatement::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DiscardStatement::to_str(const semantic::Info&,
|
void DiscardStatement::to_str(const semantic::Info&,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -36,9 +36,6 @@ class DiscardStatement : public Castable<DiscardStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
DiscardStatement* Clone(CloneContext* ctx) const override;
|
DiscardStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -44,11 +44,6 @@ TEST_F(DiscardStatementTest, IsDiscard) {
|
||||||
EXPECT_TRUE(stmt->Is<DiscardStatement>());
|
EXPECT_TRUE(stmt->Is<DiscardStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DiscardStatementTest, IsValid) {
|
|
||||||
auto* stmt = create<DiscardStatement>();
|
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(DiscardStatementTest, ToStr) {
|
TEST_F(DiscardStatementTest, ToStr) {
|
||||||
auto* stmt = create<DiscardStatement>();
|
auto* stmt = create<DiscardStatement>();
|
||||||
EXPECT_EQ(str(stmt), R"(Discard{}
|
EXPECT_EQ(str(stmt), R"(Discard{}
|
||||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
||||||
ElseStatement::ElseStatement(const Source& source,
|
ElseStatement::ElseStatement(const Source& source,
|
||||||
Expression* condition,
|
Expression* condition,
|
||||||
BlockStatement* body)
|
BlockStatement* body)
|
||||||
: Base(source), condition_(condition), body_(body) {}
|
: Base(source), condition_(condition), body_(body) {
|
||||||
|
TINT_ASSERT(body_);
|
||||||
|
}
|
||||||
|
|
||||||
ElseStatement::ElseStatement(ElseStatement&&) = default;
|
ElseStatement::ElseStatement(ElseStatement&&) = default;
|
||||||
|
|
||||||
|
@ -38,13 +40,6 @@ ElseStatement* ElseStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<ElseStatement>(src, cond, b);
|
return ctx->dst->create<ElseStatement>(src, cond, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElseStatement::IsValid() const {
|
|
||||||
if (body_ == nullptr || !body_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return condition_ == nullptr || condition_->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ElseStatement::to_str(const semantic::Info& sem,
|
void ElseStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -53,9 +53,6 @@ class ElseStatement : public Castable<ElseStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
ElseStatement* Clone(CloneContext* ctx) const override;
|
ElseStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
@ -36,7 +37,7 @@ TEST_F(ElseStatementTest, Creation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, Creation_WithSource) {
|
TEST_F(ElseStatementTest, Creation_WithSource) {
|
||||||
auto* e = create<ElseStatement>(Source{Source::Location{20, 2}}, nullptr,
|
auto* e = create<ElseStatement>(Source{Source::Location{20, 2}}, Expr(true),
|
||||||
create<BlockStatement>(StatementList{}));
|
create<BlockStatement>(StatementList{}));
|
||||||
auto src = e->source();
|
auto src = e->source();
|
||||||
EXPECT_EQ(src.range.begin.line, 20u);
|
EXPECT_EQ(src.range.begin.line, 20u);
|
||||||
|
@ -62,45 +63,13 @@ TEST_F(ElseStatementTest, HasContition_NullCondition) {
|
||||||
EXPECT_FALSE(e->HasCondition());
|
EXPECT_FALSE(e->HasCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, IsValid) {
|
TEST_F(ElseStatementTest, Assert_NullBody) {
|
||||||
auto* e =
|
EXPECT_FATAL_FAILURE(
|
||||||
create<ElseStatement>(nullptr, create<BlockStatement>(StatementList{}));
|
{
|
||||||
EXPECT_TRUE(e->IsValid());
|
ProgramBuilder b;
|
||||||
}
|
b.create<ElseStatement>(b.Expr(true), nullptr);
|
||||||
|
},
|
||||||
TEST_F(ElseStatementTest, IsValid_WithBody) {
|
"internal compiler error");
|
||||||
auto* body = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
});
|
|
||||||
auto* e = create<ElseStatement>(nullptr, body);
|
|
||||||
EXPECT_TRUE(e->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, IsValid_WithNullBodyStatement) {
|
|
||||||
auto* body = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
auto* e = create<ElseStatement>(nullptr, body);
|
|
||||||
EXPECT_FALSE(e->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, IsValid_InvalidCondition) {
|
|
||||||
auto* cond = create<ScalarConstructorExpression>(nullptr);
|
|
||||||
auto* e =
|
|
||||||
create<ElseStatement>(cond, create<BlockStatement>(StatementList{}));
|
|
||||||
EXPECT_FALSE(e->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, IsValid_InvalidBodyStatement) {
|
|
||||||
auto* body = create<BlockStatement>(
|
|
||||||
|
|
||||||
StatementList{
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ElseStatementList{}),
|
|
||||||
});
|
|
||||||
auto* e = create<ElseStatement>(nullptr, body);
|
|
||||||
EXPECT_FALSE(e->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ElseStatementTest, ToStr) {
|
TEST_F(ElseStatementTest, ToStr) {
|
||||||
|
|
|
@ -34,10 +34,6 @@ FallthroughStatement* FallthroughStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<FallthroughStatement>(src);
|
return ctx->dst->create<FallthroughStatement>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FallthroughStatement::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FallthroughStatement::to_str(const semantic::Info&,
|
void FallthroughStatement::to_str(const semantic::Info&,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -36,9 +36,6 @@ class FallthroughStatement : public Castable<FallthroughStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
FallthroughStatement* Clone(CloneContext* ctx) const override;
|
FallthroughStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -42,11 +42,6 @@ TEST_F(FallthroughStatementTest, IsFallthrough) {
|
||||||
EXPECT_TRUE(stmt->Is<FallthroughStatement>());
|
EXPECT_TRUE(stmt->Is<FallthroughStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FallthroughStatementTest, IsValid) {
|
|
||||||
auto* stmt = create<FallthroughStatement>();
|
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FallthroughStatementTest, ToStr) {
|
TEST_F(FallthroughStatementTest, ToStr) {
|
||||||
auto* stmt = create<FallthroughStatement>();
|
auto* stmt = create<FallthroughStatement>();
|
||||||
EXPECT_EQ(str(stmt), R"(Fallthrough{}
|
EXPECT_EQ(str(stmt), R"(Fallthrough{}
|
||||||
|
|
|
@ -34,7 +34,14 @@ Function::Function(const Source& source,
|
||||||
params_(std::move(params)),
|
params_(std::move(params)),
|
||||||
return_type_(return_type),
|
return_type_(return_type),
|
||||||
body_(body),
|
body_(body),
|
||||||
decorations_(std::move(decorations)) {}
|
decorations_(std::move(decorations)) {
|
||||||
|
for (auto* param : params_) {
|
||||||
|
TINT_ASSERT(param);
|
||||||
|
}
|
||||||
|
TINT_ASSERT(body_);
|
||||||
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
|
TINT_ASSERT(return_type_);
|
||||||
|
}
|
||||||
|
|
||||||
Function::Function(Function&&) = default;
|
Function::Function(Function&&) = default;
|
||||||
|
|
||||||
|
@ -73,23 +80,6 @@ Function* Function::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<Function>(src, sym, p, ret, b, decos);
|
return ctx->dst->create<Function>(src, sym, p, ret, b, decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Function::IsValid() const {
|
|
||||||
for (auto* param : params_) {
|
|
||||||
if (param == nullptr || !param->IsValid())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (body_ == nullptr || !body_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!symbol_.IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (return_type_ == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Function::to_str(const semantic::Info& sem,
|
void Function::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -89,9 +89,6 @@ class Function : public Castable<Function, Node> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
Function* Clone(CloneContext* ctx) const override;
|
Function* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the symbol and type are both present
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/stage_decoration.h"
|
#include "src/ast/stage_decoration.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
@ -47,80 +48,38 @@ TEST_F(FunctionTest, Creation_WithSource) {
|
||||||
EXPECT_EQ(src.range.begin.column, 2u);
|
EXPECT_EQ(src.range.begin.column, 2u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid) {
|
TEST_F(FunctionTest, Assert_InvalidName) {
|
||||||
VariableList params;
|
EXPECT_FATAL_FAILURE(
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* f = Func("func", params, ty.void_(),
|
b.Func("", VariableList{}, b.ty.void_(), StatementList{},
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
},
|
|
||||||
FunctionDecorationList{});
|
FunctionDecorationList{});
|
||||||
EXPECT_TRUE(f->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_InvalidName) {
|
TEST_F(FunctionTest, Assert_NullReturnType) {
|
||||||
VariableList params;
|
EXPECT_FATAL_FAILURE(
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* f =
|
b.Func("f", VariableList{}, nullptr, StatementList{},
|
||||||
Func("", params, ty.void_(), StatementList{}, FunctionDecorationList{});
|
FunctionDecorationList{});
|
||||||
EXPECT_FALSE(f->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_MissingReturnType) {
|
TEST_F(FunctionTest, Assert_NullParam) {
|
||||||
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
VariableList params;
|
VariableList params;
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
params.push_back(b.Var("var", b.ty.i32(), StorageClass::kNone));
|
||||||
|
|
||||||
auto* f =
|
|
||||||
Func("func", params, nullptr, StatementList{}, FunctionDecorationList{});
|
|
||||||
EXPECT_FALSE(f->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_NullParam) {
|
|
||||||
VariableList params;
|
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
|
||||||
params.push_back(nullptr);
|
params.push_back(nullptr);
|
||||||
|
|
||||||
auto* f = Func("func", params, ty.void_(), StatementList{},
|
b.Func("f", params, b.ty.void_(), StatementList{},
|
||||||
FunctionDecorationList{});
|
FunctionDecorationList{});
|
||||||
EXPECT_FALSE(f->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_InvalidParam) {
|
|
||||||
VariableList params;
|
|
||||||
params.push_back(Var("var", nullptr, StorageClass::kNone));
|
|
||||||
|
|
||||||
auto* f = Func("func", params, ty.void_(), StatementList{},
|
|
||||||
FunctionDecorationList{});
|
|
||||||
EXPECT_FALSE(f->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_NullBodyStatement) {
|
|
||||||
VariableList params;
|
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
|
||||||
|
|
||||||
auto* f = Func("func", params, ty.void_(),
|
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
},
|
},
|
||||||
FunctionDecorationList{});
|
"internal compiler error");
|
||||||
|
|
||||||
EXPECT_FALSE(f->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FunctionTest, IsValid_InvalidBodyStatement) {
|
|
||||||
VariableList params;
|
|
||||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
|
||||||
|
|
||||||
auto* f = Func("func", params, ty.void_(),
|
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
},
|
|
||||||
FunctionDecorationList{});
|
|
||||||
EXPECT_FALSE(f->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionTest, ToStr) {
|
TEST_F(FunctionTest, ToStr) {
|
||||||
|
|
|
@ -22,7 +22,9 @@ namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(const Source& source, Symbol sym)
|
IdentifierExpression::IdentifierExpression(const Source& source, Symbol sym)
|
||||||
: Base(source), sym_(sym) {}
|
: Base(source), sym_(sym) {
|
||||||
|
TINT_ASSERT(sym_.IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
||||||
|
|
||||||
|
@ -35,10 +37,6 @@ IdentifierExpression* IdentifierExpression::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<IdentifierExpression>(src, sym);
|
return ctx->dst->create<IdentifierExpression>(src, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdentifierExpression::IsValid() const {
|
|
||||||
return sym_.IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentifierExpression::to_str(const semantic::Info& sem,
|
void IdentifierExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -41,9 +41,6 @@ class IdentifierExpression : public Castable<IdentifierExpression, Expression> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
IdentifierExpression* Clone(CloneContext* ctx) const override;
|
IdentifierExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -39,9 +40,13 @@ TEST_F(IdentifierExpressionTest, IsIdentifier) {
|
||||||
EXPECT_TRUE(i->Is<IdentifierExpression>());
|
EXPECT_TRUE(i->Is<IdentifierExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, IsValid) {
|
TEST_F(IdentifierExpressionTest, Assert_InvalidSymbol) {
|
||||||
auto* i = Expr("ident");
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(i->IsValid());
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
|
b.Expr("");
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, ToStr) {
|
TEST_F(IdentifierExpressionTest, ToStr) {
|
||||||
|
|
|
@ -28,7 +28,13 @@ IfStatement::IfStatement(const Source& source,
|
||||||
: Base(source),
|
: Base(source),
|
||||||
condition_(condition),
|
condition_(condition),
|
||||||
body_(body),
|
body_(body),
|
||||||
else_statements_(std::move(else_stmts)) {}
|
else_statements_(std::move(else_stmts)) {
|
||||||
|
TINT_ASSERT(condition_);
|
||||||
|
TINT_ASSERT(body);
|
||||||
|
for (auto* el : else_statements_) {
|
||||||
|
TINT_ASSERT(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IfStatement::IfStatement(IfStatement&&) = default;
|
IfStatement::IfStatement(IfStatement&&) = default;
|
||||||
|
|
||||||
|
@ -43,30 +49,6 @@ IfStatement* IfStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<IfStatement>(src, cond, b, el);
|
return ctx->dst->create<IfStatement>(src, cond, b, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IfStatement::IsValid() const {
|
|
||||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (body_ == nullptr || !body_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found_else = false;
|
|
||||||
for (auto* el : else_statements_) {
|
|
||||||
// Else statement must be last
|
|
||||||
if (found_else)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (el == nullptr || !el->IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (el->condition() == nullptr)
|
|
||||||
found_else = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IfStatement::to_str(const semantic::Info& sem,
|
void IfStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -57,9 +57,6 @@ class IfStatement : public Castable<IfStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
IfStatement* Clone(CloneContext* ctx) const override;
|
IfStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
|
@ -36,128 +37,37 @@ TEST_F(IfStatementTest, Creation) {
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsIf) {
|
TEST_F(IfStatementTest, IsIf) {
|
||||||
auto* stmt = create<IfStatement>(
|
auto* stmt = create<IfStatement>(
|
||||||
nullptr, create<BlockStatement>(StatementList{}), ElseStatementList{});
|
Expr(true), create<BlockStatement>(StatementList{}), ElseStatementList{});
|
||||||
EXPECT_TRUE(stmt->Is<IfStatement>());
|
EXPECT_TRUE(stmt->Is<IfStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid) {
|
TEST_F(IfStatementTest, Assert_NullCondition) {
|
||||||
auto* cond = Expr("cond");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* body =
|
{
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
ProgramBuilder b;
|
||||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
auto* body = b.create<BlockStatement>(StatementList{});
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
b.create<IfStatement>(nullptr, body, ElseStatementList{});
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_WithElseStatements) {
|
TEST_F(IfStatementTest, Assert_NullBody) {
|
||||||
auto* cond = Expr("cond");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* body =
|
{
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
ProgramBuilder b;
|
||||||
auto* stmt = create<IfStatement>(
|
b.create<IfStatement>(b.Expr(true), nullptr, ElseStatementList{});
|
||||||
cond, body,
|
},
|
||||||
ElseStatementList{
|
"internal compiler error");
|
||||||
create<ElseStatement>(Expr("Ident"),
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
create<ElseStatement>(nullptr,
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
});
|
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_MissingCondition) {
|
TEST_F(IfStatementTest, Assert_NullElseStatement) {
|
||||||
auto* body =
|
EXPECT_FATAL_FAILURE(
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
{
|
||||||
auto* stmt = create<IfStatement>(nullptr, body, ElseStatementList{});
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
auto* body = b.create<BlockStatement>(StatementList{});
|
||||||
}
|
b.create<IfStatement>(b.Expr(true), body, ElseStatementList{nullptr});
|
||||||
|
},
|
||||||
TEST_F(IfStatementTest, IsValid_InvalidCondition) {
|
"internal compiler error");
|
||||||
auto* cond = Expr("");
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_NullBodyStatement) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_InvalidBodyStatement) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body = create<BlockStatement>(
|
|
||||||
|
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ast::ElseStatementList{}),
|
|
||||||
});
|
|
||||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_NullElseStatement) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
auto* stmt = create<IfStatement>(
|
|
||||||
cond, body,
|
|
||||||
ElseStatementList{
|
|
||||||
create<ElseStatement>(Expr("Ident"),
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
create<ElseStatement>(nullptr,
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_InvalidElseStatement) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
auto* stmt = create<IfStatement>(
|
|
||||||
cond, body,
|
|
||||||
ElseStatementList{
|
|
||||||
create<ElseStatement>(Expr(""),
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_MultipleElseWiththoutCondition) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
auto* stmt = create<IfStatement>(
|
|
||||||
cond, body,
|
|
||||||
ElseStatementList{
|
|
||||||
create<ElseStatement>(nullptr,
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
create<ElseStatement>(nullptr,
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IfStatementTest, IsValid_ElseNotLast) {
|
|
||||||
auto* cond = Expr("cond");
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
auto* stmt = create<IfStatement>(
|
|
||||||
cond, body,
|
|
||||||
ElseStatementList{
|
|
||||||
create<ElseStatement>(nullptr,
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
create<ElseStatement>(Expr("Ident"),
|
|
||||||
create<BlockStatement>(StatementList{})),
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IfStatementTest, ToStr) {
|
TEST_F(IfStatementTest, ToStr) {
|
||||||
|
|
|
@ -24,10 +24,6 @@ Literal::Literal(const Source& source, type::Type* type)
|
||||||
|
|
||||||
Literal::~Literal() = default;
|
Literal::~Literal() = default;
|
||||||
|
|
||||||
bool Literal::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Literal::to_str(const semantic::Info& sem,
|
void Literal::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -30,9 +30,6 @@ class Literal : public Castable<Literal, Node> {
|
||||||
/// @returns the type of the literal
|
/// @returns the type of the literal
|
||||||
type::Type* type() const { return type_; }
|
type::Type* type() const { return type_; }
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
||||||
LoopStatement::LoopStatement(const Source& source,
|
LoopStatement::LoopStatement(const Source& source,
|
||||||
BlockStatement* body,
|
BlockStatement* body,
|
||||||
BlockStatement* continuing)
|
BlockStatement* continuing)
|
||||||
: Base(source), body_(body), continuing_(continuing) {}
|
: Base(source), body_(body), continuing_(continuing) {
|
||||||
|
TINT_ASSERT(body_);
|
||||||
|
}
|
||||||
|
|
||||||
LoopStatement::LoopStatement(LoopStatement&&) = default;
|
LoopStatement::LoopStatement(LoopStatement&&) = default;
|
||||||
|
|
||||||
|
@ -38,16 +40,6 @@ LoopStatement* LoopStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<LoopStatement>(src, b, cont);
|
return ctx->dst->create<LoopStatement>(src, b, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoopStatement::IsValid() const {
|
|
||||||
if (body_ == nullptr || !body_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (continuing_ == nullptr || !continuing_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoopStatement::to_str(const semantic::Info& sem,
|
void LoopStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -54,9 +54,6 @@ class LoopStatement : public Castable<LoopStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
LoopStatement* Clone(CloneContext* ctx) const override;
|
LoopStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/loop_statement.h"
|
#include "src/ast/loop_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/discard_statement.h"
|
#include "src/ast/discard_statement.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
@ -78,88 +79,13 @@ TEST_F(LoopStatementTest, HasContinuing_WithContinuing) {
|
||||||
EXPECT_TRUE(l->has_continuing());
|
EXPECT_TRUE(l->has_continuing());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid) {
|
TEST_F(LoopStatementTest, Assert_NullBody) {
|
||||||
auto* body =
|
EXPECT_FATAL_FAILURE(
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* continuing =
|
b.create<LoopStatement>(nullptr, nullptr);
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
},
|
||||||
|
"internal compiler error");
|
||||||
auto* l = create<LoopStatement>(body, continuing);
|
|
||||||
EXPECT_TRUE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_WithoutContinuing) {
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
|
|
||||||
auto* l =
|
|
||||||
create<LoopStatement>(body, create<BlockStatement>(StatementList{}));
|
|
||||||
EXPECT_TRUE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_WithoutBody) {
|
|
||||||
auto* l = create<LoopStatement>(create<BlockStatement>(StatementList{}),
|
|
||||||
create<BlockStatement>(StatementList{}));
|
|
||||||
EXPECT_TRUE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_NullBodyStatement) {
|
|
||||||
auto* body = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* continuing =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
|
|
||||||
auto* l = create<LoopStatement>(body, continuing);
|
|
||||||
EXPECT_FALSE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_InvalidBodyStatement) {
|
|
||||||
auto* body = create<BlockStatement>(
|
|
||||||
|
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ElseStatementList{}),
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* continuing =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
|
|
||||||
auto* l = create<LoopStatement>(body, continuing);
|
|
||||||
EXPECT_FALSE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_NullContinuingStatement) {
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
|
|
||||||
auto* continuing = create<BlockStatement>(StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* l = create<LoopStatement>(body, continuing);
|
|
||||||
EXPECT_FALSE(l->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, IsValid_InvalidContinuingStatement) {
|
|
||||||
auto* body =
|
|
||||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
|
||||||
|
|
||||||
auto* continuing = create<BlockStatement>(
|
|
||||||
|
|
||||||
StatementList{
|
|
||||||
create<DiscardStatement>(),
|
|
||||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
|
||||||
ElseStatementList{}),
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* l = create<LoopStatement>(body, continuing);
|
|
||||||
EXPECT_FALSE(l->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LoopStatementTest, ToStr) {
|
TEST_F(LoopStatementTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
||||||
MemberAccessorExpression::MemberAccessorExpression(const Source& source,
|
MemberAccessorExpression::MemberAccessorExpression(const Source& source,
|
||||||
Expression* structure,
|
Expression* structure,
|
||||||
IdentifierExpression* member)
|
IdentifierExpression* member)
|
||||||
: Base(source), struct_(structure), member_(member) {}
|
: Base(source), struct_(structure), member_(member) {
|
||||||
|
TINT_ASSERT(structure);
|
||||||
|
TINT_ASSERT(member);
|
||||||
|
}
|
||||||
|
|
||||||
MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
|
MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
|
||||||
default;
|
default;
|
||||||
|
@ -40,16 +43,6 @@ MemberAccessorExpression* MemberAccessorExpression::Clone(
|
||||||
return ctx->dst->create<MemberAccessorExpression>(src, str, mem);
|
return ctx->dst->create<MemberAccessorExpression>(src, str, mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemberAccessorExpression::IsValid() const {
|
|
||||||
if (struct_ == nullptr || !struct_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (member_ == nullptr || !member_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemberAccessorExpression::to_str(const semantic::Info& sem,
|
void MemberAccessorExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -46,9 +46,6 @@ class MemberAccessorExpression
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
MemberAccessorExpression* Clone(CloneContext* ctx) const override;
|
MemberAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -43,30 +44,22 @@ TEST_F(MemberAccessorExpressionTest, IsMemberAccessor) {
|
||||||
EXPECT_TRUE(stmt->Is<MemberAccessorExpression>());
|
EXPECT_TRUE(stmt->Is<MemberAccessorExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MemberAccessorExpressionTest, IsValid) {
|
TEST_F(MemberAccessorExpressionTest, Assert_NullStruct) {
|
||||||
auto* stmt =
|
EXPECT_FATAL_FAILURE(
|
||||||
create<MemberAccessorExpression>(Expr("structure"), Expr("member"));
|
{
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
ProgramBuilder b;
|
||||||
|
b.create<MemberAccessorExpression>(nullptr, b.Expr("member"));
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MemberAccessorExpressionTest, IsValid_NullStruct) {
|
TEST_F(MemberAccessorExpressionTest, Assert_NullMember) {
|
||||||
auto* stmt = create<MemberAccessorExpression>(nullptr, Expr("member"));
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
b.create<MemberAccessorExpression>(b.Expr("struct"), nullptr);
|
||||||
TEST_F(MemberAccessorExpressionTest, IsValid_InvalidStruct) {
|
},
|
||||||
auto* stmt = create<MemberAccessorExpression>(Expr(""), Expr("member"));
|
"internal compiler error");
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MemberAccessorExpressionTest, IsValid_NullMember) {
|
|
||||||
auto* stmt = create<MemberAccessorExpression>(Expr("structure"), nullptr);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MemberAccessorExpressionTest, IsValid_InvalidMember) {
|
|
||||||
auto* stmt = create<MemberAccessorExpression>(Expr("structure"), Expr(""));
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MemberAccessorExpressionTest, ToStr) {
|
TEST_F(MemberAccessorExpressionTest, ToStr) {
|
||||||
|
|
|
@ -47,46 +47,6 @@ Module::Module(const Source& source, std::vector<CastableBase*> global_decls)
|
||||||
|
|
||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
bool Module::IsValid() const {
|
|
||||||
for (auto* decl : global_declarations_) {
|
|
||||||
if (decl == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto* var : global_variables_) {
|
|
||||||
if (var == nullptr || !var->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto* const ty : constructed_types_) {
|
|
||||||
if (ty == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (auto* alias = ty->As<type::Alias>()) {
|
|
||||||
if (alias->type() == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (auto* str = alias->type()->As<type::Struct>()) {
|
|
||||||
if (!str->symbol().IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (auto* str = ty->As<type::Struct>()) {
|
|
||||||
if (!str->symbol().IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto* func : functions_) {
|
|
||||||
if (func == nullptr || !func->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module* Module::Clone(CloneContext* ctx) const {
|
Module* Module::Clone(CloneContext* ctx) const {
|
||||||
auto* out = ctx->dst->create<Module>();
|
auto* out = ctx->dst->create<Module>();
|
||||||
out->Copy(ctx, this);
|
out->Copy(ctx, this);
|
||||||
|
|
|
@ -48,6 +48,7 @@ class Module : public Castable<Module, Node> {
|
||||||
/// Add a global variable to the Builder
|
/// Add a global variable to the Builder
|
||||||
/// @param var the variable to add
|
/// @param var the variable to add
|
||||||
void AddGlobalVariable(ast::Variable* var) {
|
void AddGlobalVariable(ast::Variable* var) {
|
||||||
|
TINT_ASSERT(var);
|
||||||
global_variables_.push_back(var);
|
global_variables_.push_back(var);
|
||||||
global_declarations_.push_back(var);
|
global_declarations_.push_back(var);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +63,7 @@ class Module : public Castable<Module, Node> {
|
||||||
/// The type must be an alias or a struct.
|
/// The type must be an alias or a struct.
|
||||||
/// @param type the constructed type to add
|
/// @param type the constructed type to add
|
||||||
void AddConstructedType(type::Type* type) {
|
void AddConstructedType(type::Type* type) {
|
||||||
|
TINT_ASSERT(type);
|
||||||
constructed_types_.push_back(type);
|
constructed_types_.push_back(type);
|
||||||
global_declarations_.push_back(type);
|
global_declarations_.push_back(type);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,7 @@ class Module : public Castable<Module, Node> {
|
||||||
/// Add a function to the Builder
|
/// Add a function to the Builder
|
||||||
/// @param func the function to add
|
/// @param func the function to add
|
||||||
void AddFunction(ast::Function* func) {
|
void AddFunction(ast::Function* func) {
|
||||||
|
TINT_ASSERT(func);
|
||||||
functions_.push_back(func);
|
functions_.push_back(func);
|
||||||
global_declarations_.push_back(func);
|
global_declarations_.push_back(func);
|
||||||
}
|
}
|
||||||
|
@ -81,9 +84,6 @@ class Module : public Castable<Module, Node> {
|
||||||
/// @returns the functions declared in the translation unit
|
/// @returns the functions declared in the translation unit
|
||||||
const FunctionList& Functions() const { return functions_; }
|
const FunctionList& Functions() const { return functions_; }
|
||||||
|
|
||||||
/// @returns true if all required fields in the AST are present.
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -45,78 +46,40 @@ TEST_F(ModuleTest, LookupFunctionMissing) {
|
||||||
program.AST().Functions().Find(program.Symbols().Get("Missing")));
|
program.AST().Functions().Find(program.Symbols().Get("Missing")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Empty) {
|
TEST_F(ModuleTest, Assert_Null_GlobalVariable) {
|
||||||
Program program(std::move(*this));
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(program.AST().IsValid());
|
{
|
||||||
|
ProgramBuilder builder;
|
||||||
|
builder.AST().AddGlobalVariable(nullptr);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_GlobalVariable) {
|
TEST_F(ModuleTest, Assert_Invalid_GlobalVariable) {
|
||||||
Global("var", ty.f32(), StorageClass::kInput);
|
EXPECT_FATAL_FAILURE(
|
||||||
Program program(std::move(*this));
|
{
|
||||||
EXPECT_TRUE(program.AST().IsValid());
|
ProgramBuilder builder;
|
||||||
|
builder.Global("var", nullptr, StorageClass::kInput);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Null_GlobalVariable) {
|
TEST_F(ModuleTest, Assert_Null_ConstructedType) {
|
||||||
AST().AddGlobalVariable(nullptr);
|
EXPECT_FATAL_FAILURE(
|
||||||
Program program(std::move(*this));
|
{
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
ProgramBuilder builder;
|
||||||
|
builder.AST().AddConstructedType(nullptr);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Invalid_GlobalVariable) {
|
TEST_F(ModuleTest, Assert_Null_Function) {
|
||||||
Global("var", nullptr, StorageClass::kInput);
|
EXPECT_FATAL_FAILURE(
|
||||||
Program program(std::move(*this));
|
{
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
ProgramBuilder builder;
|
||||||
}
|
builder.AST().AddFunction(nullptr);
|
||||||
|
},
|
||||||
TEST_F(ModuleTest, IsValid_Alias) {
|
"internal compiler error");
|
||||||
auto* alias = ty.alias("alias", ty.f32());
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Null_Alias) {
|
|
||||||
AST().AddConstructedType(nullptr);
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Struct) {
|
|
||||||
auto* st = ty.struct_("name", {});
|
|
||||||
auto* alias = ty.alias("name", st);
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Struct_EmptyName) {
|
|
||||||
auto* st = ty.struct_("", {});
|
|
||||||
auto* alias = ty.alias("name", st);
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Function) {
|
|
||||||
Func("main", VariableList(), ty.f32(), StatementList{},
|
|
||||||
ast::FunctionDecorationList{});
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Null_Function) {
|
|
||||||
AST().AddFunction(nullptr);
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Invalid_Function) {
|
|
||||||
Func("main", VariableList{}, nullptr, StatementList{},
|
|
||||||
ast::FunctionDecorationList{});
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.AST().IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -40,9 +40,6 @@ class Node : public Castable<Node, Cloneable> {
|
||||||
/// @returns the node source data
|
/// @returns the node source data
|
||||||
const Source& source() const { return source_; }
|
const Source& source() const { return source_; }
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
virtual bool IsValid() const = 0;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -38,13 +38,6 @@ ReturnStatement* ReturnStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<ReturnStatement>(src, ret);
|
return ctx->dst->create<ReturnStatement>(src, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReturnStatement::IsValid() const {
|
|
||||||
if (value_ != nullptr) {
|
|
||||||
return value_->IsValid();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReturnStatement::to_str(const semantic::Info& sem,
|
void ReturnStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -46,9 +46,6 @@ class ReturnStatement : public Castable<ReturnStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
ReturnStatement* Clone(CloneContext* ctx) const override;
|
ReturnStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -52,23 +52,6 @@ TEST_F(ReturnStatementTest, HasValue_WithValue) {
|
||||||
EXPECT_TRUE(r->has_value());
|
EXPECT_TRUE(r->has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ReturnStatementTest, IsValid_WithoutValue) {
|
|
||||||
auto* r = create<ReturnStatement>();
|
|
||||||
EXPECT_TRUE(r->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ReturnStatementTest, IsValid_WithValue) {
|
|
||||||
auto* expr = Expr("expr");
|
|
||||||
auto* r = create<ReturnStatement>(expr);
|
|
||||||
EXPECT_TRUE(r->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ReturnStatementTest, IsValid_InvalidValue) {
|
|
||||||
auto* expr = Expr("");
|
|
||||||
auto* r = create<ReturnStatement>(expr);
|
|
||||||
EXPECT_FALSE(r->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ReturnStatementTest, ToStr_WithValue) {
|
TEST_F(ReturnStatementTest, ToStr_WithValue) {
|
||||||
auto* expr = Expr("expr");
|
auto* expr = Expr("expr");
|
||||||
auto* r = create<ReturnStatement>(expr);
|
auto* r = create<ReturnStatement>(expr);
|
||||||
|
|
|
@ -22,8 +22,10 @@ namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
ScalarConstructorExpression::ScalarConstructorExpression(const Source& source,
|
ScalarConstructorExpression::ScalarConstructorExpression(const Source& source,
|
||||||
Literal* litearl)
|
Literal* literal)
|
||||||
: Base(source), literal_(litearl) {}
|
: Base(source), literal_(literal) {
|
||||||
|
TINT_ASSERT(literal);
|
||||||
|
}
|
||||||
|
|
||||||
ScalarConstructorExpression::ScalarConstructorExpression(
|
ScalarConstructorExpression::ScalarConstructorExpression(
|
||||||
ScalarConstructorExpression&&) = default;
|
ScalarConstructorExpression&&) = default;
|
||||||
|
@ -38,10 +40,6 @@ ScalarConstructorExpression* ScalarConstructorExpression::Clone(
|
||||||
return ctx->dst->create<ScalarConstructorExpression>(src, lit);
|
return ctx->dst->create<ScalarConstructorExpression>(src, lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScalarConstructorExpression::IsValid() const {
|
|
||||||
return literal_ != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScalarConstructorExpression::to_str(const semantic::Info& sem,
|
void ScalarConstructorExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -42,9 +42,6 @@ class ScalarConstructorExpression
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
ScalarConstructorExpression* Clone(CloneContext* ctx) const override;
|
ScalarConstructorExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -33,14 +34,13 @@ TEST_F(ScalarConstructorExpressionTest, Creation_WithSource) {
|
||||||
EXPECT_EQ(src.range.begin.column, 2u);
|
EXPECT_EQ(src.range.begin.column, 2u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ScalarConstructorExpressionTest, IsValid) {
|
TEST_F(ScalarConstructorExpressionTest, Assert_NullLiteral) {
|
||||||
auto* c = Expr(true);
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(c->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
b.create<ScalarConstructorExpression>(nullptr);
|
||||||
TEST_F(ScalarConstructorExpressionTest, IsValid_MissingLiteral) {
|
},
|
||||||
auto* c = create<ScalarConstructorExpression>(nullptr);
|
"internal compiler error");
|
||||||
EXPECT_FALSE(c->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ScalarConstructorExpressionTest, ToStr) {
|
TEST_F(ScalarConstructorExpressionTest, ToStr) {
|
||||||
|
|
|
@ -27,7 +27,14 @@ Struct::Struct(const Source& source,
|
||||||
StructDecorationList decorations)
|
StructDecorationList decorations)
|
||||||
: Base(source),
|
: Base(source),
|
||||||
members_(std::move(members)),
|
members_(std::move(members)),
|
||||||
decorations_(std::move(decorations)) {}
|
decorations_(std::move(decorations)) {
|
||||||
|
for (auto* mem : members_) {
|
||||||
|
TINT_ASSERT(mem);
|
||||||
|
}
|
||||||
|
for (auto* deco : decorations_) {
|
||||||
|
TINT_ASSERT(deco);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Struct::Struct(Struct&&) = default;
|
Struct::Struct(Struct&&) = default;
|
||||||
|
|
||||||
|
@ -59,15 +66,6 @@ Struct* Struct::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<Struct>(src, mem, decos);
|
return ctx->dst->create<Struct>(src, mem, decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Struct::IsValid() const {
|
|
||||||
for (auto* mem : members_) {
|
|
||||||
if (mem == nullptr || !mem->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Struct::to_str(const semantic::Info& sem,
|
void Struct::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -58,9 +58,6 @@ class Struct : public Castable<Struct, Node> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
Struct* Clone(CloneContext* ctx) const override;
|
Struct* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -28,7 +28,13 @@ StructMember::StructMember(const Source& source,
|
||||||
: Base(source),
|
: Base(source),
|
||||||
symbol_(sym),
|
symbol_(sym),
|
||||||
type_(type),
|
type_(type),
|
||||||
decorations_(std::move(decorations)) {}
|
decorations_(std::move(decorations)) {
|
||||||
|
TINT_ASSERT(type);
|
||||||
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
|
for (auto* deco : decorations_) {
|
||||||
|
TINT_ASSERT(deco);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StructMember::StructMember(StructMember&&) = default;
|
StructMember::StructMember(StructMember&&) = default;
|
||||||
|
|
||||||
|
@ -61,18 +67,6 @@ StructMember* StructMember::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<StructMember>(src, sym, ty, decos);
|
return ctx->dst->create<StructMember>(src, sym, ty, decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructMember::IsValid() const {
|
|
||||||
if (type_ == nullptr || !symbol_.IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (auto* deco : decorations_) {
|
|
||||||
if (deco == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructMember::to_str(const semantic::Info& sem,
|
void StructMember::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -59,9 +59,6 @@ class StructMember : public Castable<StructMember, Node> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
StructMember* Clone(CloneContext* ctx) const override;
|
StructMember* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -45,24 +46,31 @@ TEST_F(StructMemberTest, CreationWithSource) {
|
||||||
EXPECT_EQ(st->source().range.end.column, 8u);
|
EXPECT_EQ(st->source().range.end.column, 8u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructMemberTest, IsValid) {
|
TEST_F(StructMemberTest, Assert_EmptySymbol) {
|
||||||
auto* st = Member("a", ty.i32());
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(st->IsValid());
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
|
b.Member("", b.ty.i32());
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructMemberTest, IsValid_EmptySymbol) {
|
TEST_F(StructMemberTest, Assert_NullType) {
|
||||||
auto* st = Member("", ty.i32());
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_FALSE(st->IsValid());
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
|
b.Member("a", nullptr);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructMemberTest, IsValid_NullType) {
|
TEST_F(StructMemberTest, Assert_NullDecoration) {
|
||||||
auto* st = Member("a", nullptr);
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_FALSE(st->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
b.Member("a", b.ty.i32(), {b.MemberOffset(4), nullptr});
|
||||||
TEST_F(StructMemberTest, IsValid_Null_Decoration) {
|
},
|
||||||
auto* st = Member("a", ty.i32(), {MemberOffset(4), nullptr});
|
"internal compiler error");
|
||||||
EXPECT_FALSE(st->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructMemberTest, ToStr) {
|
TEST_F(StructMemberTest, ToStr) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/struct_block_decoration.h"
|
#include "src/ast/struct_block_decoration.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
|
@ -62,21 +63,24 @@ TEST_F(StructTest, CreationWithSourceAndDecorations) {
|
||||||
EXPECT_EQ(s->source().range.end.column, 8u);
|
EXPECT_EQ(s->source().range.end.column, 8u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTest, IsValid) {
|
TEST_F(StructTest, Assert_Null_StructMember) {
|
||||||
auto* s = create<Struct>(StructMemberList{}, StructDecorationList{});
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(s->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
b.create<Struct>(StructMemberList{b.Member("a", b.ty.i32()), nullptr},
|
||||||
TEST_F(StructTest, IsValid_Null_StructMember) {
|
|
||||||
auto* s = create<Struct>(StructMemberList{Member("a", ty.i32()), nullptr},
|
|
||||||
StructDecorationList{});
|
StructDecorationList{});
|
||||||
EXPECT_FALSE(s->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTest, IsValid_Invalid_StructMember) {
|
TEST_F(StructTest, Assert_Null_Decoration) {
|
||||||
auto* s = create<Struct>(StructMemberList{Member("", ty.i32())},
|
EXPECT_FATAL_FAILURE(
|
||||||
ast::StructDecorationList{});
|
{
|
||||||
EXPECT_FALSE(s->IsValid());
|
ProgramBuilder b;
|
||||||
|
b.create<Struct>(StructMemberList{b.Member("a", b.ty.i32())},
|
||||||
|
StructDecorationList{nullptr});
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTest, ToStr) {
|
TEST_F(StructTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
||||||
SwitchStatement::SwitchStatement(const Source& source,
|
SwitchStatement::SwitchStatement(const Source& source,
|
||||||
Expression* condition,
|
Expression* condition,
|
||||||
CaseStatementList body)
|
CaseStatementList body)
|
||||||
: Base(source), condition_(condition), body_(body) {}
|
: Base(source), condition_(condition), body_(body) {
|
||||||
|
TINT_ASSERT(condition_);
|
||||||
|
for (auto* stmt : body_) {
|
||||||
|
TINT_ASSERT(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SwitchStatement::SwitchStatement(SwitchStatement&&) = default;
|
SwitchStatement::SwitchStatement(SwitchStatement&&) = default;
|
||||||
|
|
||||||
|
@ -38,18 +43,6 @@ SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<SwitchStatement>(src, cond, b);
|
return ctx->dst->create<SwitchStatement>(src, cond, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwitchStatement::IsValid() const {
|
|
||||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (auto* stmt : body_) {
|
|
||||||
if (stmt == nullptr || !stmt->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitchStatement::to_str(const semantic::Info& sem,
|
void SwitchStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -49,9 +49,6 @@ class SwitchStatement : public Castable<SwitchStatement, Statement> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
SwitchStatement* Clone(CloneContext* ctx) const override;
|
SwitchStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/switch_statement.h"
|
#include "src/ast/switch_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -61,69 +62,26 @@ TEST_F(SwitchStatementTest, IsSwitch) {
|
||||||
EXPECT_TRUE(stmt->Is<SwitchStatement>());
|
EXPECT_TRUE(stmt->Is<SwitchStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, IsValid) {
|
TEST_F(SwitchStatementTest, Assert_Null_Condition) {
|
||||||
CaseSelectorList lit;
|
EXPECT_FATAL_FAILURE(
|
||||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* ident = Expr("ident");
|
CaseStatementList cases;
|
||||||
CaseStatementList body;
|
cases.push_back(
|
||||||
body.push_back(
|
b.create<CaseStatement>(CaseSelectorList{b.Literal(1)},
|
||||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
b.create<BlockStatement>(StatementList{})));
|
||||||
|
b.create<SwitchStatement>(nullptr, cases);
|
||||||
auto* stmt = create<SwitchStatement>(ident, body);
|
},
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, IsValid_Null_Condition) {
|
TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
|
||||||
CaseSelectorList lit;
|
EXPECT_FATAL_FAILURE(
|
||||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
CaseStatementList body;
|
b.create<SwitchStatement>(b.Expr(true), CaseStatementList{nullptr});
|
||||||
body.push_back(
|
},
|
||||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
"internal compiler error");
|
||||||
|
|
||||||
auto* stmt = create<SwitchStatement>(nullptr, body);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, IsValid_Invalid_Condition) {
|
|
||||||
CaseSelectorList lit;
|
|
||||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
|
||||||
|
|
||||||
auto* ident = Expr("");
|
|
||||||
CaseStatementList body;
|
|
||||||
body.push_back(
|
|
||||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
|
||||||
|
|
||||||
auto* stmt = create<SwitchStatement>(ident, body);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, IsValid_Null_BodyStatement) {
|
|
||||||
CaseSelectorList lit;
|
|
||||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
|
||||||
|
|
||||||
auto* ident = Expr("ident");
|
|
||||||
CaseStatementList body;
|
|
||||||
body.push_back(
|
|
||||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
|
||||||
body.push_back(nullptr);
|
|
||||||
|
|
||||||
auto* stmt = create<SwitchStatement>(ident, body);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, IsValid_Invalid_BodyStatement) {
|
|
||||||
auto* ident = Expr("ident");
|
|
||||||
|
|
||||||
auto* case_body = create<BlockStatement>(StatementList{
|
|
||||||
nullptr,
|
|
||||||
});
|
|
||||||
CaseStatementList body;
|
|
||||||
body.push_back(create<CaseStatement>(CaseSelectorList{}, case_body));
|
|
||||||
|
|
||||||
auto* stmt = create<SwitchStatement>(ident, body);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SwitchStatementTest, ToStr_Empty) {
|
TEST_F(SwitchStatementTest, ToStr_Empty) {
|
||||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
||||||
TypeConstructorExpression::TypeConstructorExpression(const Source& source,
|
TypeConstructorExpression::TypeConstructorExpression(const Source& source,
|
||||||
type::Type* type,
|
type::Type* type,
|
||||||
ExpressionList values)
|
ExpressionList values)
|
||||||
: Base(source), type_(type), values_(std::move(values)) {}
|
: Base(source), type_(type), values_(std::move(values)) {
|
||||||
|
TINT_ASSERT(type);
|
||||||
|
for (auto* val : values_) {
|
||||||
|
TINT_ASSERT(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypeConstructorExpression::TypeConstructorExpression(
|
TypeConstructorExpression::TypeConstructorExpression(
|
||||||
TypeConstructorExpression&&) = default;
|
TypeConstructorExpression&&) = default;
|
||||||
|
@ -40,21 +45,6 @@ TypeConstructorExpression* TypeConstructorExpression::Clone(
|
||||||
return ctx->dst->create<TypeConstructorExpression>(src, ty, vals);
|
return ctx->dst->create<TypeConstructorExpression>(src, ty, vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeConstructorExpression::IsValid() const {
|
|
||||||
if (values_.empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (type_ == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (auto* val : values_) {
|
|
||||||
if (val == nullptr || !val->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeConstructorExpression::to_str(const semantic::Info& sem,
|
void TypeConstructorExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -48,9 +48,6 @@ class TypeConstructorExpression
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
TypeConstructorExpression* Clone(CloneContext* ctx) const override;
|
TypeConstructorExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -49,44 +50,23 @@ TEST_F(TypeConstructorExpressionTest, IsTypeConstructor) {
|
||||||
EXPECT_TRUE(t->Is<TypeConstructorExpression>());
|
EXPECT_TRUE(t->Is<TypeConstructorExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TypeConstructorExpressionTest, IsValid) {
|
TEST_F(TypeConstructorExpressionTest, Assert_NullType) {
|
||||||
ExpressionList expr;
|
EXPECT_FATAL_FAILURE(
|
||||||
expr.push_back(Expr("expr"));
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
b.create<TypeConstructorExpression>(nullptr, ExpressionList{b.Expr(1)});
|
||||||
EXPECT_TRUE(t->IsValid());
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) {
|
TEST_F(TypeConstructorExpressionTest, Assert_NullValue) {
|
||||||
ExpressionList expr;
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
ProgramBuilder b;
|
||||||
EXPECT_TRUE(t->IsValid());
|
b.create<TypeConstructorExpression>(b.ty.i32(),
|
||||||
}
|
ExpressionList{nullptr});
|
||||||
|
},
|
||||||
TEST_F(TypeConstructorExpressionTest, IsValid_NullType) {
|
"internal compiler error");
|
||||||
ExpressionList expr;
|
|
||||||
expr.push_back(Expr("expr"));
|
|
||||||
|
|
||||||
auto* t = create<TypeConstructorExpression>(nullptr, expr);
|
|
||||||
EXPECT_FALSE(t->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TypeConstructorExpressionTest, IsValid_NullValue) {
|
|
||||||
ExpressionList expr;
|
|
||||||
expr.push_back(Expr("expr"));
|
|
||||||
expr.push_back(nullptr);
|
|
||||||
|
|
||||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
|
||||||
EXPECT_FALSE(t->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TypeConstructorExpressionTest, IsValid_InvalidValue) {
|
|
||||||
ExpressionList expr;
|
|
||||||
expr.push_back(Expr(""));
|
|
||||||
|
|
||||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
|
||||||
EXPECT_FALSE(t->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TypeConstructorExpressionTest, ToStr) {
|
TEST_F(TypeConstructorExpressionTest, ToStr) {
|
||||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
||||||
UnaryOpExpression::UnaryOpExpression(const Source& source,
|
UnaryOpExpression::UnaryOpExpression(const Source& source,
|
||||||
UnaryOp op,
|
UnaryOp op,
|
||||||
Expression* expr)
|
Expression* expr)
|
||||||
: Base(source), op_(op), expr_(expr) {}
|
: Base(source), op_(op), expr_(expr) {
|
||||||
|
TINT_ASSERT(expr_);
|
||||||
|
}
|
||||||
|
|
||||||
UnaryOpExpression::UnaryOpExpression(UnaryOpExpression&&) = default;
|
UnaryOpExpression::UnaryOpExpression(UnaryOpExpression&&) = default;
|
||||||
|
|
||||||
|
@ -37,10 +39,6 @@ UnaryOpExpression* UnaryOpExpression::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<UnaryOpExpression>(src, op_, e);
|
return ctx->dst->create<UnaryOpExpression>(src, op_, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnaryOpExpression::IsValid() const {
|
|
||||||
return expr_ != nullptr && expr_->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnaryOpExpression::to_str(const semantic::Info& sem,
|
void UnaryOpExpression::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -44,9 +44,6 @@ class UnaryOpExpression : public Castable<UnaryOpExpression, Expression> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
UnaryOpExpression* Clone(CloneContext* ctx) const override;
|
UnaryOpExpression* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/unary_op_expression.h"
|
#include "src/ast/unary_op_expression.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -45,21 +46,13 @@ TEST_F(UnaryOpExpressionTest, IsUnaryOp) {
|
||||||
EXPECT_TRUE(u->Is<UnaryOpExpression>());
|
EXPECT_TRUE(u->Is<UnaryOpExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UnaryOpExpressionTest, IsValid) {
|
TEST_F(UnaryOpExpressionTest, Assert_NullExpression) {
|
||||||
auto* ident = Expr("ident");
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
|
{
|
||||||
EXPECT_TRUE(u->IsValid());
|
ProgramBuilder b;
|
||||||
}
|
b.create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
|
||||||
|
},
|
||||||
TEST_F(UnaryOpExpressionTest, IsValid_NullExpression) {
|
"internal compiler error");
|
||||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
|
|
||||||
EXPECT_FALSE(u->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnaryOpExpressionTest, IsValid_InvalidExpression) {
|
|
||||||
auto* ident = Expr("");
|
|
||||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
|
|
||||||
EXPECT_FALSE(u->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UnaryOpExpressionTest, ToStr) {
|
TEST_F(UnaryOpExpressionTest, ToStr) {
|
||||||
|
|
|
@ -36,7 +36,10 @@ Variable::Variable(const Source& source,
|
||||||
is_const_(is_const),
|
is_const_(is_const),
|
||||||
constructor_(constructor),
|
constructor_(constructor),
|
||||||
decorations_(std::move(decorations)),
|
decorations_(std::move(decorations)),
|
||||||
declared_storage_class_(sc) {}
|
declared_storage_class_(sc) {
|
||||||
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
|
TINT_ASSERT(type_);
|
||||||
|
}
|
||||||
|
|
||||||
Variable::Variable(Variable&&) = default;
|
Variable::Variable(Variable&&) = default;
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ LocationDecoration* Variable::GetLocationDecoration() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Variable::constant_id() const {
|
uint32_t Variable::constant_id() const {
|
||||||
assert(HasConstantIdDecoration());
|
TINT_ASSERT(HasConstantIdDecoration());
|
||||||
for (auto* deco : decorations_) {
|
for (auto* deco : decorations_) {
|
||||||
if (auto* cid = deco->As<ConstantIdDecoration>()) {
|
if (auto* cid = deco->As<ConstantIdDecoration>()) {
|
||||||
return cid->value();
|
return cid->value();
|
||||||
|
@ -98,19 +101,6 @@ Variable* Variable::Clone(CloneContext* ctx) const {
|
||||||
is_const_, ctor, decos);
|
is_const_, ctor, decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Variable::IsValid() const {
|
|
||||||
if (!symbol_.IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (type_ == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (constructor_ && !constructor_->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Variable::info_to_str(const semantic::Info& sem,
|
void Variable::info_to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -137,9 +137,6 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
Variable* Clone(CloneContext* ctx) const override;
|
Variable* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the variable is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -23,7 +23,9 @@ namespace ast {
|
||||||
|
|
||||||
VariableDeclStatement::VariableDeclStatement(const Source& source,
|
VariableDeclStatement::VariableDeclStatement(const Source& source,
|
||||||
Variable* variable)
|
Variable* variable)
|
||||||
: Base(source), variable_(variable) {}
|
: Base(source), variable_(variable) {
|
||||||
|
TINT_ASSERT(variable_);
|
||||||
|
}
|
||||||
|
|
||||||
VariableDeclStatement::VariableDeclStatement(VariableDeclStatement&&) = default;
|
VariableDeclStatement::VariableDeclStatement(VariableDeclStatement&&) = default;
|
||||||
|
|
||||||
|
@ -36,10 +38,6 @@ VariableDeclStatement* VariableDeclStatement::Clone(CloneContext* ctx) const {
|
||||||
return ctx->dst->create<VariableDeclStatement>(src, var);
|
return ctx->dst->create<VariableDeclStatement>(src, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VariableDeclStatement::IsValid() const {
|
|
||||||
return variable_ != nullptr && variable_->IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VariableDeclStatement::to_str(const semantic::Info& sem,
|
void VariableDeclStatement::to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
|
|
|
@ -42,9 +42,6 @@ class VariableDeclStatement
|
||||||
/// @return the newly cloned node
|
/// @return the newly cloned node
|
||||||
VariableDeclStatement* Clone(CloneContext* ctx) const override;
|
VariableDeclStatement* Clone(CloneContext* ctx) const override;
|
||||||
|
|
||||||
/// @returns true if the node is valid
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
/// Writes a representation of the node to the output stream
|
||||||
/// @param sem the semantic info for the program
|
/// @param sem the semantic info for the program
|
||||||
/// @param out the stream to write to
|
/// @param out the stream to write to
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -46,21 +47,13 @@ TEST_F(VariableDeclStatementTest, IsVariableDecl) {
|
||||||
EXPECT_TRUE(stmt->Is<VariableDeclStatement>());
|
EXPECT_TRUE(stmt->Is<VariableDeclStatement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableDeclStatementTest, IsValid) {
|
TEST_F(VariableDeclStatementTest, Assert_NullVariable) {
|
||||||
auto* var = Var("a", ty.f32(), StorageClass::kNone);
|
EXPECT_FATAL_FAILURE(
|
||||||
auto* stmt = create<VariableDeclStatement>(var);
|
{
|
||||||
EXPECT_TRUE(stmt->IsValid());
|
ProgramBuilder b;
|
||||||
}
|
b.create<VariableDeclStatement>(nullptr);
|
||||||
|
},
|
||||||
TEST_F(VariableDeclStatementTest, IsValid_InvalidVariable) {
|
"internal compiler error");
|
||||||
auto* var = Var("", ty.f32(), StorageClass::kNone);
|
|
||||||
auto* stmt = create<VariableDeclStatement>(var);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(VariableDeclStatementTest, IsValid_NullVariable) {
|
|
||||||
auto* stmt = create<VariableDeclStatement>(nullptr);
|
|
||||||
EXPECT_FALSE(stmt->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableDeclStatementTest, ToStr) {
|
TEST_F(VariableDeclStatementTest, ToStr) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/constant_id_decoration.h"
|
#include "src/ast/constant_id_decoration.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
|
@ -62,34 +63,22 @@ TEST_F(VariableTest, CreationEmpty) {
|
||||||
EXPECT_EQ(v->source().range.end.column, 7u);
|
EXPECT_EQ(v->source().range.end.column, 7u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, IsValid) {
|
TEST_F(VariableTest, Assert_MissingSymbol) {
|
||||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone);
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(v->IsValid());
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
|
b.Var("", b.ty.i32(), StorageClass::kNone);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, IsValid_WithConstructor) {
|
TEST_F(VariableTest, Assert_NullType) {
|
||||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone, Expr("ident"));
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_TRUE(v->IsValid());
|
{
|
||||||
}
|
ProgramBuilder b;
|
||||||
|
b.Var("x", nullptr, StorageClass::kNone);
|
||||||
TEST_F(VariableTest, IsValid_MissingSymbol) {
|
},
|
||||||
auto* v = Var("", ty.i32(), StorageClass::kNone);
|
"internal compiler error");
|
||||||
EXPECT_FALSE(v->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(VariableTest, IsValid_MissingType) {
|
|
||||||
auto* v = Var("x", nullptr, StorageClass::kNone);
|
|
||||||
EXPECT_FALSE(v->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(VariableTest, IsValid_MissingBoth) {
|
|
||||||
auto* v = Var("", nullptr, StorageClass::kNone);
|
|
||||||
EXPECT_FALSE(v->IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(VariableTest, IsValid_InvalidConstructor) {
|
|
||||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone, Expr(""));
|
|
||||||
EXPECT_FALSE(v->IsValid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, to_str) {
|
TEST_F(VariableTest, to_str) {
|
||||||
|
|
|
@ -37,7 +37,6 @@ struct Node : public Castable<Node, ast::Node> {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const override { return true; }
|
|
||||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,7 +54,6 @@ struct NotANode : public Castable<NotANode, ast::Node> {
|
||||||
return ctx->dst->create<NotANode>();
|
return ctx->dst->create<NotANode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const override { return true; }
|
|
||||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProgramBuilder::IsValid() const {
|
bool ProgramBuilder::IsValid() const {
|
||||||
return !diagnostics_.contains_errors() && ast_->IsValid();
|
return !diagnostics_.contains_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ProgramBuilder::str(const ast::Node* node) const {
|
std::string ProgramBuilder::str(const ast::Node* node) const {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
#include "src/ast/return_statement.h"
|
#include "src/ast/return_statement.h"
|
||||||
#include "src/ast/test_helper.h"
|
#include "src/ast/test_helper.h"
|
||||||
|
|
||||||
|
@ -37,109 +38,43 @@ TEST_F(ProgramTest, ToStrEmitsPreambleAndPostamble) {
|
||||||
EXPECT_EQ(str, expected);
|
EXPECT_EQ(str, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Empty) {
|
TEST_F(ProgramTest, EmptyIsValid) {
|
||||||
Program program(std::move(*this));
|
Program program(std::move(*this));
|
||||||
EXPECT_TRUE(program.IsValid());
|
EXPECT_TRUE(program.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_GlobalVariable) {
|
TEST_F(ProgramTest, Assert_GlobalVariable) {
|
||||||
Global("var", ty.f32(), ast::StorageClass::kInput);
|
Global("var", ty.f32(), ast::StorageClass::kInput);
|
||||||
|
|
||||||
Program program(std::move(*this));
|
Program program(std::move(*this));
|
||||||
EXPECT_TRUE(program.IsValid());
|
EXPECT_TRUE(program.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Null_GlobalVariable) {
|
TEST_F(ProgramTest, Assert_NullGlobalVariable) {
|
||||||
AST().AddGlobalVariable(nullptr);
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
Program program(std::move(*this));
|
ProgramBuilder b;
|
||||||
EXPECT_FALSE(program.IsValid());
|
b.AST().AddGlobalVariable(nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Invalid_GlobalVariable) {
|
|
||||||
Global("var", nullptr, ast::StorageClass::kInput);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Alias) {
|
|
||||||
auto* alias = ty.alias("alias", ty.f32());
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Null_Alias) {
|
|
||||||
AST().AddConstructedType(nullptr);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Struct) {
|
|
||||||
auto* st = ty.struct_("name", {});
|
|
||||||
auto* alias = ty.alias("name", st);
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Struct_EmptyName) {
|
|
||||||
auto* st = ty.struct_("", {});
|
|
||||||
auto* alias = ty.alias("name", st);
|
|
||||||
AST().AddConstructedType(alias);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Function) {
|
|
||||||
Func("main", ast::VariableList(), ty.f32(), ast::StatementList{},
|
|
||||||
ast::FunctionDecorationList{});
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_TRUE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Null_Function) {
|
|
||||||
AST().AddFunction(nullptr);
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Invalid_Function) {
|
|
||||||
Func("main", ast::VariableList{}, nullptr, ast::StatementList{},
|
|
||||||
ast::FunctionDecorationList{});
|
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_Invalid_UnknownVar) {
|
|
||||||
Func("main", ast::VariableList{}, nullptr,
|
|
||||||
ast::StatementList{
|
|
||||||
create<ast::ReturnStatement>(Expr("unknown_ident")),
|
|
||||||
},
|
},
|
||||||
ast::FunctionDecorationList{});
|
"internal compiler error");
|
||||||
|
|
||||||
Program program(std::move(*this));
|
|
||||||
EXPECT_FALSE(program.IsValid());
|
|
||||||
EXPECT_NE(program.Diagnostics().count(), 0u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, IsValid_GeneratesError) {
|
TEST_F(ProgramTest, Assert_NullConstructedType) {
|
||||||
AST().AddGlobalVariable(nullptr);
|
EXPECT_FATAL_FAILURE(
|
||||||
|
{
|
||||||
|
ProgramBuilder b;
|
||||||
|
b.AST().AddConstructedType(nullptr);
|
||||||
|
},
|
||||||
|
"internal compiler error");
|
||||||
|
}
|
||||||
|
|
||||||
Program program(std::move(*this));
|
TEST_F(ProgramTest, Assert_Null_Function) {
|
||||||
EXPECT_FALSE(program.IsValid());
|
EXPECT_FATAL_FAILURE(
|
||||||
EXPECT_EQ(program.Diagnostics().count(), 1u);
|
{
|
||||||
EXPECT_EQ(program.Diagnostics().error_count(), 1u);
|
ProgramBuilder b;
|
||||||
EXPECT_EQ(program.Diagnostics().begin()->message,
|
b.AST().AddFunction(nullptr);
|
||||||
"invalid program generated");
|
},
|
||||||
|
"internal compiler error");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProgramTest, DiagnosticsMove) {
|
TEST_F(ProgramTest, DiagnosticsMove) {
|
||||||
|
|
|
@ -684,9 +684,6 @@ DefInfo::DefInfo(const spvtools::opt::Instruction& def_inst,
|
||||||
|
|
||||||
DefInfo::~DefInfo() = default;
|
DefInfo::~DefInfo() = default;
|
||||||
|
|
||||||
bool StatementBuilder::IsValid() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ast::Node* StatementBuilder::Clone(CloneContext*) const {
|
ast::Node* StatementBuilder::Clone(CloneContext*) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -4117,6 +4114,9 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
|
||||||
for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
|
for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
|
||||||
params.emplace_back(MakeOperand(inst, iarg).expr);
|
params.emplace_back(MakeOperand(inst, iarg).expr);
|
||||||
}
|
}
|
||||||
|
if (failed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
auto* call_expr =
|
auto* call_expr =
|
||||||
create<ast::CallExpression>(Source{}, function, std::move(params));
|
create<ast::CallExpression>(Source{}, function, std::move(params));
|
||||||
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
||||||
|
|
|
@ -368,7 +368,6 @@ class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
|
||||||
virtual ast::Statement* Build(ProgramBuilder* builder) const = 0;
|
virtual ast::Statement* Build(ProgramBuilder* builder) const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsValid() const override;
|
|
||||||
Node* Clone(CloneContext*) const override;
|
Node* Clone(CloneContext*) const override;
|
||||||
void to_str(const semantic::Info& sem,
|
void to_str(const semantic::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
|
|
|
@ -50,7 +50,6 @@ class FakeStmt : public ast::Statement {
|
||||||
public:
|
public:
|
||||||
explicit FakeStmt(Source source) : ast::Statement(source) {}
|
explicit FakeStmt(Source source) : ast::Statement(source) {}
|
||||||
FakeStmt* Clone(CloneContext*) const override { return nullptr; }
|
FakeStmt* Clone(CloneContext*) const override { return nullptr; }
|
||||||
bool IsValid() const override { return true; }
|
|
||||||
void to_str(const semantic::Info&, std::ostream& out, size_t) const override {
|
void to_str(const semantic::Info&, std::ostream& out, size_t) const override {
|
||||||
out << "Fake";
|
out << "Fake";
|
||||||
}
|
}
|
||||||
|
@ -60,7 +59,6 @@ class FakeExpr : public ast::Expression {
|
||||||
public:
|
public:
|
||||||
explicit FakeExpr(Source source) : ast::Expression(source) {}
|
explicit FakeExpr(Source source) : ast::Expression(source) {}
|
||||||
FakeExpr* Clone(CloneContext*) const override { return nullptr; }
|
FakeExpr* Clone(CloneContext*) const override { return nullptr; }
|
||||||
bool IsValid() const override { return true; }
|
|
||||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2715,9 +2715,11 @@ bool Builder::GenerateLoopStatement(ast::LoopStatement* stmt) {
|
||||||
if (!GenerateLabel(continue_block_id)) {
|
if (!GenerateLabel(continue_block_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (stmt->has_continuing()) {
|
||||||
if (!GenerateBlockStatementWithoutScoping(stmt->continuing())) {
|
if (!GenerateBlockStatementWithoutScoping(stmt->continuing())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scope_stack_.pop_scope();
|
scope_stack_.pop_scope();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue